feat(design): add Badge & MultipleSelect (#5160)

This commit is contained in:
白熱
2025-05-08 15:18:27 +08:00
committed by GitHub
parent 8520a1fbfd
commit 232ce87815
49 changed files with 368 additions and 897 deletions
+14 -5
View File
@@ -15,6 +15,7 @@
*/
import type { Preview } from '@storybook/react';
import type { Theme } from '@univerjs/themes';
import {
CommandService,
ConfigService,
@@ -43,14 +44,15 @@ import {
import { ConfigProvider } from '@univerjs/design';
import enUS from '@univerjs/design/locale/en-US';
import zhCN from '@univerjs/design/locale/zh-CN';
import { DesktopLocalStorageService, RediContext } from '@univerjs/ui';
import React, { useMemo } from 'react';
import { defaultTheme, greenTheme } from '@univerjs/themes';
import { DesktopLocalStorageService, RediContext, ThemeSwitcherService } from '@univerjs/ui';
import React, { useEffect, useMemo } from 'react';
import './global.css';
export const themes: Record<string, Record<string, string>> = {
// default: defaultTheme,
// green: greenTheme,
export const themes: Record<string, Theme> = {
default: defaultTheme,
green: greenTheme,
};
const preview: Preview = {
@@ -115,6 +117,7 @@ const preview: Preview = {
const rediContext = useMemo(() => {
const injector = new Injector([
[ThemeSwitcherService],
[IUniverInstanceService, { useClass: UniverInstanceService }],
[ErrorService],
[LocaleService],
@@ -138,6 +141,12 @@ const preview: Preview = {
};
}, []);
useEffect(() => {
const theme = themes[context.globals.theme];
rediContext.injector.get(ThemeSwitcherService).injectThemeToHead(theme);
}, [context.globals.theme]);
return (
<RediContext.Provider value={rediContext}>
<ConfigProvider locale={designLocale} mountContainer={document.body}>
-1
View File
@@ -83,7 +83,6 @@
"rc-dropdown": "^4.2.1",
"rc-menu": "^9.16.0",
"rc-picker": "^4.9.0",
"rc-select": "^14.16.4",
"rc-virtual-list": "^3.16.1",
"react-grid-layout": "^1.5.1",
"react-transition-group": "^4.4.5",
@@ -14,4 +14,29 @@
* limitations under the License.
*/
export { Avatar, type IAvatarProps } from './Avatar';
import type { Meta } from '@storybook/react';
import { Badge } from './Badge';
const meta: Meta<typeof Badge> = {
title: 'Components / Badge',
component: Badge,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
};
export default meta;
export const BadgeBasic = {
render() {
return (
<>
<div>
<Badge>Badge</Badge>
<Badge closable>Badge</Badge>
</div>
</>
);
},
};
@@ -0,0 +1,62 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { ReactNode } from 'react';
import { CloseSingle } from '@univerjs/icons';
import { clsx } from '../../helper/clsx';
export interface IBadgeProps {
className?: string;
children: ReactNode;
closable?: boolean;
onClose?: () => void;
}
export function Badge(props: IBadgeProps) {
const { className, children, closable = false, onClose } = props;
return (
<span
data-u-comp="badge"
className={clsx(
`
univer-box-border univer-inline-flex univer-items-center univer-gap-1 univer-truncate
univer-rounded-md univer-border univer-border-solid univer-border-gray-100 univer-bg-gray-100
univer-px-2.5 univer-py-0.5 univer-text-xs univer-font-medium univer-text-gray-900
dark:univer-border-gray-500 dark:univer-bg-gray-700 dark:univer-text-gray-300
`,
className
)}
>
<span className="univer-flex-1 univer-truncate">
{children}
</span>
{closable && (
<a
className={`
univer-flex univer-cursor-pointer univer-items-center univer-justify-center
univer-transition-opacity
hover:univer-opacity-70
`}
onClick={onClose}
>
<CloseSingle className="univer-text-current" />
</a>
)}
</span>
);
}
@@ -1,18 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Button, type IButtonProps } from './Button';
export { ButtonGroup, type IButtonGroupProps } from './ButtonGroup';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { CascaderList, type ICascaderListProps, type ICascaderOption } from './CascaderList';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { CheckboxGroup, type ICheckboxGroupProps } from './CheckboxGroup';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Checkbox, type ICheckboxProps } from './Checkbox';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { ColorPicker, type IColorPickerProps } from './ColorPicker';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { ConfigContext, ConfigProvider, type IConfigProviderProps } from './ConfigProvider';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Confirm, type IConfirmProps } from './Confirm';
@@ -19,7 +19,7 @@ import type { BasePickerPanelProps } from 'rc-picker';
import { PickerPanel } from 'rc-picker';
import generateConfig from 'rc-picker/lib/generate/dayjs';
import { useContext } from 'react';
import { ConfigContext } from '../config-provider';
import { ConfigContext } from '../config-provider/ConfigProvider';
import styles from './index.module.css';
export type IDatePanelProps = Omit<BasePickerPanelProps<dayjs.Dayjs>, 'prefixCls' | 'locale' | 'generateConfig'> & {
@@ -17,7 +17,7 @@
import type { CSSProperties, MouseEvent as ReactMouseEvent, ReactNode } from 'react';
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { clsx } from '../../helper/clsx';
import { Button } from '../button';
import { Button } from '../button/Button';
import { ConfigContext } from '../config-provider/ConfigProvider';
import { DialogContent, DialogDescription, DialogFooter, DialogHeader, Dialog as DialogProvider, DialogTitle } from './DialogPrimitive';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Dialog, type IDialogProps } from './Dialog';
@@ -17,6 +17,7 @@
import type { ComponentProps, ReactNode } from 'react';
import { useState } from 'react';
import {
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuPrimitive,
@@ -31,7 +32,7 @@ interface IDropdownMenuNormalItem {
className?: string;
children: ReactNode;
disabled?: boolean;
onSelect?: (item: DropdownMenu) => void;
onSelect?: (item: DropdownMenuType) => void;
}
interface IDropdownMenuSeparatorItem {
@@ -54,11 +55,21 @@ interface IDropdownMenuRadioItem {
onSelect?: (item: string) => void;
}
type DropdownMenu = IDropdownMenuNormalItem | IDropdownMenuSeparatorItem | IDropdownMenuRadioItem;
interface IDropdownMenuCheckItem {
type: 'checkbox';
className?: string;
label?: ReactNode;
value: string;
disabled?: boolean;
checked?: boolean;
onSelect?: (item: string) => void;
}
type DropdownMenuType = IDropdownMenuNormalItem | IDropdownMenuSeparatorItem | IDropdownMenuRadioItem | IDropdownMenuCheckItem;
export interface IDropdownMenuProps extends ComponentProps<typeof DropdownMenuContent> {
children: ReactNode;
items: DropdownMenu[];
items: DropdownMenuType[];
disabled?: boolean;
open?: boolean;
onOpenChange?: (open: boolean) => void;
@@ -89,7 +100,7 @@ export function DropdownMenu(props: IDropdownMenuProps) {
controlledOnOpenChange?.(newOpen);
}
function renderMenuItem(item: DropdownMenu, index: number) {
function renderMenuItem(item: DropdownMenuType, index: number) {
const { className, type } = item;
if (type === 'separator') {
@@ -105,7 +116,7 @@ export function DropdownMenu(props: IDropdownMenuProps) {
{item.options.map((option, index) => {
if ('type' in option) {
if (option.type === 'separator') {
return <DropdownMenuSeparator key={index} className={className} />;
return <DropdownMenuSeparator key={index} className={option.className} />;
}
} else {
if (option.value === undefined) {
@@ -126,6 +137,20 @@ export function DropdownMenu(props: IDropdownMenuProps) {
})}
</DropdownMenuRadioGroup>
);
} else if (type === 'checkbox') {
return (
<DropdownMenuCheckboxItem
key={index}
className={className}
disabled={item.disabled}
checked={item.checked}
onSelect={() => {
item.onSelect?.(item.value);
}}
>
{item.label}
</DropdownMenuCheckboxItem>
);
} else if (type === 'item') {
return (
<DropdownMenuItem
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { DropdownMenu, type IDropdownMenuProps } from './DropdownMenu';
@@ -16,7 +16,7 @@
import type { Meta } from '@storybook/react';
import { Input } from '../input';
import { Input } from '../input/Input';
import { Select } from '../select/Select';
import { FormLayout } from './FormLayout';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { type IInputNumberProps, InputNumber } from './InputNumber';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { type IInputProps, Input } from './Input';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { type IKBDProps, KBD } from './Kbd';
+1 -1
View File
@@ -19,7 +19,7 @@ import RcMenu, { MenuItem as RcMenuItem, MenuItemGroup as RcMenuItemGroup, SubMe
import React, { useContext } from 'react';
import { clsx } from '../../helper/clsx';
import { ConfigContext } from '../config-provider/ConfigProvider';
import { Tooltip } from '../tooltip';
import { Tooltip } from '../tooltip/Tooltip';
import styles from './index.module.css';
/** @deprecated */
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { type IMessageProps, message, Messager, MessageType, removeMessage } from './Message';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { type IPagerProps, Pager } from './Pager';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { type IRadioGroupProps, RadioGroup } from './RadioGroup';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { type IRadioProps, Radio } from './Radio';
@@ -97,6 +97,7 @@ export function Segmented<T extends ItemValue = ItemValue>({
return (
<div
data-u-comp="segmented"
ref={containerRef}
className={clsx(`
univer-relative univer-box-border univer-flex univer-gap-4 univer-rounded-lg univer-bg-gray-100 univer-p-1
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Segmented } from './Segmented';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { type ISelectListProps, SelectList } from './SelectList';
@@ -1,125 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { LabelInValueType } from 'rc-select/lib/Select';
import type { CSSProperties, JSXElementConstructor, ReactElement, ReactNode } from 'react';
import { MoreDownSingle } from '@univerjs/icons';
import RcSelect from 'rc-select';
import { useContext } from 'react';
import { clsx } from '../../helper/clsx';
import { ConfigContext } from '../config-provider/ConfigProvider';
import styles from './index.module.css';
/** @deprecated */
interface ILegacyOption {
label?: string | ReactNode;
value?: string;
options?: ILegacyOption[];
}
/** @deprecated */
export interface ILegacySelectProps {
/**
* The value of select
*/
value: string;
/**
* The options of select
* @default []
*/
options?: ILegacyOption[];
/**
* The callback function that is triggered when the value is changed
*/
onChange: (value: string) => void;
style?: CSSProperties;
/**
* Whether the borderless style is used
* @default false
*/
borderless?: boolean;
className?: string;
/**
* select mode
*/
mode?: 'combobox' | 'multiple' | 'tags' | undefined;
dropdownRender?: (
menu: ReactElement<any, string | JSXElementConstructor<any>>
) => ReactElement<any, string | JSXElementConstructor<any>>;
labelRender?: ((props: LabelInValueType) => ReactNode) | undefined;
open?: boolean;
dropdownStyle?: CSSProperties;
onDropdownVisibleChange?: (open: boolean) => void;
disabled?: boolean;
}
/** @deprecated */
export function LegacySelect(props: ILegacySelectProps) {
const {
value,
options = [],
onChange,
style,
className,
mode,
borderless = false,
dropdownRender,
labelRender,
open,
dropdownStyle,
onDropdownVisibleChange,
disabled,
} = props;
const { mountContainer, locale } = useContext(ConfigContext);
const _className = clsx(className, {
[styles.selectBorderless]: borderless,
});
return mountContainer && (
<RcSelect
mode={mode}
prefixCls={styles.select}
getPopupContainer={() => mountContainer}
options={options}
value={value}
menuItemSelectedIcon={null}
suffixIcon={<MoreDownSingle />}
onChange={onChange}
style={style}
className={_className}
dropdownRender={dropdownRender}
labelRender={labelRender}
open={open}
dropdownStyle={dropdownStyle}
onDropdownVisibleChange={onDropdownVisibleChange}
notFoundContent={locale?.Select.empty}
disabled={disabled}
/>
);
}
@@ -0,0 +1,153 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { ReactNode } from 'react';
import type { IDropdownMenuProps } from '../dropdown-menu/DropdownMenu';
import { MoreDownSingle } from '@univerjs/icons';
import { useMemo, useState } from 'react';
import { clsx } from '../../helper/clsx';
import { Badge } from '../badge/Badge';
import { DropdownMenu } from '../dropdown-menu/DropdownMenu';
interface IOption {
label?: string | ReactNode;
value?: string;
disabled?: boolean;
}
export interface IMultipleSelectProps {
className?: string;
/**
* The value of select
*/
value: string[];
/**
* Whether the select is disabled
* @default false
*/
disabled?: boolean;
/**
* The options of select
* @default []
*/
options?: IOption[];
/**
* The style of select
* @default false
*/
borderless?: boolean;
/**
* The callback function that is triggered when the value is changed
*/
onChange: (values: string[]) => void;
}
export function MultipleSelect(props: IMultipleSelectProps) {
const {
className,
value = [],
disabled = false,
options = [],
borderless = false,
onChange,
} = props;
const [open, setOpen] = useState(false);
function handleOpenChange(open: boolean) {
setOpen(open);
}
const items: IDropdownMenuProps['items'] = useMemo(() => {
return options.map((option) => {
return {
type: 'checkbox',
value: option.value!,
label: option.label,
disabled: option.disabled,
checked: value.includes(option.value!),
onSelect: (item: string) => {
const newValue = value.includes(item) ? value.filter((v) => v !== item) : [...value, item];
onChange(newValue);
},
};
});
}, [options]);
function handleClose(item: string) {
const newValue = value.filter((v) => v !== item);
onChange(newValue);
}
const displayValue = useMemo(() => {
return options
.filter((option) => value.includes(option.value!))
.map((option, index) => (
<Badge
key={index}
className="univer-max-w-32"
closable
onClose={() => handleClose(option.value!)}
>
{option.label}
</Badge>
));
}, [options, value]);
return (
<DropdownMenu
className="univer-w-[var(--radix-popper-anchor-width)] univer-min-w-36"
align="start"
open={open}
items={items}
disabled={disabled}
onOpenChange={handleOpenChange}
>
<div
data-u-comp="multiple-select"
className={clsx(`
univer-box-border univer-inline-flex univer-h-8 univer-min-w-36 univer-cursor-pointer
univer-items-center univer-justify-between univer-gap-2 univer-rounded-lg univer-border
univer-border-solid univer-border-gray-200 univer-bg-white univer-px-2.5 univer-transition-colors
univer-duration-200
dark:univer-border-gray-600 dark:univer-bg-gray-700 dark:univer-text-white
hover:univer-border-primary-600
`, {
'univer-border-primary-600 univer-outline-none univer-ring-2 univer-ring-primary-600/20': open && !borderless,
'univer-border-transparent univer-bg-transparent hover:univer-border-transparent': borderless,
}, className)}
>
<div
className="univer-flex univer-flex-1 univer-gap-2"
>
{displayValue}
</div>
<MoreDownSingle
className={`
univer-flex-shrink-0
dark:univer-text-white
`}
/>
</div>
</DropdownMenu>
);
}
@@ -17,6 +17,7 @@
import type { Meta } from '@storybook/react';
import type { ISelectProps } from './Select';
import { useState } from 'react';
import { MultipleSelect } from './MultipleSelect';
import { Select } from './Select';
const meta: Meta<typeof Select> = {
@@ -53,6 +54,31 @@ export const SelectBasic = {
},
};
export const SelectMultiple = {
render() {
const [values, setValues] = useState<string[]>(['option2']);
const options = [
{ label: 'Option 1', value: 'option1' },
{ label: 'Option 2', value: 'option2' },
{ label: 'Option 3 Option 3 Option 3 Option 3 Option 3 Option 3', value: 'option3' },
];
function handleChange(values: string[]) {
setValues(values);
}
return (
<>
{values.toString()}
<MultipleSelect
value={values}
options={options}
onChange={handleChange}
/>
</>
);
},
};
export const SelectEmpty = {
render() {
const [value, setValue] = useState('');
@@ -40,12 +40,6 @@ export interface ISelectProps {
*/
value: string;
/**
* select mode
* @default 'combobox'
*/
mode?: 'combobox' | 'multiple';
/**
* Whether the select is disabled
* @default false
@@ -74,7 +68,6 @@ export function Select(props: ISelectProps) {
const {
className,
value,
mode,
disabled = false,
options = [],
borderless = false,
@@ -1,323 +0,0 @@
.select {
position: relative;
display: inline-block;
}
.select-disabled,
.select-disabled input {
cursor: not-allowed;
}
.select-disabled .select-selector {
opacity: 0.3;
}
.select-show-arrow.select-loading .select-arrow-icon::after {
transform: none;
box-sizing: border-box;
width: 12px;
height: 12px;
margin-top: 4px;
border-top-color: transparent;
border-bottom-color: transparent;
border-radius: 100%;
animation: select-loading-icon 0.5s infinite;
@apply univer-border-2 univer-border-solid univer-border-gray-200;
}
.select-selection-placeholder {
pointer-events: none;
opacity: 0.4;
}
.select-selection-search-input {
appearance: none;
@apply univer-text-gray-900 univer-text-sm;
}
.select-selection-search-input::-webkit-search-cancel-button {
display: none;
appearance: none;
}
.select-single .select-selector {
position: relative;
display: flex;
box-sizing: border-box;
height: 28px;
padding: 0 10px;
transition: all 0.15s;
}
.select-single .select-selection-search {
width: 100%;
line-height: 0;
}
.select-single .select-selection-search-input {
width: 100%;
height: 100%;
}
.select-single .select-selection-item,
.select-single .select-selection-placeholder {
pointer-events: none;
position: absolute;
left: 0;
height: 100%;
width: 100%;
padding: 0 18px 0 10px;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 28px;
display: inline-block;
align-items: center;
@apply univer-text-sm;
}
.select-single:not(.select-customize-input) .select-selector {
@apply univer-border univer-border-solid univer-border-gray-200 univer-rounded;
}
.select-single:not(.select-customize-input) .select-selection-search-input {
width: 100%;
padding: 0;
border: none;
outline: none;
}
.select-multiple .select-selector {
display: flex;
flex-wrap: wrap;
@apply univer-border univer-border-solid univer-border-gray-200 univer-rounded;
}
.select-multiple .select-selection-item {
flex: none;
margin-right: 2px;
padding: 0 8px;
background: #bbb;
border-radius: 4px;
}
.select-multiple .select-selection-item-disabled {
cursor: not-allowed;
opacity: 0.5;
}
.select-multiple .select-selection-overflow {
display: flex;
flex-wrap: wrap;
width: 100%;
}
.select-multiple .select-selection-overflow-item {
flex: none;
max-width: 100%;
}
.select-multiple .select-selection-search {
position: relative;
max-width: 100%;
}
.select-multiple .select-selection-search-input,
.select-multiple .select-selection-search-mirror {
box-sizing: border-box;
@apply univer-px-2 univer-py-1;
}
.select-multiple .select-selection-search-mirror {
position: none;
z-index: 999;
top: 0;
left: 0;
white-space: nowrap;
visibility: hidden;
}
.select-multiple .select-selection-search-input {
width: 100%;
padding: 0;
border: none;
outline: none;
}
.select-borderless:not(.select-customize-input) .select-selector {
border-color: transparent;
}
.select-borderless.select-focused .select-selector,
.select-borderless:hover .select-selector {
border-color: transparent !important;
}
.select-allow-clear.select-multiple .select-selector {
padding-right: 20px;
}
.select-allow-clear .select-clear {
position: absolute;
top: 0;
right: 20px;
}
.select-show-arrow.select-multiple .select-selector {
padding-right: 20px;
}
.select-show-arrow .select-arrow {
pointer-events: none;
position: absolute;
top: 0;
display: flex;
align-items: center;
height: 100%;
@apply univer-text-gray-600 univer-text-xs univer-right-3;
}
.select-show-arrow .select-arrow-icon::after {
content: '';
transform: translateY(5px);
display: inline-block;
width: 0;
height: 0;
border: 5px solid transparent;
@apply univer-border-t-gray-200;
}
.select-focused .select-selector,
.select:hover .select-selector {
@apply !univer-border-primary-600;
}
.select-dropdown {
position: absolute;
z-index: 1070;
@apply univer-bg-white univer-border univer-border-solid univer-border-gray-200 univer-rounded univer-shadow;
}
.select-dropdown-hidden {
display: none;
}
.select-item {
cursor: pointer;
@apply univer-py-2 univer-px-3 univer-text-sm;
}
.select-item-group {
padding: 0;
}
.select-item-group:not(:first-child) {
@apply univer-border-0 univer-border-t univer-border-t-gray-200 univer-border-solid;
}
.select-item-option {
position: relative;
transition: all 0.15s;
}
.select-item-option .select-item-option-state {
pointer-events: none;
position: absolute;
top: 4px;
right: 0;
}
.select-item-option-active {
background: #ddd;
}
.select-item-option-disabled {
@apply univer-text-gray-400;
}
.select-item-empty {
text-align: center;
@apply univer-text-gray-400 univer-text-sm univer-py-1;
}
.select-selection__choice-zoom {
transition: all 0.3s;
}
.select-selection__choice-zoom-appear {
transform: scale(0.5);
opacity: 0;
}
.select-selection__choice-zoom-appear-active {
transform: scale(1);
opacity: 1;
}
.select-selection__choice-zoom-leave {
transform: scale(1);
opacity: 1;
}
.select-selection__choice-zoom-leave-active {
transform: scale(0.5);
opacity: 0;
}
.select-dropdown-slide-up-enter,
.select-dropdown-slide-up-appear {
transform-origin: 0 0;
animation-duration: 0.3s;
animation-fill-mode: both;
opacity: 0;
animation-play-state: paused;
animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
}
.select-dropdown-slide-up-leave {
transform-origin: 0 0;
animation-duration: 0.3s;
animation-fill-mode: both;
opacity: 1;
animation-play-state: paused;
animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
}
@keyframes select-dropdown-slide-up-in {
0% {
transform-origin: 0% 0%;
transform: scaleY(0);
opacity: 0;
}
100% {
transform-origin: 0% 0%;
transform: scaleY(1);
opacity: 1;
}
}
@keyframes select-dropdown-slide-up-out {
0% {
transform-origin: 0% 0%;
transform: scaleY(1);
opacity: 1;
}
100% {
transform-origin: 0% 0%;
transform: scaleY(0);
opacity: 0;
}
}
@keyframes select-loading-icon {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Separator } from './Separator';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Switch } from './Switch';
@@ -1,17 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { type ITooltipProps, Tooltip } from './Tooltip';
+2 -2
View File
@@ -19,8 +19,8 @@ import { DropdownSingle } from '@univerjs/icons';
import VirtualList from 'rc-virtual-list';
import { useEffect, useMemo, useState } from 'react';
import { clsx } from '../../helper/clsx';
import { Checkbox } from '../checkbox';
import { Tooltip } from '../tooltip';
import { Checkbox } from '../checkbox/Checkbox';
import { Tooltip } from '../tooltip/Tooltip';
import styles from './index.module.css';
import { createCacheWithFindNodePathFromTree, isIntermediated } from './util';
+37 -32
View File
@@ -16,45 +16,50 @@
import './global.css';
export { Avatar, type IAvatarProps } from './components/avatar';
export { Button, ButtonGroup, type IButtonGroupProps, type IButtonProps } from './components/button';
export { CascaderList, type ICascaderListProps, type ICascaderOption } from './components/cascader-list';
export { Checkbox, type ICheckboxProps } from './components/checkbox';
export { CheckboxGroup, type ICheckboxGroupProps } from './components/checkbox-group';
export { ColorPicker, type IColorPickerProps } from './components/color-picker';
export { ConfigContext, ConfigProvider, type IConfigProviderProps } from './components/config-provider';
export { Confirm, type IConfirmProps } from './components/confirm';
export { DatePanel, DatePicker, type IDatePanelProps, type IDatePickerProps } from './components/date-picker';
export { Dialog, type IDialogProps } from './components/dialog';
export { DropdownLegacy, type IDropdownLegacyProps } from './components/dropdown-legacy';
export { Avatar, type IAvatarProps } from './components/avatar/Avatar';
export { Button, type IButtonProps } from './components/button/Button';
export { ButtonGroup, type IButtonGroupProps } from './components/button/ButtonGroup';
export { CascaderList, type ICascaderListProps, type ICascaderOption } from './components/cascader-list/CascaderList';
export { Checkbox, type ICheckboxProps } from './components/checkbox/Checkbox';
export { CheckboxGroup, type ICheckboxGroupProps } from './components/checkbox-group/CheckboxGroup';
export { ColorPicker, type IColorPickerProps } from './components/color-picker/ColorPicker';
export { ConfigContext, ConfigProvider, type IConfigProviderProps } from './components/config-provider/ConfigProvider';
export { Confirm, type IConfirmProps } from './components/confirm/Confirm';
export { Dialog, type IDialogProps } from './components/dialog/Dialog';
export { Dropdown, type IDropdownProps } from './components/dropdown';
export { FormDualColumnLayout, FormLayout, type IFormDualColumnLayoutProps, type IFormLayoutProps } from './components/form-layout';
export { type IInputProps, Input } from './components/input';
export { type IInputNumberProps, InputNumber } from './components/input-number';
export { Menu, MenuItem, MenuItemGroup, type MenuRef, SubMenu, TinyMenuGroup } from './components/menu';
export { type IMessageProps, message, Messager, MessageType, removeMessage } from './components/message';
export { type IPagerProps, Pager } from './components/pager';
export { type IPopupProps, Popup } from './components/popup';
export { type IRadioProps, Radio } from './components/radio';
export { type IRadioGroupProps, RadioGroup } from './components/radio-group';
export { type ILegacySelectProps, LegacySelect } from './components/select/LegacySelect';
export { type IInputProps, Input } from './components/input/Input';
export { type IInputNumberProps, InputNumber } from './components/input-number/InputNumber';
export { type IMessageProps, message, Messager, MessageType, removeMessage } from './components/message/Message';
export { type IPagerProps, Pager } from './components/pager/Pager';
export { type IRadioProps, Radio } from './components/radio/Radio';
export { type IRadioGroupProps, RadioGroup } from './components/radio-group/RadioGroup';
export { type ISelectProps, Select } from './components/select/Select';
export { type ISelectListProps, SelectList } from './components/select-list';
export { Segmented } from './components/segmented';
export { type ITooltipProps, Tooltip } from './components/tooltip';
export { filterLeafNode, findNodePathFromTree, findSubTreeFromPath, type ITreeNodeProps, type ITreeProps, mergeTreeSelected, Tree, TreeSelectionMode } from './components/tree';
export { Switch } from './components/switch';
export { type ILocale } from './locale/interface';
export { type IMultipleSelectProps, MultipleSelect } from './components/select/MultipleSelect';
export { Badge, type IBadgeProps } from './components/badge/Badge';
export { type ISelectListProps, SelectList } from './components/select-list/SelectList';
export { Segmented } from './components/segmented/Segmented';
export { type ITooltipProps, Tooltip } from './components/tooltip/Tooltip';
export { Switch } from './components/switch/Switch';
export { DropdownMenu, type IDropdownMenuProps } from './components/dropdown-menu/DropdownMenu';
export { Separator } from './components/separator/Separator';
export { type IKBDProps, KBD } from './components/kbd/Kbd';
export { type IToasterProps, toast, Toaster } from './components/toaster/Toaster';
export { DatePanel, DatePicker, type IDatePanelProps, type IDatePickerProps } from './components/date-picker';
export { DropdownLegacy, type IDropdownLegacyProps } from './components/dropdown-legacy';
export { FormDualColumnLayout, FormLayout, type IFormDualColumnLayoutProps, type IFormLayoutProps } from './components/form-layout';
export { DraggableList, type IDraggableListProps, ReactGridLayout } from './components/draggable-list';
export { filterLeafNode, findNodePathFromTree, findSubTreeFromPath, type ITreeNodeProps, type ITreeProps, mergeTreeSelected, Tree, TreeSelectionMode } from './components/tree';
export { Menu, MenuItem, MenuItemGroup, type MenuRef, SubMenu, TinyMenuGroup } from './components/menu';
export { type IPopupProps, Popup } from './components/popup';
export { DateRangePicker } from './components/date-range-picker';
export { type ILocale } from './locale/interface';
export { clsx } from './helper/clsx';
export { resizeObserverCtor } from './helper/resize-observer';
export { render, unmount } from './helper/react-dom';
export { isBrowser } from './helper/is-browser';
export { DropdownMenu, type IDropdownMenuProps } from './components/dropdown-menu';
export { Separator } from './components/separator';
export { DateRangePicker } from './components/date-range-picker';
export { type IKBDProps, KBD } from './components/kbd';
export { type IToasterProps, toast, Toaster } from './components/toaster/Toaster';
export { scrollbarClassName } from './helper/scrollbar-cls';
/** @deprecated Only for compatibility with versions before 0.7.0, will be removed in future versions */
@@ -99,7 +99,7 @@ export const ImagePopupMenu: React.FC<IImagePopupMenuProps> = (props: IImagePopu
})}
>
<Autofill className="univer-fill-primary-600 univer-text-gray-900" />
{showMore && <MoreDownSingle className="univer-text-[10px] univer-text-gray-400" />}
{showMore && <MoreDownSingle />}
</div>
</DropdownMenu>
</div>
@@ -122,7 +122,7 @@ const ColorSelect = (props: IColorSelectProps) => {
style={{ background: value }}
/>
<MoreDownSingle className="univer-text-gray-600" />
<MoreDownSingle />
</div>
</Dropdown>
);
@@ -46,10 +46,10 @@ export function DataValidationOptions(props: IDataValidationOptionsParams) {
{localeService.t('dataValidation.panel.options')}
{show
? (
<MoreUpSingle className="univer-ml-1 univer-text-[8px]" />
<MoreUpSingle className="univer-ml-1" />
)
: (
<MoreDownSingle className="univer-ml-1 univer-text-[8px]" />
<MoreDownSingle className="univer-ml-1" />
)}
</div>
{show && (
@@ -291,7 +291,7 @@ export function SortOptionItem(props: ISortOptionItemProps) {
>
{itemLabel}
</span>
<MoreDownSingle className="univer-size-4 univer-text-gray-600" />
<MoreDownSingle />
</div>
</Dropdown>
</div>
@@ -119,7 +119,7 @@ export const SheetTableConditionPanel = (props: IConditionFilterProps) => {
{selectType}
</span>
<MoreDownSingle className="univer-text-gray-400" />
<MoreDownSingle />
</div>
</Dropdown>
@@ -133,7 +133,7 @@ export function BorderPanel(props: IBorderPanelProps) {
type="button"
>
<PaintBucket className="univer-fill-primary-600" extend={{ colorChannel1: value?.color ?? '' }} />
<MoreDownSingle className="univer-text-gray-400" />
<MoreDownSingle />
</button>
</Dropdown>
</div>
@@ -169,7 +169,7 @@ export function BorderPanel(props: IBorderPanelProps) {
type="button"
>
<BorderLine type={BorderStyleTypes.THIN} />
<MoreDownSingle className="univer-text-gray-400" />
<MoreDownSingle />
</button>
</Dropdown>
</div>
@@ -208,8 +208,8 @@ export const AutoFillPopupMenu: React.FC<{}> = () => {
'univer-bg-white': !visible,
})}
>
<Autofill className="univer-fill-green-500 univer-text-gray-900" />
{showMore && <MoreDownSingle className="univer-text-[10px] univer-text-gray-400" />}
<Autofill className="univer-fill-primary-600 univer-text-gray-900" />
{showMore && <MoreDownSingle />}
</div>
</DropdownMenu>
</div>
@@ -117,7 +117,7 @@ export function SlideImagePopupMenu(props: IImagePopupMenuProps) {
})}
>
<Autofill className="univer-fill-primary-600 univer-text-gray-900" />
{showMore && <MoreDownSingle className="univer-text-[10px] univer-text-gray-400" />}
{showMore && <MoreDownSingle />}
</div>
</Dropdown>
</div>
@@ -106,7 +106,7 @@ export default function ArrangePanel(props: IProps) {
>
<a className="univer-flex univer-cursor-pointer univer-items-center univer-gap-1">
<PaintBucket className="univer-fill-primary-600" />
<MoreDownSingle className="univer-text-[10px] univer-text-gray-400" />
<MoreDownSingle />
</a>
</Dropdown>
</div>
+1
View File
@@ -118,6 +118,7 @@ export * from './utils';
export { ComponentContainer, type IComponentContainerProps, useComponentsOfPart } from './views/components/ComponentContainer';
export { ZenZone } from './views/components/zen-zone/ZenZone';
export { Menu as DesktopMenu } from './components/menu/desktop/Menu';
export { ThemeSwitcherService } from './services/theme-switcher/theme-switcher.service';
// #region - workbench components
-22
View File
@@ -1176,9 +1176,6 @@ importers:
rc-picker:
specifier: ^4.9.0
version: 4.9.0(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
rc-select:
specifier: ^14.16.4
version: 14.16.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
rc-virtual-list:
specifier: ^3.16.1
version: 3.16.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -10267,13 +10264,6 @@ packages:
react: '19'
react-dom: '19'
rc-select@14.16.4:
resolution: {integrity: sha512-jP6qf7+vjnxGvPpfPWbGYfFlSl3h8L2XcD4O7g2GYXmEeBC0mw+nPD7i++OOE8v3YGqP8xtYjRKAWCMLfjgxlw==}
engines: {node: '>=8.x'}
peerDependencies:
react: '19'
react-dom: '19'
rc-util@5.43.0:
resolution: {integrity: sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==}
peerDependencies:
@@ -19365,18 +19355,6 @@ snapshots:
react-dom: 19.0.0(react@19.0.0)
resize-observer-polyfill: 1.5.1
rc-select@14.16.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
'@babel/runtime': 7.26.0
'@rc-component/trigger': 2.2.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
classnames: 2.5.1
rc-motion: 2.9.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
rc-overflow: 1.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
rc-util: 5.43.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
rc-virtual-list: 3.16.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
rc-util@5.43.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
'@babel/runtime': 7.24.7