@lobehub/ui 5.20.1 → 5.20.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -49,7 +49,7 @@ const motionTransition = {
49
49
  };
50
50
  const Button = ({ block, children, className, classNames, danger = false, disabled, ghost = false, href, htmlType = "button", icon, iconPosition = "start", loading, onClick, ref, shape = "default", size = "middle", styles: userStyles, target, type = "default", ...rest }) => {
51
51
  const Motion = useMotionComponent();
52
- const isDisabled = disabled || loading;
52
+ const isInteractionDisabled = disabled || loading;
53
53
  const sizeCls = resolveSizeCls(size);
54
54
  const variantCls = resolveVariantCls({
55
55
  danger,
@@ -73,21 +73,22 @@ const Button = ({ block, children, className, classNames, danger = false, disabl
73
73
  }) : null,
74
74
  children
75
75
  ] });
76
- const motionGestures = isDisabled ? {} : {
76
+ const motionGestures = isInteractionDisabled ? {} : {
77
77
  transition: motionTransition,
78
78
  whileTap: tapAnim
79
79
  };
80
80
  if (href !== void 0) {
81
81
  const handleAnchorClick = (e) => {
82
- if (isDisabled) {
82
+ if (isInteractionDisabled) {
83
83
  e.preventDefault();
84
84
  return;
85
85
  }
86
86
  onClick?.(e);
87
87
  };
88
88
  return /* @__PURE__ */ jsx(Motion.a, {
89
- "aria-disabled": isDisabled || void 0,
90
- href: isDisabled ? void 0 : href,
89
+ "aria-busy": loading || void 0,
90
+ "aria-disabled": isInteractionDisabled || void 0,
91
+ href: disabled ? void 0 : href,
91
92
  target,
92
93
  ...rest,
93
94
  className: composedClassName,
@@ -97,13 +98,22 @@ const Button = ({ block, children, className, classNames, danger = false, disabl
97
98
  children: inner
98
99
  });
99
100
  }
101
+ const handleButtonClick = (e) => {
102
+ if (isInteractionDisabled) {
103
+ e.preventDefault();
104
+ return;
105
+ }
106
+ onClick?.(e);
107
+ };
100
108
  return /* @__PURE__ */ jsx(Motion.button, {
101
109
  type: htmlType,
102
110
  ...rest,
111
+ "aria-busy": loading || void 0,
112
+ "aria-disabled": isInteractionDisabled || void 0,
103
113
  className: composedClassName,
104
- disabled: isDisabled,
114
+ disabled,
105
115
  ref,
106
- onClick,
116
+ onClick: handleButtonClick,
107
117
  ...motionGestures,
108
118
  children: inner
109
119
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Button.mjs","names":[],"sources":["../../../src/base-ui/Button/Button.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { isValidElement, type MouseEvent, type ReactNode, type Ref } from 'react';\n\nimport Icon, { type IconProps } from '@/Icon';\nimport { useMotionComponent } from '@/MotionProvider';\n\nimport { styles } from './style';\nimport type { ButtonProps } from './type';\n\nconst resolveIconNode = (node: ReactNode | IconProps['icon'] | undefined | null) => {\n if (node === undefined || node === null) return null;\n if (isValidElement(node) || typeof node === 'string' || typeof node === 'number') {\n return node;\n }\n return <Icon icon={node as any} size={'small'} />;\n};\n\nconst resolveSizeCls = (size: ButtonProps['size']) => {\n if (size === 'small') return styles.sizeSmall;\n if (size === 'large') return styles.sizeLarge;\n return styles.sizeMiddle;\n};\n\nconst resolveIconOnlySizeCls = (size: ButtonProps['size']) => {\n if (size === 'small') return styles.iconOnlySmall;\n if (size === 'large') return styles.iconOnlyLarge;\n return styles.iconOnlyMiddle;\n};\n\nconst resolveVariantCls = ({\n danger,\n ghost,\n type,\n}: {\n danger: boolean;\n ghost: boolean;\n type: NonNullable<ButtonProps['type']>;\n}): string => {\n if (ghost) {\n if (danger) return styles.ghostDanger;\n if (type === 'primary') return styles.ghostPrimary;\n if (type === 'dashed') return cx(styles.ghostDefault, styles.ghostDashed);\n return styles.ghostDefault;\n }\n\n switch (type) {\n case 'primary': {\n return danger ? styles.dangerSolid : styles.variantPrimary;\n }\n case 'dashed': {\n return danger ? cx(styles.variantDashed, styles.dangerOutlined) : styles.variantDashed;\n }\n case 'fill': {\n return danger ? styles.dangerFill : styles.variantFill;\n }\n case 'text': {\n return danger ? cx(styles.variantText, styles.dangerInline) : styles.variantText;\n }\n case 'link': {\n return danger ? cx(styles.variantLink, styles.dangerInline) : styles.variantLink;\n }\n default: {\n return danger ? cx(styles.variantDefault, styles.dangerOutlined) : styles.variantDefault;\n }\n }\n};\n\nconst tapAnim = { scale: 0.98 };\nconst motionTransition = {\n damping: 26,\n mass: 0.6,\n stiffness: 600,\n type: 'spring' as const,\n};\n\nconst Button = ({\n block,\n children,\n className,\n classNames,\n danger = false,\n disabled,\n ghost = false,\n href,\n htmlType = 'button',\n icon,\n iconPosition = 'start',\n loading,\n onClick,\n ref,\n shape = 'default',\n size = 'middle',\n styles: userStyles,\n target,\n type = 'default',\n ...rest\n}: ButtonProps) => {\n const Motion = useMotionComponent();\n const isDisabled = disabled || loading;\n const sizeCls = resolveSizeCls(size);\n const variantCls = resolveVariantCls({ danger, ghost, type });\n const shapeCls =\n shape === 'circle' ? styles.shapeCircle : shape === 'round' ? styles.shapeRound : undefined;\n\n const hasChildren =\n children !== undefined && children !== null && children !== false && children !== '';\n const renderIcon = loading || icon;\n const iconOnly = !hasChildren && !!renderIcon;\n const iconOnlySizeCls = iconOnly ? resolveIconOnlySizeCls(size) : undefined;\n\n const composedClassName = cx(\n styles.base,\n sizeCls,\n variantCls,\n shapeCls,\n block && styles.block,\n iconPosition === 'end' && styles.iconEnd,\n iconOnlySizeCls,\n className,\n );\n\n const spinnerNode = (\n <span\n aria-hidden={!loading}\n style={userStyles?.icon}\n className={cx(\n styles.iconBox,\n styles.spinnerSlot,\n loading && styles.spinnerSlotShow,\n iconPosition === 'end' && styles.spinnerSlotEnd,\n classNames?.icon,\n )}\n >\n <span className={styles.spinner} />\n </span>\n );\n\n const iconNode =\n icon && !loading ? (\n <span className={cx(styles.iconBox, classNames?.icon)} style={userStyles?.icon}>\n {resolveIconNode(icon)}\n </span>\n ) : null;\n\n const inner = (\n <>\n {spinnerNode}\n {iconNode}\n {children}\n </>\n );\n\n const motionGestures = isDisabled ? {} : { transition: motionTransition, whileTap: tapAnim };\n\n if (href !== undefined) {\n const handleAnchorClick = (e: MouseEvent<HTMLAnchorElement>) => {\n if (isDisabled) {\n e.preventDefault();\n return;\n }\n onClick?.(e as unknown as MouseEvent<HTMLButtonElement>);\n };\n\n return (\n <Motion.a\n aria-disabled={isDisabled || undefined}\n href={isDisabled ? undefined : href}\n target={target}\n {...(rest as any)}\n className={composedClassName}\n ref={ref as Ref<HTMLAnchorElement>}\n onClick={handleAnchorClick}\n {...motionGestures}\n >\n {inner}\n </Motion.a>\n );\n }\n\n return (\n <Motion.button\n type={htmlType}\n {...(rest as any)}\n className={composedClassName}\n disabled={isDisabled}\n ref={ref as Ref<HTMLButtonElement>}\n onClick={onClick}\n {...motionGestures}\n >\n {inner}\n </Motion.button>\n );\n};\n\nButton.displayName = 'BaseButton';\n\nexport default Button;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Button.mjs","names":[],"sources":["../../../src/base-ui/Button/Button.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { isValidElement, type MouseEvent, type ReactNode, type Ref } from 'react';\n\nimport Icon, { type IconProps } from '@/Icon';\nimport { useMotionComponent } from '@/MotionProvider';\n\nimport { styles } from './style';\nimport type { ButtonProps } from './type';\n\nconst resolveIconNode = (node: ReactNode | IconProps['icon'] | undefined | null) => {\n if (node === undefined || node === null) return null;\n if (isValidElement(node) || typeof node === 'string' || typeof node === 'number') {\n return node;\n }\n return <Icon icon={node as any} size={'small'} />;\n};\n\nconst resolveSizeCls = (size: ButtonProps['size']) => {\n if (size === 'small') return styles.sizeSmall;\n if (size === 'large') return styles.sizeLarge;\n return styles.sizeMiddle;\n};\n\nconst resolveIconOnlySizeCls = (size: ButtonProps['size']) => {\n if (size === 'small') return styles.iconOnlySmall;\n if (size === 'large') return styles.iconOnlyLarge;\n return styles.iconOnlyMiddle;\n};\n\nconst resolveVariantCls = ({\n danger,\n ghost,\n type,\n}: {\n danger: boolean;\n ghost: boolean;\n type: NonNullable<ButtonProps['type']>;\n}): string => {\n if (ghost) {\n if (danger) return styles.ghostDanger;\n if (type === 'primary') return styles.ghostPrimary;\n if (type === 'dashed') return cx(styles.ghostDefault, styles.ghostDashed);\n return styles.ghostDefault;\n }\n\n switch (type) {\n case 'primary': {\n return danger ? styles.dangerSolid : styles.variantPrimary;\n }\n case 'dashed': {\n return danger ? cx(styles.variantDashed, styles.dangerOutlined) : styles.variantDashed;\n }\n case 'fill': {\n return danger ? styles.dangerFill : styles.variantFill;\n }\n case 'text': {\n return danger ? cx(styles.variantText, styles.dangerInline) : styles.variantText;\n }\n case 'link': {\n return danger ? cx(styles.variantLink, styles.dangerInline) : styles.variantLink;\n }\n default: {\n return danger ? cx(styles.variantDefault, styles.dangerOutlined) : styles.variantDefault;\n }\n }\n};\n\nconst tapAnim = { scale: 0.98 };\nconst motionTransition = {\n damping: 26,\n mass: 0.6,\n stiffness: 600,\n type: 'spring' as const,\n};\n\nconst Button = ({\n block,\n children,\n className,\n classNames,\n danger = false,\n disabled,\n ghost = false,\n href,\n htmlType = 'button',\n icon,\n iconPosition = 'start',\n loading,\n onClick,\n ref,\n shape = 'default',\n size = 'middle',\n styles: userStyles,\n target,\n type = 'default',\n ...rest\n}: ButtonProps) => {\n const Motion = useMotionComponent();\n const isInteractionDisabled = disabled || loading;\n const sizeCls = resolveSizeCls(size);\n const variantCls = resolveVariantCls({ danger, ghost, type });\n const shapeCls =\n shape === 'circle' ? styles.shapeCircle : shape === 'round' ? styles.shapeRound : undefined;\n\n const hasChildren =\n children !== undefined && children !== null && children !== false && children !== '';\n const renderIcon = loading || icon;\n const iconOnly = !hasChildren && !!renderIcon;\n const iconOnlySizeCls = iconOnly ? resolveIconOnlySizeCls(size) : undefined;\n\n const composedClassName = cx(\n styles.base,\n sizeCls,\n variantCls,\n shapeCls,\n block && styles.block,\n iconPosition === 'end' && styles.iconEnd,\n iconOnlySizeCls,\n className,\n );\n\n const spinnerNode = (\n <span\n aria-hidden={!loading}\n style={userStyles?.icon}\n className={cx(\n styles.iconBox,\n styles.spinnerSlot,\n loading && styles.spinnerSlotShow,\n iconPosition === 'end' && styles.spinnerSlotEnd,\n classNames?.icon,\n )}\n >\n <span className={styles.spinner} />\n </span>\n );\n\n const iconNode =\n icon && !loading ? (\n <span className={cx(styles.iconBox, classNames?.icon)} style={userStyles?.icon}>\n {resolveIconNode(icon)}\n </span>\n ) : null;\n\n const inner = (\n <>\n {spinnerNode}\n {iconNode}\n {children}\n </>\n );\n\n const motionGestures = isInteractionDisabled\n ? {}\n : { transition: motionTransition, whileTap: tapAnim };\n\n if (href !== undefined) {\n const handleAnchorClick = (e: MouseEvent<HTMLAnchorElement>) => {\n if (isInteractionDisabled) {\n e.preventDefault();\n return;\n }\n onClick?.(e as unknown as MouseEvent<HTMLButtonElement>);\n };\n\n return (\n <Motion.a\n aria-busy={loading || undefined}\n aria-disabled={isInteractionDisabled || undefined}\n href={disabled ? undefined : href}\n target={target}\n {...(rest as any)}\n className={composedClassName}\n ref={ref as Ref<HTMLAnchorElement>}\n onClick={handleAnchorClick}\n {...motionGestures}\n >\n {inner}\n </Motion.a>\n );\n }\n\n const handleButtonClick = (e: MouseEvent<HTMLButtonElement>) => {\n if (isInteractionDisabled) {\n e.preventDefault();\n return;\n }\n onClick?.(e);\n };\n\n return (\n <Motion.button\n type={htmlType}\n {...(rest as any)}\n aria-busy={loading || undefined}\n aria-disabled={isInteractionDisabled || undefined}\n className={composedClassName}\n disabled={disabled}\n ref={ref as Ref<HTMLButtonElement>}\n onClick={handleButtonClick}\n {...motionGestures}\n >\n {inner}\n </Motion.button>\n );\n};\n\nButton.displayName = 'BaseButton';\n\nexport default Button;\n"],"mappings":"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"}
@@ -14,13 +14,14 @@ import { Select } from "@base-ui/react/select";
14
14
  const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOpen, defaultValue, disabled, id, labelRender, listHeight = 512, listItemHeight, loading, mode, name, onChange, onOpenChange, onSelect, open, optionRender, options, placeholder, popupClassName, popupMatchSelectWidth, prefix, readOnly, required, behaviorVariant = "default", selectedIndicatorVariant = "check", shadow, showSearch, size = "middle", style, suffixIcon, suffixIconProps, tokenSeparators, value, variant, virtual }) => {
15
15
  const { isDarkMode } = useThemeMode();
16
16
  const resolvedVariant = variant ?? (isDarkMode ? "filled" : "outlined");
17
+ const isTags = mode === "tags";
17
18
  const isMultiple = mode === "multiple" || mode === "tags";
18
19
  const isItemAligned = behaviorVariant === "item-aligned";
19
20
  const [extraOptions, setExtraOptions] = useState([]);
20
21
  useEffect(() => {
21
22
  if (mode !== "tags" && extraOptions.length > 0) setExtraOptions([]);
22
23
  }, [mode, extraOptions.length]);
23
- const { appendTagValues, getOption, handleValueChange, normalizedValue, normalizeValue, resolvedOptions, valueArray } = useSelectValue({
24
+ const { appendTagValues, getOption, handleValueChange, normalizedValue, normalizeValue, removeLastTagValue, resolvedOptions, valueArray } = useSelectValue({
24
25
  defaultValue,
25
26
  extraOptions,
26
27
  isMultiple,
@@ -35,11 +36,20 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
35
36
  onOpenChange,
36
37
  open
37
38
  });
39
+ const handleRootValueChange = useCallback((nextValue) => {
40
+ if (!(isTags && !mergedOpen)) handleValueChange(nextValue);
41
+ }, [
42
+ handleValueChange,
43
+ isTags,
44
+ mergedOpen
45
+ ]);
46
+ const handleRemoveTag = useCallback((index) => handleValueChange(valueArray.filter((_, itemIndex) => itemIndex !== index)), [handleValueChange, valueArray]);
38
47
  const { filteredOptions, handleSearchChange, handleSearchKeyDown, searchValue, shouldShowSearch, stopSearchPropagation } = useSelectSearch({
39
48
  appendTagValues,
40
49
  handleOpenChange,
41
50
  mergedOpen,
42
51
  mode,
52
+ removeLastTagValue,
43
53
  resolvedOptions,
44
54
  showSearch,
45
55
  tokenSeparators
@@ -55,12 +65,16 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
55
65
  const renderValue = useMemo(() => createTriggerValueRenderer({
56
66
  getOption,
57
67
  isMultiple,
68
+ isTags,
58
69
  labelRender,
59
70
  normalizeValue,
60
- placeholder
71
+ onRemoveValue: handleRemoveTag,
72
+ placeholder: isTags ? void 0 : placeholder
61
73
  }), [
62
74
  getOption,
75
+ handleRemoveTag,
63
76
  isMultiple,
77
+ isTags,
64
78
  labelRender,
65
79
  normalizeValue,
66
80
  placeholder
@@ -130,11 +144,13 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
130
144
  required,
131
145
  value: normalizedValue,
132
146
  onOpenChange: handleOpenChange,
133
- onValueChange: handleValueChange,
147
+ onValueChange: handleRootValueChange,
134
148
  children: [/* @__PURE__ */ jsxs(Select.Trigger, {
135
- autoFocus,
149
+ autoFocus: !isTags && autoFocus,
136
150
  className: triggerClassName,
137
151
  disabled,
152
+ nativeButton: !isTags,
153
+ render: isTags ? /* @__PURE__ */ jsx("div", {}) : void 0,
138
154
  style,
139
155
  children: [
140
156
  prefixNode !== null && prefixNode !== void 0 && /* @__PURE__ */ jsx("span", {
@@ -142,9 +158,21 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
142
158
  children: prefixNode
143
159
  }),
144
160
  /* @__PURE__ */ jsx(Select.Value, {
145
- className: cx(styles$1.value, classNames?.value),
161
+ className: cx(styles$1.value, isTags && styles$1.tagsValue, classNames?.value),
146
162
  children: renderValue
147
163
  }),
164
+ isTags && /* @__PURE__ */ jsx(SelectSearchInput, {
165
+ inline: true,
166
+ autoFocus,
167
+ classNames,
168
+ disabled,
169
+ placeholder: valueArray.length === 0 ? placeholder : void 0,
170
+ readOnly,
171
+ stopPropagation: stopSearchPropagation,
172
+ value: searchValue,
173
+ onChange: handleSearchChange,
174
+ onKeyDown: handleSearchKeyDown
175
+ }),
148
176
  /* @__PURE__ */ jsx(SelectTriggerSuffix, {
149
177
  classNames,
150
178
  showClear,
@@ -163,7 +191,7 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
163
191
  children: /* @__PURE__ */ jsxs(Select.Popup, {
164
192
  style: popupStyle,
165
193
  className: cx(styles.popup, styles$1.popup, popupClassName, classNames?.popup, classNames?.dropdown),
166
- children: [shouldShowSearch && /* @__PURE__ */ jsx(SelectSearchInput, {
194
+ children: [shouldShowSearch && !isTags && /* @__PURE__ */ jsx(SelectSearchInput, {
167
195
  classNames,
168
196
  placeholder,
169
197
  stopPropagation: stopSearchPropagation,
@@ -172,6 +200,7 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
172
200
  onKeyDown: handleSearchKeyDown
173
201
  }), /* @__PURE__ */ jsx(SelectListSection, {
174
202
  classNames,
203
+ hasSearch: shouldShowSearch && !isTags,
175
204
  isEmpty,
176
205
  listContent,
177
206
  listItemHeight,
@@ -1 +1 @@
1
- {"version":3,"file":"Select.mjs","names":["Select","menuStyles","styles","BaseSelect"],"sources":["../../../src/base-ui/Select/Select.tsx"],"sourcesContent":["'use client';\n\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cx, useThemeMode } from 'antd-style';\nimport { type MouseEvent } from 'react';\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { styles as menuStyles } from '@/base-ui/DropdownMenu/sharedStyle';\n\nimport { SelectPositioner } from './atoms';\nimport { isValueEmpty } from './helpers';\nimport {\n usePortalContainer,\n useSelectOpen,\n useSelectSearch,\n useSelectValue,\n useSelectVirtual,\n} from './hooks';\nimport {\n createTriggerValueRenderer,\n EmptyContent,\n resolveIconNode,\n resolveSuffixIcon,\n SelectListSection,\n SelectSearchInput,\n SelectTriggerSuffix,\n} from './parts';\nimport { renderOptions } from './renderOptions';\nimport { styles, triggerVariants } from './style';\nimport { type SelectOption, type SelectProps } from './type';\n\nconst Select = memo<SelectProps<any>>(\n ({\n allowClear,\n autoFocus,\n className,\n classNames,\n defaultOpen,\n defaultValue,\n disabled,\n id,\n labelRender,\n listHeight = 512,\n listItemHeight,\n loading,\n mode,\n name,\n onChange,\n onOpenChange,\n onSelect,\n open,\n optionRender,\n options,\n placeholder,\n popupClassName,\n popupMatchSelectWidth,\n prefix,\n readOnly,\n required,\n behaviorVariant = 'default',\n selectedIndicatorVariant = 'check',\n shadow,\n showSearch,\n size = 'middle',\n style,\n suffixIcon,\n suffixIconProps,\n tokenSeparators,\n value,\n variant,\n virtual,\n }) => {\n const { isDarkMode } = useThemeMode();\n const resolvedVariant = variant ?? (isDarkMode ? 'filled' : 'outlined');\n const isMultiple = mode === 'multiple' || mode === 'tags';\n const isItemAligned = behaviorVariant === 'item-aligned';\n\n const [extraOptions, setExtraOptions] = useState<SelectOption<any>[]>([]);\n\n useEffect(() => {\n if (mode !== 'tags' && extraOptions.length > 0) {\n setExtraOptions([]);\n }\n }, [mode, extraOptions.length]);\n\n const {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n resolvedOptions,\n valueArray,\n } = useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n });\n\n const { handleOpenChange, mergedOpen } = useSelectOpen({ defaultOpen, onOpenChange, open });\n\n const {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n } = useSelectSearch({\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n });\n\n const virtualState = useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n });\n\n const portalContainer = usePortalContainer();\n\n const renderValue = useMemo(\n () =>\n createTriggerValueRenderer({\n getOption,\n isMultiple,\n labelRender,\n normalizeValue,\n placeholder,\n }),\n [getOption, isMultiple, labelRender, normalizeValue, placeholder],\n );\n\n const hasValue = isMultiple ? valueArray.length > 0 : !isValueEmpty(normalizedValue);\n const showClear = Boolean(allowClear && hasValue && !disabled && !readOnly);\n\n const handleClear = useCallback(\n (event: MouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n handleValueChange(isMultiple ? [] : null);\n },\n [handleValueChange, isMultiple],\n );\n\n const prefixNode = useMemo(() => resolveIconNode(prefix), [prefix]);\n const suffixIconNode = useMemo(\n () => resolveSuffixIcon(suffixIcon, suffixIconProps, loading),\n [loading, suffixIcon, suffixIconProps],\n );\n\n const popupStyle = useMemo(() => {\n const maxHeight = isItemAligned ? '80vh' : `${listHeight}px`;\n const baseStyle: React.CSSProperties = {\n maxHeight,\n maxWidth: 'var(--available-width)',\n minWidth: 'var(--anchor-width)',\n ['--lobe-select-popup-max-height' as any]: maxHeight,\n };\n\n if (popupMatchSelectWidth === undefined || popupMatchSelectWidth === true) {\n return baseStyle;\n }\n if (typeof popupMatchSelectWidth === 'number') {\n return {\n ...baseStyle,\n minWidth: popupMatchSelectWidth,\n width: popupMatchSelectWidth,\n };\n }\n return { ...baseStyle, minWidth: 'max-content' };\n }, [isItemAligned, listHeight, popupMatchSelectWidth]);\n\n const triggerClassName = cx(\n triggerVariants({ shadow, size, variant: resolvedVariant }),\n className,\n classNames?.root,\n classNames?.trigger,\n );\n\n const isBoldIndicator = selectedIndicatorVariant === 'bold';\n const itemTextClassName = cx(\n optionRender ? menuStyles.itemContent : menuStyles.label,\n styles.itemText,\n classNames?.itemText,\n );\n\n const isEmpty = filteredOptions.length === 0;\n const listContent = isEmpty ? (\n <EmptyContent classNames={classNames} />\n ) : (\n renderOptions({\n classNames,\n isBoldIndicator,\n items: filteredOptions,\n itemTextClassName,\n listItemHeight,\n optionRender,\n renderVirtualItem: virtualState.renderVirtualItem,\n virtual,\n })\n );\n\n return (\n <BaseSelect.Root\n disabled={disabled}\n id={id}\n modal={isItemAligned}\n multiple={isMultiple}\n name={name}\n open={mergedOpen}\n readOnly={readOnly}\n required={required}\n value={normalizedValue}\n onOpenChange={handleOpenChange}\n onValueChange={handleValueChange}\n >\n <BaseSelect.Trigger\n autoFocus={autoFocus}\n className={triggerClassName}\n disabled={disabled}\n style={style}\n >\n {prefixNode !== null && prefixNode !== undefined && (\n <span className={cx(styles.prefix, classNames?.prefix)}>{prefixNode}</span>\n )}\n <BaseSelect.Value className={cx(styles.value, classNames?.value)}>\n {renderValue}\n </BaseSelect.Value>\n <SelectTriggerSuffix\n classNames={classNames}\n showClear={showClear}\n suffixIconNode={suffixIconNode}\n onClear={handleClear}\n />\n </BaseSelect.Trigger>\n\n <BaseSelect.Portal container={portalContainer}>\n <SelectPositioner\n align=\"start\"\n alignItemWithTrigger={isItemAligned}\n className={styles.positioner}\n side=\"bottom\"\n sideOffset={6}\n >\n <BaseSelect.Popup\n style={popupStyle}\n className={cx(\n menuStyles.popup,\n styles.popup,\n popupClassName,\n classNames?.popup,\n classNames?.dropdown,\n )}\n >\n {shouldShowSearch && (\n <SelectSearchInput\n classNames={classNames}\n placeholder={placeholder}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectListSection\n classNames={classNames}\n isEmpty={isEmpty}\n listContent={listContent}\n listItemHeight={listItemHeight}\n virtual={virtual}\n virtualState={virtualState}\n />\n </BaseSelect.Popup>\n </SelectPositioner>\n </BaseSelect.Portal>\n </BaseSelect.Root>\n );\n },\n);\n\nSelect.displayName = 'Select';\n\nexport default Select;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Select.mjs","names":["Select","menuStyles","styles","BaseSelect"],"sources":["../../../src/base-ui/Select/Select.tsx"],"sourcesContent":["'use client';\n\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cx, useThemeMode } from 'antd-style';\nimport { type MouseEvent } from 'react';\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { styles as menuStyles } from '@/base-ui/DropdownMenu/sharedStyle';\n\nimport { SelectPositioner } from './atoms';\nimport { isValueEmpty } from './helpers';\nimport {\n usePortalContainer,\n useSelectOpen,\n useSelectSearch,\n useSelectValue,\n useSelectVirtual,\n} from './hooks';\nimport {\n createTriggerValueRenderer,\n EmptyContent,\n resolveIconNode,\n resolveSuffixIcon,\n SelectListSection,\n SelectSearchInput,\n SelectTriggerSuffix,\n} from './parts';\nimport { renderOptions } from './renderOptions';\nimport { styles, triggerVariants } from './style';\nimport { type SelectOption, type SelectProps } from './type';\n\nconst Select = memo<SelectProps<any>>(\n ({\n allowClear,\n autoFocus,\n className,\n classNames,\n defaultOpen,\n defaultValue,\n disabled,\n id,\n labelRender,\n listHeight = 512,\n listItemHeight,\n loading,\n mode,\n name,\n onChange,\n onOpenChange,\n onSelect,\n open,\n optionRender,\n options,\n placeholder,\n popupClassName,\n popupMatchSelectWidth,\n prefix,\n readOnly,\n required,\n behaviorVariant = 'default',\n selectedIndicatorVariant = 'check',\n shadow,\n showSearch,\n size = 'middle',\n style,\n suffixIcon,\n suffixIconProps,\n tokenSeparators,\n value,\n variant,\n virtual,\n }) => {\n const { isDarkMode } = useThemeMode();\n const resolvedVariant = variant ?? (isDarkMode ? 'filled' : 'outlined');\n const isTags = mode === 'tags';\n const isMultiple = mode === 'multiple' || mode === 'tags';\n const isItemAligned = behaviorVariant === 'item-aligned';\n\n const [extraOptions, setExtraOptions] = useState<SelectOption<any>[]>([]);\n\n useEffect(() => {\n if (mode !== 'tags' && extraOptions.length > 0) {\n setExtraOptions([]);\n }\n }, [mode, extraOptions.length]);\n\n const {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n removeLastTagValue,\n resolvedOptions,\n valueArray,\n } = useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n });\n\n const { handleOpenChange, mergedOpen } = useSelectOpen({ defaultOpen, onOpenChange, open });\n\n const handleRootValueChange = useCallback(\n (nextValue: any) => {\n if (!(isTags && !mergedOpen)) handleValueChange(nextValue);\n },\n [handleValueChange, isTags, mergedOpen],\n );\n\n const handleRemoveTag = useCallback(\n (index: number) =>\n handleValueChange(valueArray.filter((_, itemIndex) => itemIndex !== index)),\n [handleValueChange, valueArray],\n );\n\n const {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n } = useSelectSearch({\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n removeLastTagValue,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n });\n\n const virtualState = useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n });\n\n const portalContainer = usePortalContainer();\n\n const renderValue = useMemo(\n () =>\n createTriggerValueRenderer({\n getOption,\n isMultiple,\n isTags,\n labelRender,\n normalizeValue,\n onRemoveValue: handleRemoveTag,\n placeholder: isTags ? undefined : placeholder,\n }),\n [getOption, handleRemoveTag, isMultiple, isTags, labelRender, normalizeValue, placeholder],\n );\n\n const hasValue = isMultiple ? valueArray.length > 0 : !isValueEmpty(normalizedValue);\n const showClear = Boolean(allowClear && hasValue && !disabled && !readOnly);\n\n const handleClear = useCallback(\n (event: MouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n handleValueChange(isMultiple ? [] : null);\n },\n [handleValueChange, isMultiple],\n );\n\n const prefixNode = useMemo(() => resolveIconNode(prefix), [prefix]);\n const suffixIconNode = useMemo(\n () => resolveSuffixIcon(suffixIcon, suffixIconProps, loading),\n [loading, suffixIcon, suffixIconProps],\n );\n\n const popupStyle = useMemo(() => {\n const maxHeight = isItemAligned ? '80vh' : `${listHeight}px`;\n const baseStyle: React.CSSProperties = {\n maxHeight,\n maxWidth: 'var(--available-width)',\n minWidth: 'var(--anchor-width)',\n ['--lobe-select-popup-max-height' as any]: maxHeight,\n };\n\n if (popupMatchSelectWidth === undefined || popupMatchSelectWidth === true) {\n return baseStyle;\n }\n if (typeof popupMatchSelectWidth === 'number') {\n return {\n ...baseStyle,\n minWidth: popupMatchSelectWidth,\n width: popupMatchSelectWidth,\n };\n }\n return { ...baseStyle, minWidth: 'max-content' };\n }, [isItemAligned, listHeight, popupMatchSelectWidth]);\n\n const triggerClassName = cx(\n triggerVariants({ shadow, size, variant: resolvedVariant }),\n className,\n classNames?.root,\n classNames?.trigger,\n );\n\n const isBoldIndicator = selectedIndicatorVariant === 'bold';\n const itemTextClassName = cx(\n optionRender ? menuStyles.itemContent : menuStyles.label,\n styles.itemText,\n classNames?.itemText,\n );\n\n const isEmpty = filteredOptions.length === 0;\n const listContent = isEmpty ? (\n <EmptyContent classNames={classNames} />\n ) : (\n renderOptions({\n classNames,\n isBoldIndicator,\n items: filteredOptions,\n itemTextClassName,\n listItemHeight,\n optionRender,\n renderVirtualItem: virtualState.renderVirtualItem,\n virtual,\n })\n );\n\n return (\n <BaseSelect.Root\n disabled={disabled}\n id={id}\n modal={isItemAligned}\n multiple={isMultiple}\n name={name}\n open={mergedOpen}\n readOnly={readOnly}\n required={required}\n value={normalizedValue}\n onOpenChange={handleOpenChange}\n onValueChange={handleRootValueChange}\n >\n <BaseSelect.Trigger\n autoFocus={!isTags && autoFocus}\n className={triggerClassName}\n disabled={disabled}\n nativeButton={!isTags}\n render={isTags ? <div /> : undefined}\n style={style}\n >\n {prefixNode !== null && prefixNode !== undefined && (\n <span className={cx(styles.prefix, classNames?.prefix)}>{prefixNode}</span>\n )}\n <BaseSelect.Value\n className={cx(styles.value, isTags && styles.tagsValue, classNames?.value)}\n >\n {renderValue}\n </BaseSelect.Value>\n {isTags && (\n <SelectSearchInput\n inline\n autoFocus={autoFocus}\n classNames={classNames}\n disabled={disabled}\n placeholder={valueArray.length === 0 ? placeholder : undefined}\n readOnly={readOnly}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectTriggerSuffix\n classNames={classNames}\n showClear={showClear}\n suffixIconNode={suffixIconNode}\n onClear={handleClear}\n />\n </BaseSelect.Trigger>\n\n <BaseSelect.Portal container={portalContainer}>\n <SelectPositioner\n align=\"start\"\n alignItemWithTrigger={isItemAligned}\n className={styles.positioner}\n side=\"bottom\"\n sideOffset={6}\n >\n <BaseSelect.Popup\n style={popupStyle}\n className={cx(\n menuStyles.popup,\n styles.popup,\n popupClassName,\n classNames?.popup,\n classNames?.dropdown,\n )}\n >\n {shouldShowSearch && !isTags && (\n <SelectSearchInput\n classNames={classNames}\n placeholder={placeholder}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectListSection\n classNames={classNames}\n hasSearch={shouldShowSearch && !isTags}\n isEmpty={isEmpty}\n listContent={listContent}\n listItemHeight={listItemHeight}\n virtual={virtual}\n virtualState={virtualState}\n />\n </BaseSelect.Popup>\n </SelectPositioner>\n </BaseSelect.Portal>\n </BaseSelect.Root>\n );\n },\n);\n\nSelect.displayName = 'Select';\n\nexport default Select;\n"],"mappings":"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"}
@@ -2,8 +2,8 @@
2
2
  const isGroupOption = (option) => Boolean(option.options);
3
3
  const getOptionSearchText = (option) => {
4
4
  if (typeof option.label === "string" || typeof option.label === "number") return String(option.label);
5
- if (typeof option.value === "string" || typeof option.value === "number") return String(option.value);
6
5
  if (option.title) return option.title;
6
+ if (typeof option.value === "string" || typeof option.value === "number") return String(option.value);
7
7
  return "";
8
8
  };
9
9
  const escapeRegExp = (value) => value.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&");
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.mjs","names":[],"sources":["../../../src/base-ui/Select/helpers.ts"],"sourcesContent":["import { type SelectOption, type SelectOptionGroup, type SelectOptions } from './type';\n\nexport const isGroupOption = <Value>(\n option: SelectOption<Value> | SelectOptionGroup<Value>,\n): option is SelectOptionGroup<Value> => Boolean((option as SelectOptionGroup<Value>).options);\n\nexport const getOptionSearchText = <Value>(option: SelectOption<Value>) => {\n if (typeof option.label === 'string' || typeof option.label === 'number') {\n return String(option.label);\n }\n if (typeof option.value === 'string' || typeof option.value === 'number') {\n return String(option.value);\n }\n if (option.title) return option.title;\n return '';\n};\n\nconst escapeRegExp = (value: string) => value.replaceAll(/[$()*+.?[\\\\\\]^{|}]/g, '\\\\$&');\n\nexport const splitBySeparators = (value: string, separators?: string[]) => {\n if (!separators || separators.length === 0) return [value];\n const pattern = separators.map(escapeRegExp).join('|');\n return value.split(new RegExp(pattern, 'g'));\n};\n\nexport const countVirtualItems = (items: SelectOptions) =>\n items.reduce((count, item) => {\n if (isGroupOption(item)) {\n return count + item.options.length + 1;\n }\n return count + 1;\n }, 0);\n\nexport const isValueEmpty = (value: unknown) =>\n value === null || value === undefined || value === '';\n\nexport const normalizeValueFor = (isMultiple: boolean) => (nextValue: any) => {\n if (isMultiple) {\n if (Array.isArray(nextValue)) return nextValue;\n if (nextValue === null || nextValue === undefined) return [];\n return [nextValue];\n }\n if (Array.isArray(nextValue)) return nextValue[0] ?? null;\n return nextValue === undefined ? null : nextValue;\n};\n"],"mappings":";AAEA,MAAa,iBACX,WACuC,QAAS,OAAoC,QAAQ;AAE9F,MAAa,uBAA8B,WAAgC;AACzE,KAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,UAAU,SAC9D,QAAO,OAAO,OAAO,MAAM;AAE7B,KAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,UAAU,SAC9D,QAAO,OAAO,OAAO,MAAM;AAE7B,KAAI,OAAO,MAAO,QAAO,OAAO;AAChC,QAAO;;AAGT,MAAM,gBAAgB,UAAkB,MAAM,WAAW,uBAAuB,OAAO;AAEvF,MAAa,qBAAqB,OAAe,eAA0B;AACzE,KAAI,CAAC,cAAc,WAAW,WAAW,EAAG,QAAO,CAAC,MAAM;CAC1D,MAAM,UAAU,WAAW,IAAI,aAAa,CAAC,KAAK,IAAI;AACtD,QAAO,MAAM,MAAM,IAAI,OAAO,SAAS,IAAI,CAAC;;AAG9C,MAAa,qBAAqB,UAChC,MAAM,QAAQ,OAAO,SAAS;AAC5B,KAAI,cAAc,KAAK,CACrB,QAAO,QAAQ,KAAK,QAAQ,SAAS;AAEvC,QAAO,QAAQ;GACd,EAAE;AAEP,MAAa,gBAAgB,UAC3B,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU;AAErD,MAAa,qBAAqB,gBAAyB,cAAmB;AAC5E,KAAI,YAAY;AACd,MAAI,MAAM,QAAQ,UAAU,CAAE,QAAO;AACrC,MAAI,cAAc,QAAQ,cAAc,KAAA,EAAW,QAAO,EAAE;AAC5D,SAAO,CAAC,UAAU;;AAEpB,KAAI,MAAM,QAAQ,UAAU,CAAE,QAAO,UAAU,MAAM;AACrD,QAAO,cAAc,KAAA,IAAY,OAAO"}
1
+ {"version":3,"file":"helpers.mjs","names":[],"sources":["../../../src/base-ui/Select/helpers.ts"],"sourcesContent":["import { type SelectOption, type SelectOptionGroup, type SelectOptions } from './type';\n\nexport const isGroupOption = <Value>(\n option: SelectOption<Value> | SelectOptionGroup<Value>,\n): option is SelectOptionGroup<Value> => Boolean((option as SelectOptionGroup<Value>).options);\n\nexport const getOptionSearchText = <Value>(option: SelectOption<Value>) => {\n if (typeof option.label === 'string' || typeof option.label === 'number') {\n return String(option.label);\n }\n if (option.title) return option.title;\n if (typeof option.value === 'string' || typeof option.value === 'number') {\n return String(option.value);\n }\n return '';\n};\n\nconst escapeRegExp = (value: string) => value.replaceAll(/[$()*+.?[\\\\\\]^{|}]/g, '\\\\$&');\n\nexport const splitBySeparators = (value: string, separators?: string[]) => {\n if (!separators || separators.length === 0) return [value];\n const pattern = separators.map(escapeRegExp).join('|');\n return value.split(new RegExp(pattern, 'g'));\n};\n\nexport const countVirtualItems = (items: SelectOptions) =>\n items.reduce((count, item) => {\n if (isGroupOption(item)) {\n return count + item.options.length + 1;\n }\n return count + 1;\n }, 0);\n\nexport const isValueEmpty = (value: unknown) =>\n value === null || value === undefined || value === '';\n\nexport const normalizeValueFor = (isMultiple: boolean) => (nextValue: any) => {\n if (isMultiple) {\n if (Array.isArray(nextValue)) return nextValue;\n if (nextValue === null || nextValue === undefined) return [];\n return [nextValue];\n }\n if (Array.isArray(nextValue)) return nextValue[0] ?? null;\n return nextValue === undefined ? null : nextValue;\n};\n"],"mappings":";AAEA,MAAa,iBACX,WACuC,QAAS,OAAoC,QAAQ;AAE9F,MAAa,uBAA8B,WAAgC;AACzE,KAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,UAAU,SAC9D,QAAO,OAAO,OAAO,MAAM;AAE7B,KAAI,OAAO,MAAO,QAAO,OAAO;AAChC,KAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,UAAU,SAC9D,QAAO,OAAO,OAAO,MAAM;AAE7B,QAAO;;AAGT,MAAM,gBAAgB,UAAkB,MAAM,WAAW,uBAAuB,OAAO;AAEvF,MAAa,qBAAqB,OAAe,eAA0B;AACzE,KAAI,CAAC,cAAc,WAAW,WAAW,EAAG,QAAO,CAAC,MAAM;CAC1D,MAAM,UAAU,WAAW,IAAI,aAAa,CAAC,KAAK,IAAI;AACtD,QAAO,MAAM,MAAM,IAAI,OAAO,SAAS,IAAI,CAAC;;AAG9C,MAAa,qBAAqB,UAChC,MAAM,QAAQ,OAAO,SAAS;AAC5B,KAAI,cAAc,KAAK,CACrB,QAAO,QAAQ,KAAK,QAAQ,SAAS;AAEvC,QAAO,QAAQ;GACd,EAAE;AAEP,MAAa,gBAAgB,UAC3B,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU;AAErD,MAAa,qBAAqB,gBAAyB,cAAmB;AAC5E,KAAI,YAAY;AACd,MAAI,MAAM,QAAQ,UAAU,CAAE,QAAO;AACrC,MAAI,cAAc,QAAQ,cAAc,KAAA,EAAW,QAAO,EAAE;AAC5D,SAAO,CAAC,UAAU;;AAEpB,KAAI,MAAM,QAAQ,UAAU,CAAE,QAAO,UAAU,MAAM;AACrD,QAAO,cAAc,KAAA,IAAY,OAAO"}
@@ -71,7 +71,7 @@ function useSelectValue({ defaultValue, extraOptions, isMultiple, onChange, onSe
71
71
  } else {
72
72
  if (!isValueEmpty(normalizedNextValue) && !Object.is(previousValue, normalizedNextValue)) onSelect?.(normalizedNextValue, getOption(normalizedNextValue));
73
73
  if (value === void 0) setUncontrolledValue(normalizedNextValue);
74
- onChange?.(normalizedNextValue, isValueEmpty(normalizedNextValue) ? void 0 : getOption(normalizedNextValue));
74
+ onChange?.(isValueEmpty(normalizedNextValue) ? void 0 : normalizedNextValue, isValueEmpty(normalizedNextValue) ? void 0 : getOption(normalizedNextValue));
75
75
  }
76
76
  previousValueRef.current = normalizedNextValue;
77
77
  }, [
@@ -86,7 +86,7 @@ function useSelectValue({ defaultValue, extraOptions, isMultiple, onChange, onSe
86
86
  appendTagValues: useCallback((rawValues) => {
87
87
  const valuesToAdd = rawValues.map((val) => val.trim()).filter(Boolean);
88
88
  if (!valuesToAdd.length) return;
89
- const nextValues = [...valueArray];
89
+ const nextValues = [...Array.isArray(previousValueRef.current) ? previousValueRef.current : valueArray];
90
90
  const newOptionValues = valuesToAdd.filter((val) => !optionMap.has(val));
91
91
  if (newOptionValues.length > 0) setExtraOptions((prev) => {
92
92
  const existingValues = new Set(prev.map((item) => item.value));
@@ -115,6 +115,10 @@ function useSelectValue({ defaultValue, extraOptions, isMultiple, onChange, onSe
115
115
  normalizeValue,
116
116
  optionMap,
117
117
  resolvedOptions,
118
+ removeLastTagValue: useCallback(() => {
119
+ const currentValues = Array.isArray(previousValueRef.current) ? previousValueRef.current : valueArray;
120
+ if (currentValues.length > 0) handleValueChange(currentValues.slice(0, -1));
121
+ }, [handleValueChange, valueArray]),
118
122
  valueArray
119
123
  };
120
124
  }
@@ -132,7 +136,7 @@ function useSelectOpen({ defaultOpen, onOpenChange, open }) {
132
136
  mergedOpen
133
137
  };
134
138
  }
135
- function useSelectSearch({ appendTagValues, handleOpenChange, mergedOpen, mode, resolvedOptions, showSearch, tokenSeparators }) {
139
+ function useSelectSearch({ appendTagValues, handleOpenChange, mergedOpen, mode, removeLastTagValue, resolvedOptions, showSearch, tokenSeparators }) {
136
140
  const [searchValue, setSearchValue] = useState("");
137
141
  const shouldShowSearch = Boolean(showSearch || mode === "tags");
138
142
  useEffect(() => {
@@ -162,6 +166,11 @@ function useSelectSearch({ appendTagValues, handleOpenChange, mergedOpen, mode,
162
166
  return;
163
167
  }
164
168
  if (mode !== "tags") return;
169
+ if (event.key === "Backspace" && !searchValue) {
170
+ event.preventDefault();
171
+ removeLastTagValue();
172
+ return;
173
+ }
165
174
  const isSeparator = tokenSeparators?.includes(event.key);
166
175
  if (event.key === "Enter" || isSeparator) {
167
176
  event.preventDefault();
@@ -173,6 +182,7 @@ function useSelectSearch({ appendTagValues, handleOpenChange, mergedOpen, mode,
173
182
  appendTagValues,
174
183
  handleOpenChange,
175
184
  mode,
185
+ removeLastTagValue,
176
186
  searchValue,
177
187
  tokenSeparators
178
188
  ]);
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.mjs","names":[],"sources":["../../../src/base-ui/Select/hooks.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ChangeEvent,\n type HTMLAttributes,\n type KeyboardEvent,\n type MutableRefObject,\n type Ref,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { useAppElement } from '@/ThemeProvider';\n\nimport {\n countVirtualItems,\n getOptionSearchText,\n isGroupOption,\n isValueEmpty,\n normalizeValueFor,\n splitBySeparators,\n} from './helpers';\nimport {\n type SelectOption,\n type SelectOptions,\n type SelectProps,\n type SelectRootChangeEventDetails,\n type SelectSize,\n} from './type';\n\ninterface UseSelectValueParams {\n defaultValue: SelectProps['defaultValue'];\n extraOptions: SelectOption<any>[];\n isMultiple: boolean;\n onChange: SelectProps['onChange'];\n onSelect: SelectProps['onSelect'];\n options: SelectOptions<any> | undefined;\n setExtraOptions: React.Dispatch<React.SetStateAction<SelectOption<any>[]>>;\n value: SelectProps['value'];\n}\n\nexport function useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n}: UseSelectValueParams) {\n const [uncontrolledValue, setUncontrolledValue] = useState<any>(() => {\n if (defaultValue !== undefined) return defaultValue;\n return isMultiple ? [] : null;\n });\n\n const normalizeValue = useMemo(() => normalizeValueFor(isMultiple), [isMultiple]);\n\n const mergedValue = value !== undefined ? value : uncontrolledValue;\n const normalizedValue = useMemo(() => normalizeValue(mergedValue), [mergedValue, normalizeValue]);\n\n const valueArray = useMemo(() => {\n if (isMultiple) return normalizedValue as any[];\n return isValueEmpty(normalizedValue) ? [] : [normalizedValue];\n }, [isMultiple, normalizedValue]);\n\n const { optionMap, resolvedOptions } = useMemo(() => {\n const baseOptions = options ?? [];\n const optionValueMap = new Map<any, SelectOption<any>>();\n\n const addOption = (item: SelectOption<any>) => {\n if (!optionValueMap.has(item.value)) {\n optionValueMap.set(item.value, item);\n }\n };\n\n baseOptions.forEach((item) => {\n if (isGroupOption(item)) {\n item.options.forEach(addOption);\n } else {\n addOption(item);\n }\n });\n\n const filteredExtraOptions = extraOptions.filter((item) => !optionValueMap.has(item.value));\n filteredExtraOptions.forEach(addOption);\n const mergedOptions: SelectOptions<any> = [...baseOptions, ...filteredExtraOptions];\n\n const missingValueOptions: SelectOption<any>[] = valueArray\n .filter((val) => !optionValueMap.has(val))\n .map((val) => ({ label: String(val), value: val }));\n missingValueOptions.forEach(addOption);\n\n return {\n optionMap: optionValueMap,\n resolvedOptions: missingValueOptions.length\n ? [...mergedOptions, ...missingValueOptions]\n : mergedOptions,\n };\n }, [extraOptions, options, valueArray]);\n\n const getOption = useCallback(\n (optionValue: any): SelectOption<any> => {\n const matched = optionMap.get(optionValue);\n if (matched) return matched;\n if (optionValue && typeof optionValue === 'object' && 'label' in optionValue) {\n return { label: (optionValue as any).label, value: optionValue };\n }\n return { label: String(optionValue), value: optionValue };\n },\n [optionMap],\n );\n\n const previousValueRef = useRef<any>(normalizedValue);\n useEffect(() => {\n previousValueRef.current = normalizedValue;\n }, [normalizedValue]);\n\n const handleValueChange = useCallback(\n (nextValue: any) => {\n const normalizedNextValue = normalizeValue(nextValue);\n const previousValue = previousValueRef.current;\n\n if (isMultiple) {\n const prevValues = Array.isArray(previousValue) ? previousValue : [];\n const nextValues = Array.isArray(normalizedNextValue) ? normalizedNextValue : [];\n const addedValues = nextValues.filter(\n (val) => !prevValues.some((prev) => Object.is(prev, val)),\n );\n addedValues.forEach((val) => onSelect?.(val, getOption(val)));\n\n if (value === undefined) setUncontrolledValue(nextValues);\n onChange?.(\n nextValues,\n nextValues.map((val) => getOption(val)),\n );\n } else {\n if (!isValueEmpty(normalizedNextValue) && !Object.is(previousValue, normalizedNextValue)) {\n onSelect?.(normalizedNextValue, getOption(normalizedNextValue));\n }\n if (value === undefined) setUncontrolledValue(normalizedNextValue);\n onChange?.(\n normalizedNextValue,\n isValueEmpty(normalizedNextValue) ? undefined : getOption(normalizedNextValue),\n );\n }\n\n previousValueRef.current = normalizedNextValue;\n },\n [getOption, isMultiple, normalizeValue, onChange, onSelect, value],\n );\n\n const appendTagValues = useCallback(\n (rawValues: string[]) => {\n const valuesToAdd = rawValues.map((val) => val.trim()).filter(Boolean);\n if (!valuesToAdd.length) return;\n\n const nextValues = [...valueArray];\n const newOptionValues = valuesToAdd.filter((val) => !optionMap.has(val));\n\n if (newOptionValues.length > 0) {\n setExtraOptions((prev) => {\n const existingValues = new Set(prev.map((item) => item.value));\n const merged = [...prev];\n newOptionValues.forEach((val) => {\n if (!existingValues.has(val)) {\n merged.push({ label: val, value: val });\n }\n });\n return merged;\n });\n }\n\n valuesToAdd.forEach((val) => {\n if (!nextValues.some((item) => Object.is(item, val))) {\n nextValues.push(val);\n }\n });\n\n if (nextValues.length !== valueArray.length) {\n handleValueChange(nextValues);\n }\n },\n [handleValueChange, optionMap, setExtraOptions, valueArray],\n );\n\n return {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n optionMap,\n resolvedOptions,\n valueArray,\n };\n}\n\ninterface UseSelectOpenParams {\n defaultOpen: boolean | undefined;\n onOpenChange: SelectProps['onOpenChange'];\n open: boolean | undefined;\n}\n\nexport function useSelectOpen({ defaultOpen, onOpenChange, open }: UseSelectOpenParams) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen));\n\n useEffect(() => {\n if (open !== undefined) setUncontrolledOpen(open);\n }, [open]);\n\n const mergedOpen = open ?? uncontrolledOpen;\n\n const handleOpenChange = useCallback(\n (nextOpen: boolean, eventDetails?: SelectRootChangeEventDetails) => {\n onOpenChange?.(nextOpen, eventDetails);\n if (open === undefined) setUncontrolledOpen(nextOpen);\n },\n [onOpenChange, open],\n );\n\n return { handleOpenChange, mergedOpen };\n}\n\ninterface UseSelectSearchParams {\n appendTagValues: (values: string[]) => void;\n handleOpenChange: (nextOpen: boolean) => void;\n mergedOpen: boolean;\n mode: SelectProps['mode'];\n resolvedOptions: SelectOptions;\n showSearch: boolean | undefined;\n tokenSeparators: string[] | undefined;\n}\n\nexport function useSelectSearch({\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n}: UseSelectSearchParams) {\n const [searchValue, setSearchValue] = useState('');\n const shouldShowSearch = Boolean(showSearch || mode === 'tags');\n\n useEffect(() => {\n if (!mergedOpen) setSearchValue('');\n }, [mergedOpen]);\n\n const handleSearchChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = event.target.value;\n if (mode === 'tags') {\n const parts = splitBySeparators(nextValue, tokenSeparators);\n if (parts.length > 1) {\n const pending = parts.pop() ?? '';\n appendTagValues(parts.filter(Boolean));\n setSearchValue(pending);\n return;\n }\n }\n setSearchValue(nextValue);\n },\n [appendTagValues, mode, tokenSeparators],\n );\n\n const handleSearchKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n\n if (event.key === 'Escape') {\n handleOpenChange(false);\n return;\n }\n if (mode !== 'tags') return;\n\n const isSeparator = tokenSeparators?.includes(event.key);\n if (event.key === 'Enter' || isSeparator) {\n event.preventDefault();\n event.stopPropagation();\n appendTagValues([searchValue]);\n setSearchValue('');\n }\n },\n [appendTagValues, handleOpenChange, mode, searchValue, tokenSeparators],\n );\n\n // Stop propagation in capture phase + on keyup to block base-ui Popup-level\n // `useTypeahead` (and any ancestor typeahead) from hijacking the search\n // input's first-letter focus behavior. Do not remove.\n const stopSearchPropagation = useCallback((event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n }, []);\n\n const filteredOptions = useMemo(() => {\n if (!shouldShowSearch || !searchValue.trim()) return resolvedOptions;\n const query = searchValue.trim().toLowerCase();\n\n return resolvedOptions\n .map((item) => {\n if (isGroupOption(item)) {\n const groupItems = item.options.filter((option) =>\n getOptionSearchText(option).toLowerCase().includes(query),\n );\n if (!groupItems.length) return null;\n return { ...item, options: groupItems };\n }\n return getOptionSearchText(item).toLowerCase().includes(query) ? item : null;\n })\n .filter(Boolean) as SelectOptions;\n }, [resolvedOptions, searchValue, shouldShowSearch]);\n\n return {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n };\n}\n\ninterface UseSelectVirtualParams {\n filteredOptions: SelectOptions;\n listItemHeight: number | undefined;\n size: SelectSize;\n valueArray: any[];\n virtual: boolean | undefined;\n}\n\nexport function useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n}: UseSelectVirtualParams) {\n const listRef = useRef<HTMLDivElement | null>(null);\n const pointerScrollRef = useRef(false);\n const pointerScrollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const renderVirtualItem = useCallback((props: HTMLAttributes<HTMLDivElement>) => {\n const { ref, ...rest } = props as HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>;\n };\n\n return (\n <div\n {...rest}\n ref={(node) => {\n if (node) {\n node.scrollIntoView = (...args) => {\n if (!pointerScrollRef.current) {\n HTMLElement.prototype.scrollIntoView.call(node, ...args);\n }\n };\n }\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref && 'current' in ref) {\n (ref as MutableRefObject<HTMLDivElement | null>).current = node;\n }\n }}\n />\n );\n }, []);\n\n const markPointerScroll = useCallback(() => {\n pointerScrollRef.current = true;\n if (pointerScrollTimeoutRef.current) {\n clearTimeout(pointerScrollTimeoutRef.current);\n }\n pointerScrollTimeoutRef.current = setTimeout(() => {\n pointerScrollRef.current = false;\n }, 120);\n }, []);\n\n const handleListScroll = useCallback(() => {\n if (!virtual || !pointerScrollRef.current) return;\n const listElement = listRef.current;\n const activeElement = document.activeElement;\n if (listElement && activeElement && listElement.contains(activeElement)) {\n listElement.focus({ preventScroll: true });\n }\n }, [virtual]);\n\n useEffect(() => {\n return () => {\n if (pointerScrollTimeoutRef.current) {\n clearTimeout(pointerScrollTimeoutRef.current);\n }\n };\n }, []);\n\n const virtualListStyle = useMemo(() => {\n if (!virtual) return undefined;\n const rowCount = countVirtualItems(filteredOptions);\n const maxVisibleRows = 6;\n const estimatedRowHeight =\n listItemHeight ?? (size === 'large' ? 40 : size === 'small' ? 28 : 32);\n const visibleRows = Math.min(Math.max(rowCount, 1), maxVisibleRows);\n const estimatedHeight = visibleRows * estimatedRowHeight + 8;\n\n return {\n height: `min(${estimatedHeight}px, var(--lobe-select-available-height, var(--available-height)))`,\n };\n }, [filteredOptions, listItemHeight, size, virtual]);\n\n const keepMountedIndices = useMemo(() => {\n if (!virtual || valueArray.length === 0) return undefined;\n const selectedSet = new Set(valueArray);\n const indices: number[] = [];\n let index = 0;\n\n filteredOptions.forEach((item) => {\n if (isGroupOption(item)) {\n if (item.options.some((option) => selectedSet.has(option.value))) {\n indices.push(index);\n }\n index += 1;\n return;\n }\n if (selectedSet.has(item.value)) indices.push(index);\n index += 1;\n });\n\n return indices.length ? indices : undefined;\n }, [filteredOptions, valueArray, virtual]);\n\n return {\n handleListScroll,\n keepMountedIndices,\n listRef,\n markPointerScroll,\n renderVirtualItem,\n virtualListStyle,\n };\n}\n\nexport function usePortalContainer() {\n const appElement = useAppElement();\n // `appElement` is the ThemeProvider wrapper div, which uses `display: contents`\n // so it has no layout box. `@base-ui/react/select` fails to mount its Popup\n // into a `display: contents` container in certain hosts (editor/chat inputs\n // with focus traps). Fall back to `document.body` in that case; keep the\n // original behavior when the wrapper has a real layout (older themes, SSR\n // snapshot, etc.).\n return useMemo(() => {\n if (typeof window === 'undefined') return appElement;\n if (!(appElement instanceof HTMLElement)) return undefined;\n const display = window.getComputedStyle(appElement).display;\n return display === 'contents' ? document.body : appElement;\n }, [appElement]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"hooks.mjs","names":[],"sources":["../../../src/base-ui/Select/hooks.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ChangeEvent,\n type HTMLAttributes,\n type KeyboardEvent,\n type MutableRefObject,\n type Ref,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { useAppElement } from '@/ThemeProvider';\n\nimport {\n countVirtualItems,\n getOptionSearchText,\n isGroupOption,\n isValueEmpty,\n normalizeValueFor,\n splitBySeparators,\n} from './helpers';\nimport {\n type SelectOption,\n type SelectOptions,\n type SelectProps,\n type SelectRootChangeEventDetails,\n type SelectSize,\n} from './type';\n\ninterface UseSelectValueParams {\n defaultValue: SelectProps['defaultValue'];\n extraOptions: SelectOption<any>[];\n isMultiple: boolean;\n onChange: SelectProps['onChange'];\n onSelect: SelectProps['onSelect'];\n options: SelectOptions<any> | undefined;\n setExtraOptions: React.Dispatch<React.SetStateAction<SelectOption<any>[]>>;\n value: SelectProps['value'];\n}\n\nexport function useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n}: UseSelectValueParams) {\n const [uncontrolledValue, setUncontrolledValue] = useState<any>(() => {\n if (defaultValue !== undefined) return defaultValue;\n return isMultiple ? [] : null;\n });\n\n const normalizeValue = useMemo(() => normalizeValueFor(isMultiple), [isMultiple]);\n\n const mergedValue = value !== undefined ? value : uncontrolledValue;\n const normalizedValue = useMemo(() => normalizeValue(mergedValue), [mergedValue, normalizeValue]);\n\n const valueArray = useMemo(() => {\n if (isMultiple) return normalizedValue as any[];\n return isValueEmpty(normalizedValue) ? [] : [normalizedValue];\n }, [isMultiple, normalizedValue]);\n\n const { optionMap, resolvedOptions } = useMemo(() => {\n const baseOptions = options ?? [];\n const optionValueMap = new Map<any, SelectOption<any>>();\n\n const addOption = (item: SelectOption<any>) => {\n if (!optionValueMap.has(item.value)) {\n optionValueMap.set(item.value, item);\n }\n };\n\n baseOptions.forEach((item) => {\n if (isGroupOption(item)) {\n item.options.forEach(addOption);\n } else {\n addOption(item);\n }\n });\n\n const filteredExtraOptions = extraOptions.filter((item) => !optionValueMap.has(item.value));\n filteredExtraOptions.forEach(addOption);\n const mergedOptions: SelectOptions<any> = [...baseOptions, ...filteredExtraOptions];\n\n const missingValueOptions: SelectOption<any>[] = valueArray\n .filter((val) => !optionValueMap.has(val))\n .map((val) => ({ label: String(val), value: val }));\n missingValueOptions.forEach(addOption);\n\n return {\n optionMap: optionValueMap,\n resolvedOptions: missingValueOptions.length\n ? [...mergedOptions, ...missingValueOptions]\n : mergedOptions,\n };\n }, [extraOptions, options, valueArray]);\n\n const getOption = useCallback(\n (optionValue: any): SelectOption<any> => {\n const matched = optionMap.get(optionValue);\n if (matched) return matched;\n if (optionValue && typeof optionValue === 'object' && 'label' in optionValue) {\n return { label: (optionValue as any).label, value: optionValue };\n }\n return { label: String(optionValue), value: optionValue };\n },\n [optionMap],\n );\n\n const previousValueRef = useRef<any>(normalizedValue);\n useEffect(() => {\n previousValueRef.current = normalizedValue;\n }, [normalizedValue]);\n\n const handleValueChange = useCallback(\n (nextValue: any) => {\n const normalizedNextValue = normalizeValue(nextValue);\n const previousValue = previousValueRef.current;\n\n if (isMultiple) {\n const prevValues = Array.isArray(previousValue) ? previousValue : [];\n const nextValues = Array.isArray(normalizedNextValue) ? normalizedNextValue : [];\n const addedValues = nextValues.filter(\n (val) => !prevValues.some((prev) => Object.is(prev, val)),\n );\n addedValues.forEach((val) => onSelect?.(val, getOption(val)));\n\n if (value === undefined) setUncontrolledValue(nextValues);\n onChange?.(\n nextValues,\n nextValues.map((val) => getOption(val)),\n );\n } else {\n if (!isValueEmpty(normalizedNextValue) && !Object.is(previousValue, normalizedNextValue)) {\n onSelect?.(normalizedNextValue, getOption(normalizedNextValue));\n }\n if (value === undefined) setUncontrolledValue(normalizedNextValue);\n onChange?.(\n isValueEmpty(normalizedNextValue) ? undefined : normalizedNextValue,\n isValueEmpty(normalizedNextValue) ? undefined : getOption(normalizedNextValue),\n );\n }\n\n previousValueRef.current = normalizedNextValue;\n },\n [getOption, isMultiple, normalizeValue, onChange, onSelect, value],\n );\n\n const appendTagValues = useCallback(\n (rawValues: string[]) => {\n const valuesToAdd = rawValues.map((val) => val.trim()).filter(Boolean);\n if (!valuesToAdd.length) return;\n\n const currentValues = Array.isArray(previousValueRef.current)\n ? previousValueRef.current\n : valueArray;\n const nextValues = [...currentValues];\n const newOptionValues = valuesToAdd.filter((val) => !optionMap.has(val));\n\n if (newOptionValues.length > 0) {\n setExtraOptions((prev) => {\n const existingValues = new Set(prev.map((item) => item.value));\n const merged = [...prev];\n newOptionValues.forEach((val) => {\n if (!existingValues.has(val)) {\n merged.push({ label: val, value: val });\n }\n });\n return merged;\n });\n }\n\n valuesToAdd.forEach((val) => {\n if (!nextValues.some((item) => Object.is(item, val))) {\n nextValues.push(val);\n }\n });\n\n if (nextValues.length !== valueArray.length) {\n handleValueChange(nextValues);\n }\n },\n [handleValueChange, optionMap, setExtraOptions, valueArray],\n );\n\n const removeLastTagValue = useCallback(() => {\n const currentValues = Array.isArray(previousValueRef.current)\n ? previousValueRef.current\n : valueArray;\n if (currentValues.length > 0) handleValueChange(currentValues.slice(0, -1));\n }, [handleValueChange, valueArray]);\n\n return {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n optionMap,\n resolvedOptions,\n removeLastTagValue,\n valueArray,\n };\n}\n\ninterface UseSelectOpenParams {\n defaultOpen: boolean | undefined;\n onOpenChange: SelectProps['onOpenChange'];\n open: boolean | undefined;\n}\n\nexport function useSelectOpen({ defaultOpen, onOpenChange, open }: UseSelectOpenParams) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen));\n\n useEffect(() => {\n if (open !== undefined) setUncontrolledOpen(open);\n }, [open]);\n\n const mergedOpen = open ?? uncontrolledOpen;\n\n const handleOpenChange = useCallback(\n (nextOpen: boolean, eventDetails?: SelectRootChangeEventDetails) => {\n onOpenChange?.(nextOpen, eventDetails);\n if (open === undefined) setUncontrolledOpen(nextOpen);\n },\n [onOpenChange, open],\n );\n\n return { handleOpenChange, mergedOpen };\n}\n\ninterface UseSelectSearchParams {\n appendTagValues: (values: string[]) => void;\n handleOpenChange: (nextOpen: boolean) => void;\n mergedOpen: boolean;\n mode: SelectProps['mode'];\n removeLastTagValue: () => void;\n resolvedOptions: SelectOptions;\n showSearch: boolean | undefined;\n tokenSeparators: string[] | undefined;\n}\n\nexport function useSelectSearch({\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n removeLastTagValue,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n}: UseSelectSearchParams) {\n const [searchValue, setSearchValue] = useState('');\n const shouldShowSearch = Boolean(showSearch || mode === 'tags');\n\n useEffect(() => {\n if (!mergedOpen) setSearchValue('');\n }, [mergedOpen]);\n\n const handleSearchChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = event.target.value;\n if (mode === 'tags') {\n const parts = splitBySeparators(nextValue, tokenSeparators);\n if (parts.length > 1) {\n const pending = parts.pop() ?? '';\n appendTagValues(parts.filter(Boolean));\n setSearchValue(pending);\n return;\n }\n }\n setSearchValue(nextValue);\n },\n [appendTagValues, mode, tokenSeparators],\n );\n\n const handleSearchKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n\n if (event.key === 'Escape') {\n handleOpenChange(false);\n return;\n }\n if (mode !== 'tags') return;\n\n if (event.key === 'Backspace' && !searchValue) {\n event.preventDefault();\n removeLastTagValue();\n return;\n }\n\n const isSeparator = tokenSeparators?.includes(event.key);\n if (event.key === 'Enter' || isSeparator) {\n event.preventDefault();\n event.stopPropagation();\n appendTagValues([searchValue]);\n setSearchValue('');\n }\n },\n [appendTagValues, handleOpenChange, mode, removeLastTagValue, searchValue, tokenSeparators],\n );\n\n // Stop propagation in capture phase + on keyup to block base-ui Popup-level\n // `useTypeahead` (and any ancestor typeahead) from hijacking the search\n // input's first-letter focus behavior. Do not remove.\n const stopSearchPropagation = useCallback((event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n }, []);\n\n const filteredOptions = useMemo(() => {\n if (!shouldShowSearch || !searchValue.trim()) return resolvedOptions;\n const query = searchValue.trim().toLowerCase();\n\n return resolvedOptions\n .map((item) => {\n if (isGroupOption(item)) {\n const groupItems = item.options.filter((option) =>\n getOptionSearchText(option).toLowerCase().includes(query),\n );\n if (!groupItems.length) return null;\n return { ...item, options: groupItems };\n }\n return getOptionSearchText(item).toLowerCase().includes(query) ? item : null;\n })\n .filter(Boolean) as SelectOptions;\n }, [resolvedOptions, searchValue, shouldShowSearch]);\n\n return {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n };\n}\n\ninterface UseSelectVirtualParams {\n filteredOptions: SelectOptions;\n listItemHeight: number | undefined;\n size: SelectSize;\n valueArray: any[];\n virtual: boolean | undefined;\n}\n\nexport function useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n}: UseSelectVirtualParams) {\n const listRef = useRef<HTMLDivElement | null>(null);\n const pointerScrollRef = useRef(false);\n const pointerScrollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const renderVirtualItem = useCallback((props: HTMLAttributes<HTMLDivElement>) => {\n const { ref, ...rest } = props as HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>;\n };\n\n return (\n <div\n {...rest}\n ref={(node) => {\n if (node) {\n node.scrollIntoView = (...args) => {\n if (!pointerScrollRef.current) {\n HTMLElement.prototype.scrollIntoView.call(node, ...args);\n }\n };\n }\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref && 'current' in ref) {\n (ref as MutableRefObject<HTMLDivElement | null>).current = node;\n }\n }}\n />\n );\n }, []);\n\n const markPointerScroll = useCallback(() => {\n pointerScrollRef.current = true;\n if (pointerScrollTimeoutRef.current) {\n clearTimeout(pointerScrollTimeoutRef.current);\n }\n pointerScrollTimeoutRef.current = setTimeout(() => {\n pointerScrollRef.current = false;\n }, 120);\n }, []);\n\n const handleListScroll = useCallback(() => {\n if (!virtual || !pointerScrollRef.current) return;\n const listElement = listRef.current;\n const activeElement = document.activeElement;\n if (listElement && activeElement && listElement.contains(activeElement)) {\n listElement.focus({ preventScroll: true });\n }\n }, [virtual]);\n\n useEffect(() => {\n return () => {\n if (pointerScrollTimeoutRef.current) {\n clearTimeout(pointerScrollTimeoutRef.current);\n }\n };\n }, []);\n\n const virtualListStyle = useMemo(() => {\n if (!virtual) return undefined;\n const rowCount = countVirtualItems(filteredOptions);\n const maxVisibleRows = 6;\n const estimatedRowHeight =\n listItemHeight ?? (size === 'large' ? 40 : size === 'small' ? 28 : 32);\n const visibleRows = Math.min(Math.max(rowCount, 1), maxVisibleRows);\n const estimatedHeight = visibleRows * estimatedRowHeight + 8;\n\n return {\n height: `min(${estimatedHeight}px, var(--lobe-select-available-height, var(--available-height)))`,\n };\n }, [filteredOptions, listItemHeight, size, virtual]);\n\n const keepMountedIndices = useMemo(() => {\n if (!virtual || valueArray.length === 0) return undefined;\n const selectedSet = new Set(valueArray);\n const indices: number[] = [];\n let index = 0;\n\n filteredOptions.forEach((item) => {\n if (isGroupOption(item)) {\n if (item.options.some((option) => selectedSet.has(option.value))) {\n indices.push(index);\n }\n index += 1;\n return;\n }\n if (selectedSet.has(item.value)) indices.push(index);\n index += 1;\n });\n\n return indices.length ? indices : undefined;\n }, [filteredOptions, valueArray, virtual]);\n\n return {\n handleListScroll,\n keepMountedIndices,\n listRef,\n markPointerScroll,\n renderVirtualItem,\n virtualListStyle,\n };\n}\n\nexport function usePortalContainer() {\n const appElement = useAppElement();\n // `appElement` is the ThemeProvider wrapper div, which uses `display: contents`\n // so it has no layout box. `@base-ui/react/select` fails to mount its Popup\n // into a `display: contents` container in certain hosts (editor/chat inputs\n // with focus traps). Fall back to `document.body` in that case; keep the\n // original behavior when the wrapper has a real layout (older themes, SSR\n // snapshot, etc.).\n return useMemo(() => {\n if (typeof window === 'undefined') return appElement;\n if (!(appElement instanceof HTMLElement)) return undefined;\n const display = window.getComputedStyle(appElement).display;\n return display === 'contents' ? document.body : appElement;\n }, [appElement]);\n}\n"],"mappings":"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"}
@@ -36,7 +36,7 @@ function resolveSuffixIcon(suffixIcon, suffixIconProps, loading) {
36
36
  }
37
37
  });
38
38
  }
39
- function createTriggerValueRenderer({ getOption, isMultiple, labelRender, normalizeValue, placeholder }) {
39
+ function createTriggerValueRenderer({ getOption, isMultiple, isTags, labelRender, normalizeValue, onRemoveValue, placeholder }) {
40
40
  return function renderValue(currentValue) {
41
41
  const resolved = normalizeValue(currentValue);
42
42
  const placeholderNode = placeholder === void 0 ? null : /* @__PURE__ */ jsx("span", {
@@ -51,9 +51,26 @@ function createTriggerValueRenderer({ getOption, isMultiple, labelRender, normal
51
51
  children: values.map((val, index) => {
52
52
  const option = getOption(val);
53
53
  const content = labelRender ? labelRender(option) : option.label ?? String(val);
54
- return /* @__PURE__ */ jsx("span", {
54
+ return /* @__PURE__ */ jsxs("span", {
55
55
  className: styles$1.tag,
56
- children: content
56
+ "data-role": "lobe-select-tag",
57
+ children: [content, isTags && /* @__PURE__ */ jsx("span", {
58
+ "aria-label": `Remove ${String(val)}`,
59
+ className: styles$1.tagClose,
60
+ "data-role": "lobe-select-tag-remove",
61
+ role: "button",
62
+ tabIndex: 0,
63
+ onClick: (event) => {
64
+ event.preventDefault();
65
+ event.stopPropagation();
66
+ onRemoveValue(index);
67
+ },
68
+ onPointerDown: (event) => {
69
+ event.preventDefault();
70
+ event.stopPropagation();
71
+ },
72
+ children: /* @__PURE__ */ jsx(X, { size: 12 })
73
+ })]
57
74
  }, `${String(val)}-${index}`);
58
75
  })
59
76
  });
@@ -67,8 +84,8 @@ function createTriggerValueRenderer({ getOption, isMultiple, labelRender, normal
67
84
  });
68
85
  };
69
86
  }
70
- function SelectListSection({ classNames, isEmpty, listContent, listItemHeight, virtual, virtualState }) {
71
- const listClassName = cx(styles$1.list, classNames?.list);
87
+ function SelectListSection({ classNames, hasSearch, isEmpty, listContent, listItemHeight, virtual, virtualState }) {
88
+ const listClassName = cx(styles$1.list, hasSearch && styles$1.listWithSearch, classNames?.list);
72
89
  if (!virtual || isEmpty) return /* @__PURE__ */ jsx(Select.List, {
73
90
  className: listClassName,
74
91
  "data-virtual": virtual || void 0,
@@ -98,16 +115,18 @@ function EmptyContent({ classNames }) {
98
115
  children: "No data"
99
116
  });
100
117
  }
101
- function SelectSearchInput({ classNames, onChange, onKeyDown, placeholder, stopPropagation, value }) {
118
+ function SelectSearchInput({ autoFocus, classNames, disabled, inline, onChange, onKeyDown, placeholder, readOnly, stopPropagation, value }) {
102
119
  return /* @__PURE__ */ jsx("div", {
103
- className: cx(styles$1.search, classNames?.search),
120
+ className: cx(inline ? styles$1.tagsSearch : styles$1.search, classNames?.search),
104
121
  children: /* @__PURE__ */ jsx("input", {
122
+ autoFocus,
105
123
  className: styles$1.searchInput,
124
+ disabled,
106
125
  placeholder: typeof placeholder === "string" ? placeholder : void 0,
126
+ readOnly,
107
127
  value,
108
128
  onChange,
109
- onKeyDown,
110
- onKeyDownCapture: stopPropagation,
129
+ onKeyDownCapture: onKeyDown,
111
130
  onKeyUp: stopPropagation,
112
131
  onKeyUpCapture: stopPropagation
113
132
  })
@@ -1 +1 @@
1
- {"version":3,"file":"parts.mjs","names":["styles","BaseSelect","menuStyles"],"sources":["../../../src/base-ui/Select/parts.tsx"],"sourcesContent":["'use client';\n\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cx } from 'antd-style';\nimport { ChevronDown, Loader2, X } from 'lucide-react';\nimport {\n type ChangeEvent,\n isValidElement,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n} from 'react';\nimport { Virtualizer } from 'virtua';\n\nimport { styles as menuStyles } from '@/base-ui/DropdownMenu/sharedStyle';\nimport Icon, { type IconProps } from '@/Icon';\n\nimport { isValueEmpty } from './helpers';\nimport { type useSelectVirtual } from './hooks';\nimport { styles } from './style';\nimport { type SelectClassNames, type SelectOption, type SelectProps } from './type';\n\nexport function resolveIconNode(node: ReactNode | IconProps['icon'] | undefined | null) {\n if (node === undefined || node === null) return null;\n if (isValidElement(node) || typeof node === 'string' || typeof node === 'number') {\n return node;\n }\n return <Icon icon={node as any} size={'small'} />;\n}\n\nexport function resolveSuffixIcon(\n suffixIcon: SelectProps['suffixIcon'],\n suffixIconProps: SelectProps['suffixIconProps'],\n loading: boolean | undefined,\n) {\n if (loading) return <Icon spin icon={Loader2} size={'small'} />;\n if (suffixIcon === null) return null;\n if (\n isValidElement(suffixIcon) ||\n typeof suffixIcon === 'string' ||\n typeof suffixIcon === 'number'\n ) {\n return suffixIcon;\n }\n return (\n <Icon\n icon={(suffixIcon as any) || ChevronDown}\n size={'small'}\n {...suffixIconProps}\n style={{\n pointerEvents: 'none',\n ...suffixIconProps?.style,\n }}\n />\n );\n}\n\ninterface TriggerValueRendererParams {\n getOption: (value: any) => SelectOption<any>;\n isMultiple: boolean;\n labelRender: SelectProps['labelRender'];\n normalizeValue: (value: any) => any;\n placeholder: ReactNode;\n}\n\nexport function createTriggerValueRenderer({\n getOption,\n isMultiple,\n labelRender,\n normalizeValue,\n placeholder,\n}: TriggerValueRendererParams) {\n return function renderValue(currentValue: any): ReactNode {\n const resolved = normalizeValue(currentValue);\n const placeholderNode =\n placeholder === undefined ? null : <span className={styles.valueText}>{placeholder}</span>;\n\n if (isMultiple) {\n const values = Array.isArray(resolved) ? resolved : [];\n if (values.length === 0) return placeholderNode;\n return (\n <span className={styles.tags}>\n {values.map((val, index) => {\n const option = getOption(val);\n const content = labelRender ? labelRender(option) : (option.label ?? String(val));\n return (\n <span className={styles.tag} key={`${String(val)}-${index}`}>\n {content}\n </span>\n );\n })}\n </span>\n );\n }\n\n if (isValueEmpty(resolved)) return placeholderNode;\n const option = getOption(resolved);\n const content = labelRender ? labelRender(option) : (option.label ?? String(resolved));\n return <span className={styles.valueText}>{content}</span>;\n };\n}\n\ntype SelectVirtualReturn = ReturnType<typeof useSelectVirtual>;\n\ninterface SelectListSectionProps {\n classNames: SelectClassNames | undefined;\n isEmpty: boolean;\n listContent: ReactNode;\n listItemHeight: number | undefined;\n virtual: boolean | undefined;\n virtualState: SelectVirtualReturn;\n}\n\nexport function SelectListSection({\n classNames,\n isEmpty,\n listContent,\n listItemHeight,\n virtual,\n virtualState,\n}: SelectListSectionProps) {\n const listClassName = cx(styles.list, classNames?.list);\n\n if (!virtual || isEmpty) {\n return (\n <BaseSelect.List className={listClassName} data-virtual={virtual || undefined}>\n {listContent}\n </BaseSelect.List>\n );\n }\n\n const { handleListScroll, keepMountedIndices, listRef, markPointerScroll, virtualListStyle } =\n virtualState;\n\n return (\n <BaseSelect.List\n data-virtual\n className={listClassName}\n ref={listRef}\n style={virtualListStyle}\n tabIndex={-1}\n onPointerDown={markPointerScroll}\n onScroll={handleListScroll}\n onTouchMove={markPointerScroll}\n onWheel={markPointerScroll}\n >\n <Virtualizer itemSize={listItemHeight} keepMounted={keepMountedIndices}>\n {listContent}\n </Virtualizer>\n </BaseSelect.List>\n );\n}\n\ninterface EmptyContentProps {\n classNames: SelectClassNames | undefined;\n}\n\nexport function EmptyContent({ classNames }: EmptyContentProps) {\n return (\n <div className={cx(menuStyles.item, menuStyles.empty, styles.empty, classNames?.empty)}>\n No data\n </div>\n );\n}\n\ninterface SelectSearchInputProps {\n classNames: SelectClassNames | undefined;\n onChange: (event: ChangeEvent<HTMLInputElement>) => void;\n onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => void;\n placeholder: ReactNode;\n stopPropagation: (event: KeyboardEvent<HTMLInputElement>) => void;\n value: string;\n}\n\nexport function SelectSearchInput({\n classNames,\n onChange,\n onKeyDown,\n placeholder,\n stopPropagation,\n value,\n}: SelectSearchInputProps) {\n return (\n <div className={cx(styles.search, classNames?.search)}>\n <input\n className={styles.searchInput}\n placeholder={typeof placeholder === 'string' ? placeholder : undefined}\n value={value}\n onChange={onChange}\n onKeyDown={onKeyDown}\n onKeyDownCapture={stopPropagation}\n onKeyUp={stopPropagation}\n onKeyUpCapture={stopPropagation}\n />\n </div>\n );\n}\n\ninterface SelectTriggerSuffixProps {\n classNames: SelectClassNames | undefined;\n onClear: (event: MouseEvent) => void;\n showClear: boolean;\n suffixIconNode: ReactNode;\n}\n\nexport function SelectTriggerSuffix({\n classNames,\n onClear,\n showClear,\n suffixIconNode,\n}: SelectTriggerSuffixProps) {\n return (\n <span className={cx(styles.suffix, classNames?.suffix)}>\n {showClear && (\n <span\n className={cx(styles.clear, classNames?.clear)}\n data-role=\"lobe-select-clear\"\n onClick={onClear}\n >\n <Icon icon={X} size={'small'} />\n </span>\n )}\n {suffixIconNode !== null && suffixIconNode !== undefined && (\n <BaseSelect.Icon className={cx(styles.icon, classNames?.icon)}>\n {suffixIconNode}\n </BaseSelect.Icon>\n )}\n </span>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"parts.mjs","names":["styles","BaseSelect","menuStyles"],"sources":["../../../src/base-ui/Select/parts.tsx"],"sourcesContent":["'use client';\n\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cx } from 'antd-style';\nimport { ChevronDown, Loader2, X } from 'lucide-react';\nimport {\n type ChangeEvent,\n isValidElement,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n} from 'react';\nimport { Virtualizer } from 'virtua';\n\nimport { styles as menuStyles } from '@/base-ui/DropdownMenu/sharedStyle';\nimport Icon, { type IconProps } from '@/Icon';\n\nimport { isValueEmpty } from './helpers';\nimport { type useSelectVirtual } from './hooks';\nimport { styles } from './style';\nimport { type SelectClassNames, type SelectOption, type SelectProps } from './type';\n\nexport function resolveIconNode(node: ReactNode | IconProps['icon'] | undefined | null) {\n if (node === undefined || node === null) return null;\n if (isValidElement(node) || typeof node === 'string' || typeof node === 'number') {\n return node;\n }\n return <Icon icon={node as any} size={'small'} />;\n}\n\nexport function resolveSuffixIcon(\n suffixIcon: SelectProps['suffixIcon'],\n suffixIconProps: SelectProps['suffixIconProps'],\n loading: boolean | undefined,\n) {\n if (loading) return <Icon spin icon={Loader2} size={'small'} />;\n if (suffixIcon === null) return null;\n if (\n isValidElement(suffixIcon) ||\n typeof suffixIcon === 'string' ||\n typeof suffixIcon === 'number'\n ) {\n return suffixIcon;\n }\n return (\n <Icon\n icon={(suffixIcon as any) || ChevronDown}\n size={'small'}\n {...suffixIconProps}\n style={{\n pointerEvents: 'none',\n ...suffixIconProps?.style,\n }}\n />\n );\n}\n\ninterface TriggerValueRendererParams {\n getOption: (value: any) => SelectOption<any>;\n isMultiple: boolean;\n isTags: boolean;\n labelRender: SelectProps['labelRender'];\n normalizeValue: (value: any) => any;\n onRemoveValue: (index: number) => void;\n placeholder: ReactNode;\n}\n\nexport function createTriggerValueRenderer({\n getOption,\n isMultiple,\n isTags,\n labelRender,\n normalizeValue,\n onRemoveValue,\n placeholder,\n}: TriggerValueRendererParams) {\n return function renderValue(currentValue: any): ReactNode {\n const resolved = normalizeValue(currentValue);\n const placeholderNode =\n placeholder === undefined ? null : <span className={styles.valueText}>{placeholder}</span>;\n\n if (isMultiple) {\n const values = Array.isArray(resolved) ? resolved : [];\n if (values.length === 0) return placeholderNode;\n return (\n <span className={styles.tags}>\n {values.map((val, index) => {\n const option = getOption(val);\n const content = labelRender ? labelRender(option) : (option.label ?? String(val));\n return (\n <span\n className={styles.tag}\n data-role=\"lobe-select-tag\"\n key={`${String(val)}-${index}`}\n >\n {content}\n {isTags && (\n <span\n aria-label={`Remove ${String(val)}`}\n className={styles.tagClose}\n data-role=\"lobe-select-tag-remove\"\n role=\"button\"\n tabIndex={0}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onRemoveValue(index);\n }}\n onPointerDown={(event) => {\n event.preventDefault();\n event.stopPropagation();\n }}\n >\n <X size={12} />\n </span>\n )}\n </span>\n );\n })}\n </span>\n );\n }\n\n if (isValueEmpty(resolved)) return placeholderNode;\n const option = getOption(resolved);\n const content = labelRender ? labelRender(option) : (option.label ?? String(resolved));\n return <span className={styles.valueText}>{content}</span>;\n };\n}\n\ntype SelectVirtualReturn = ReturnType<typeof useSelectVirtual>;\n\ninterface SelectListSectionProps {\n classNames: SelectClassNames | undefined;\n hasSearch: boolean;\n isEmpty: boolean;\n listContent: ReactNode;\n listItemHeight: number | undefined;\n virtual: boolean | undefined;\n virtualState: SelectVirtualReturn;\n}\n\nexport function SelectListSection({\n classNames,\n hasSearch,\n isEmpty,\n listContent,\n listItemHeight,\n virtual,\n virtualState,\n}: SelectListSectionProps) {\n const listClassName = cx(styles.list, hasSearch && styles.listWithSearch, classNames?.list);\n\n if (!virtual || isEmpty) {\n return (\n <BaseSelect.List className={listClassName} data-virtual={virtual || undefined}>\n {listContent}\n </BaseSelect.List>\n );\n }\n\n const { handleListScroll, keepMountedIndices, listRef, markPointerScroll, virtualListStyle } =\n virtualState;\n\n return (\n <BaseSelect.List\n data-virtual\n className={listClassName}\n ref={listRef}\n style={virtualListStyle}\n tabIndex={-1}\n onPointerDown={markPointerScroll}\n onScroll={handleListScroll}\n onTouchMove={markPointerScroll}\n onWheel={markPointerScroll}\n >\n <Virtualizer itemSize={listItemHeight} keepMounted={keepMountedIndices}>\n {listContent}\n </Virtualizer>\n </BaseSelect.List>\n );\n}\n\ninterface EmptyContentProps {\n classNames: SelectClassNames | undefined;\n}\n\nexport function EmptyContent({ classNames }: EmptyContentProps) {\n return (\n <div className={cx(menuStyles.item, menuStyles.empty, styles.empty, classNames?.empty)}>\n No data\n </div>\n );\n}\n\ninterface SelectSearchInputProps {\n autoFocus?: boolean;\n classNames: SelectClassNames | undefined;\n disabled?: boolean;\n inline?: boolean;\n onChange: (event: ChangeEvent<HTMLInputElement>) => void;\n onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => void;\n placeholder: ReactNode;\n readOnly?: boolean;\n stopPropagation: (event: KeyboardEvent<HTMLInputElement>) => void;\n value: string;\n}\n\nexport function SelectSearchInput({\n autoFocus,\n classNames,\n disabled,\n inline,\n onChange,\n onKeyDown,\n placeholder,\n readOnly,\n stopPropagation,\n value,\n}: SelectSearchInputProps) {\n return (\n <div className={cx(inline ? styles.tagsSearch : styles.search, classNames?.search)}>\n <input\n autoFocus={autoFocus}\n className={styles.searchInput}\n disabled={disabled}\n placeholder={typeof placeholder === 'string' ? placeholder : undefined}\n readOnly={readOnly}\n value={value}\n onChange={onChange}\n onKeyDownCapture={onKeyDown}\n onKeyUp={stopPropagation}\n onKeyUpCapture={stopPropagation}\n />\n </div>\n );\n}\n\ninterface SelectTriggerSuffixProps {\n classNames: SelectClassNames | undefined;\n onClear: (event: MouseEvent) => void;\n showClear: boolean;\n suffixIconNode: ReactNode;\n}\n\nexport function SelectTriggerSuffix({\n classNames,\n onClear,\n showClear,\n suffixIconNode,\n}: SelectTriggerSuffixProps) {\n return (\n <span className={cx(styles.suffix, classNames?.suffix)}>\n {showClear && (\n <span\n className={cx(styles.clear, classNames?.clear)}\n data-role=\"lobe-select-clear\"\n onClick={onClear}\n >\n <Icon icon={X} size={'small'} />\n </span>\n )}\n {suffixIconNode !== null && suffixIconNode !== undefined && (\n <BaseSelect.Icon className={cx(styles.icon, classNames?.icon)}>\n {suffixIconNode}\n </BaseSelect.Icon>\n )}\n </span>\n );\n}\n"],"mappings":"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"}
@@ -74,6 +74,9 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
74
74
  min-height: 0;
75
75
  max-height: var(--lobe-select-available-height, var(--available-height));
76
76
  padding-block: 0;
77
+ `,
78
+ listWithSearch: css`
79
+ padding-block-start: 4px;
77
80
  `,
78
81
  outlined: cx(staticStylish.variantOutlined, css`
79
82
  --lobe-select-open-bg: ${cssVar.colorFillTertiary};
@@ -177,12 +180,33 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
177
180
  color: ${cssVar.colorText};
178
181
 
179
182
  background: ${cssVar.colorFillTertiary};
183
+ `,
184
+ tagClose: css`
185
+ cursor: pointer;
186
+
187
+ display: inline-flex;
188
+ align-items: center;
189
+ justify-content: center;
190
+
191
+ margin-inline-start: 4px;
192
+
193
+ color: ${cssVar.colorTextSecondary};
194
+
195
+ transition: opacity 150ms ${cssVar.motionEaseOut};
180
196
  `,
181
197
  tags: css`
182
198
  display: flex;
183
199
  flex-wrap: wrap;
184
200
  gap: 4px;
185
201
  align-items: center;
202
+ `,
203
+ tagsValue: css`
204
+ flex: none;
205
+ `,
206
+ tagsSearch: css`
207
+ display: flex;
208
+ flex: 1;
209
+ min-width: 48px;
186
210
  `,
187
211
  trigger: css`
188
212
  cursor: pointer;
@@ -1 +1 @@
1
- {"version":3,"file":"style.mjs","names":["lobeStaticStylish"],"sources":["../../../src/base-ui/Select/style.ts"],"sourcesContent":["import { createStaticStyles, cx } from 'antd-style';\nimport { cva } from 'class-variance-authority';\n\nimport { controlHeight } from '@/base-ui/controlSize';\nimport { lobeStaticStylish } from '@/styles';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n arrow: css`\n display: flex;\n width: 12px;\n height: 6px;\n\n & > svg {\n width: 100%;\n height: 100%;\n }\n `,\n borderless: cx(\n lobeStaticStylish.variantBorderless,\n css`\n --lobe-select-open-bg: ${cssVar.colorFillTertiary};\n --lobe-select-readonly-bg: color-mix(in srgb, ${cssVar.colorFillTertiary} 70%, transparent);\n --lobe-select-disabled-bg: color-mix(in srgb, ${cssVar.colorFillTertiary} 55%, transparent);\n `,\n ),\n clear: css`\n display: inline-flex;\n align-items: center;\n\n color: ${cssVar.colorTextTertiary};\n\n opacity: 0;\n\n transition: opacity 150ms ${cssVar.motionEaseOut};\n\n &:hover {\n color: ${cssVar.colorTextSecondary};\n }\n `,\n empty: css``,\n filled: cx(\n lobeStaticStylish.variantFilled,\n css`\n --lobe-select-open-bg: ${cssVar.colorFillSecondary};\n --lobe-select-readonly-bg: color-mix(in srgb, ${cssVar.colorFillTertiary} 70%, transparent);\n --lobe-select-disabled-bg: color-mix(in srgb, ${cssVar.colorFillTertiary} 55%, transparent);\n `,\n ),\n group: css``,\n groupLabel: css``,\n icon: css`\n display: inline-flex;\n align-items: center;\n transition: transform 150ms ${cssVar.motionEaseOut};\n\n &[data-popup-open] {\n transform: rotate(180deg);\n }\n `,\n item: css``,\n itemBoldSelected: css`\n &[data-selected] {\n font-weight: 600;\n }\n `,\n itemIndicator: css`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n margin-inline-start: auto;\n padding-inline-start: 8px;\n\n color: ${cssVar.colorPrimary};\n `,\n itemText: css``,\n list: css`\n overflow-y: auto;\n flex: 1;\n\n min-height: 0;\n max-height: var(--lobe-select-available-height, var(--available-height));\n padding-block: 0;\n `,\n outlined: cx(\n lobeStaticStylish.variantOutlined,\n css`\n --lobe-select-open-bg: ${cssVar.colorFillTertiary};\n --lobe-select-readonly-bg: color-mix(in srgb, ${cssVar.colorBgContainer} 75%, transparent);\n --lobe-select-disabled-bg: color-mix(in srgb, ${cssVar.colorBgContainer} 60%, transparent);\n `,\n ),\n popup: css`\n --lobe-select-available-height: min(\n var(--available-height),\n var(--lobe-select-popup-max-height, var(--available-height))\n );\n\n transform-origin: var(--transform-origin);\n\n display: flex;\n flex-direction: column;\n\n box-sizing: border-box;\n\n transition:\n opacity 150ms ${cssVar.motionEaseOut},\n transform 150ms ${cssVar.motionEaseOut};\n\n &[data-starting-style],\n &[data-ending-style] {\n transform: scaleY(0.92);\n opacity: 0;\n }\n `,\n positioner: css`\n z-index: 1100;\n outline: none;\n `,\n prefix: css`\n display: inline-flex;\n align-items: center;\n color: ${cssVar.colorTextSecondary};\n `,\n scrollArrow: css`\n cursor: default;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n height: 16px;\n\n color: ${cssVar.colorTextSecondary};\n\n background: ${cssVar.colorBgElevated};\n `,\n search: css`\n cursor: text;\n\n display: flex;\n align-items: center;\n\n min-height: 36px;\n margin-inline: -4px;\n padding-block: 8px;\n padding-inline: 12px;\n border-block-end: 1px solid ${cssVar.colorFillSecondary};\n `,\n searchInput: css`\n flex: 1;\n\n min-width: 0;\n padding-block: 0;\n padding-inline: 4px;\n border: 0;\n\n font-size: 14px;\n line-height: 20px;\n color: ${cssVar.colorText};\n\n background: transparent;\n outline: none;\n\n &::placeholder {\n color: ${cssVar.colorTextPlaceholder};\n }\n `,\n shadow: lobeStaticStylish.shadow,\n suffix: css`\n display: inline-flex;\n gap: 6px;\n align-items: center;\n color: ${cssVar.colorTextSecondary};\n `,\n tag: css`\n display: inline-flex;\n align-items: center;\n\n max-width: 100%;\n padding-block: 0;\n padding-inline: 6px;\n border-radius: ${cssVar.borderRadiusSM};\n\n font-size: 12px;\n line-height: 20px;\n color: ${cssVar.colorText};\n\n background: ${cssVar.colorFillTertiary};\n `,\n tags: css`\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n align-items: center;\n `,\n trigger: css`\n cursor: pointer;\n user-select: none;\n\n display: inline-flex;\n gap: 8px;\n align-items: center;\n\n box-sizing: border-box;\n width: 100%;\n border: 1px solid transparent;\n border-radius: ${cssVar.borderRadius};\n\n font-family: inherit;\n color: ${cssVar.colorText};\n\n background: transparent;\n outline: none;\n\n transition: all 150ms ${cssVar.motionEaseOut};\n\n &:not([data-disabled], [data-readonly])[data-popup-open],\n &:not([data-disabled], [data-readonly])[data-open],\n &:not([data-disabled], [data-readonly])[data-state='open'],\n &:not([data-disabled], [data-readonly])[aria-expanded='true'] {\n background: var(--lobe-select-open-bg, ${cssVar.colorFillTertiary});\n }\n\n &:focus-visible {\n outline: 2px solid ${cssVar.colorPrimaryBorder};\n outline-offset: 1px;\n }\n\n &:hover [data-role='lobe-select-clear'] {\n opacity: 1;\n }\n\n &[data-placeholder] [data-role='lobe-select-clear'] {\n pointer-events: none;\n opacity: 0;\n }\n\n &[data-disabled] {\n cursor: not-allowed;\n color: ${cssVar.colorTextDisabled};\n background: var(--lobe-select-disabled-bg, transparent);\n\n &:hover {\n background: var(--lobe-select-disabled-bg, transparent);\n }\n }\n\n &[data-readonly] {\n cursor: default;\n color: ${cssVar.colorTextSecondary};\n background: var(--lobe-select-readonly-bg, transparent);\n\n &:hover {\n background: var(--lobe-select-readonly-bg, transparent);\n }\n }\n\n &[data-disabled] [data-role='lobe-select-clear'] {\n pointer-events: none;\n opacity: 0;\n }\n `,\n triggerLarge: css`\n min-height: ${controlHeight.large}px;\n padding-block: 6px;\n padding-inline: 12px;\n\n font-size: 16px;\n line-height: 24px;\n `,\n triggerMiddle: css`\n min-height: ${controlHeight.middle}px;\n padding-block: 4px;\n padding-inline: 11px;\n\n font-size: 14px;\n line-height: 20px;\n `,\n triggerSmall: css`\n min-height: ${controlHeight.small}px;\n padding-block: 0;\n padding-inline: 8px;\n\n font-size: 12px;\n line-height: 18px;\n `,\n value: css`\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 4px;\n align-items: center;\n\n min-width: 0;\n\n color: inherit;\n\n &[data-placeholder] {\n color: ${cssVar.colorTextPlaceholder};\n }\n `,\n valueText: css`\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n `,\n}));\n\nexport const triggerVariants = cva(styles.trigger, {\n defaultVariants: {\n shadow: false,\n size: 'middle',\n variant: 'outlined',\n },\n variants: {\n shadow: {\n false: null,\n true: styles.shadow,\n },\n size: {\n large: styles.triggerLarge,\n middle: styles.triggerMiddle,\n small: styles.triggerSmall,\n },\n variant: {\n borderless: styles.borderless,\n filled: styles.filled,\n outlined: styles.outlined,\n },\n },\n});\n"],"mappings":";;;;;AAMA,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,OAAO,GAAG;;;;;;;;;;CAUV,YAAY,GACVA,cAAkB,mBAClB,GAAG;+BACwB,OAAO,kBAAkB;sDACF,OAAO,kBAAkB;sDACzB,OAAO,kBAAkB;MAE5E;CACD,OAAO,GAAG;;;;aAIC,OAAO,kBAAkB;;;;gCAIN,OAAO,cAAc;;;eAGtC,OAAO,mBAAmB;;;CAGvC,OAAO,GAAG;CACV,QAAQ,GACNA,cAAkB,eAClB,GAAG;+BACwB,OAAO,mBAAmB;sDACH,OAAO,kBAAkB;sDACzB,OAAO,kBAAkB;MAE5E;CACD,OAAO,GAAG;CACV,YAAY,GAAG;CACf,MAAM,GAAG;;;kCAGuB,OAAO,cAAc;;;;;;CAMrD,MAAM,GAAG;CACT,kBAAkB,GAAG;;;;;CAKrB,eAAe,GAAG;;;;;;;;aAQP,OAAO,aAAa;;CAE/B,UAAU,GAAG;CACb,MAAM,GAAG;;;;;;;;CAQT,UAAU,GACRA,cAAkB,iBAClB,GAAG;+BACwB,OAAO,kBAAkB;sDACF,OAAO,iBAAiB;sDACxB,OAAO,iBAAiB;MAE3E;CACD,OAAO,GAAG;;;;;;;;;;;;;;sBAcU,OAAO,cAAc;wBACnB,OAAO,cAAc;;;;;;;;CAQ3C,YAAY,GAAG;;;;CAIf,QAAQ,GAAG;;;aAGA,OAAO,mBAAmB;;CAErC,aAAa,GAAG;;;;;;;;;aASL,OAAO,mBAAmB;;kBAErB,OAAO,gBAAgB;;CAEvC,QAAQ,GAAG;;;;;;;;;;kCAUqB,OAAO,mBAAmB;;CAE1D,aAAa,GAAG;;;;;;;;;;aAUL,OAAO,UAAU;;;;;;eAMf,OAAO,qBAAqB;;;CAGzC,QAAQA,cAAkB;CAC1B,QAAQ,GAAG;;;;aAIA,OAAO,mBAAmB;;CAErC,KAAK,GAAG;;;;;;;qBAOW,OAAO,eAAe;;;;aAI9B,OAAO,UAAU;;kBAEZ,OAAO,kBAAkB;;CAEzC,MAAM,GAAG;;;;;;CAMT,SAAS,GAAG;;;;;;;;;;;qBAWO,OAAO,aAAa;;;aAG5B,OAAO,UAAU;;;;;4BAKF,OAAO,cAAc;;;;;;+CAMF,OAAO,kBAAkB;;;;2BAI7C,OAAO,mBAAmB;;;;;;;;;;;;;;;eAetC,OAAO,kBAAkB;;;;;;;;;;eAUzB,OAAO,mBAAmB;;;;;;;;;;;;;CAavC,cAAc,GAAG;kBACD,cAAc,MAAM;;;;;;;CAOpC,eAAe,GAAG;kBACF,cAAc,OAAO;;;;;;;CAOrC,cAAc,GAAG;kBACD,cAAc,MAAM;;;;;;;CAOpC,OAAO,GAAG;;;;;;;;;;;;eAYG,OAAO,qBAAqB;;;CAGzC,WAAW,GAAG;;;;;CAKf,EAAE;AAEH,MAAa,kBAAkB,IAAI,OAAO,SAAS;CACjD,iBAAiB;EACf,QAAQ;EACR,MAAM;EACN,SAAS;EACV;CACD,UAAU;EACR,QAAQ;GACN,OAAO;GACP,MAAM,OAAO;GACd;EACD,MAAM;GACJ,OAAO,OAAO;GACd,QAAQ,OAAO;GACf,OAAO,OAAO;GACf;EACD,SAAS;GACP,YAAY,OAAO;GACnB,QAAQ,OAAO;GACf,UAAU,OAAO;GAClB;EACF;CACF,CAAC"}
1
+ {"version":3,"file":"style.mjs","names":["lobeStaticStylish"],"sources":["../../../src/base-ui/Select/style.ts"],"sourcesContent":["import { createStaticStyles, cx } from 'antd-style';\nimport { cva } from 'class-variance-authority';\n\nimport { controlHeight } from '@/base-ui/controlSize';\nimport { lobeStaticStylish } from '@/styles';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n arrow: css`\n display: flex;\n width: 12px;\n height: 6px;\n\n & > svg {\n width: 100%;\n height: 100%;\n }\n `,\n borderless: cx(\n lobeStaticStylish.variantBorderless,\n css`\n --lobe-select-open-bg: ${cssVar.colorFillTertiary};\n --lobe-select-readonly-bg: color-mix(in srgb, ${cssVar.colorFillTertiary} 70%, transparent);\n --lobe-select-disabled-bg: color-mix(in srgb, ${cssVar.colorFillTertiary} 55%, transparent);\n `,\n ),\n clear: css`\n display: inline-flex;\n align-items: center;\n\n color: ${cssVar.colorTextTertiary};\n\n opacity: 0;\n\n transition: opacity 150ms ${cssVar.motionEaseOut};\n\n &:hover {\n color: ${cssVar.colorTextSecondary};\n }\n `,\n empty: css``,\n filled: cx(\n lobeStaticStylish.variantFilled,\n css`\n --lobe-select-open-bg: ${cssVar.colorFillSecondary};\n --lobe-select-readonly-bg: color-mix(in srgb, ${cssVar.colorFillTertiary} 70%, transparent);\n --lobe-select-disabled-bg: color-mix(in srgb, ${cssVar.colorFillTertiary} 55%, transparent);\n `,\n ),\n group: css``,\n groupLabel: css``,\n icon: css`\n display: inline-flex;\n align-items: center;\n transition: transform 150ms ${cssVar.motionEaseOut};\n\n &[data-popup-open] {\n transform: rotate(180deg);\n }\n `,\n item: css``,\n itemBoldSelected: css`\n &[data-selected] {\n font-weight: 600;\n }\n `,\n itemIndicator: css`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n margin-inline-start: auto;\n padding-inline-start: 8px;\n\n color: ${cssVar.colorPrimary};\n `,\n itemText: css``,\n list: css`\n overflow-y: auto;\n flex: 1;\n\n min-height: 0;\n max-height: var(--lobe-select-available-height, var(--available-height));\n padding-block: 0;\n `,\n listWithSearch: css`\n padding-block-start: 4px;\n `,\n outlined: cx(\n lobeStaticStylish.variantOutlined,\n css`\n --lobe-select-open-bg: ${cssVar.colorFillTertiary};\n --lobe-select-readonly-bg: color-mix(in srgb, ${cssVar.colorBgContainer} 75%, transparent);\n --lobe-select-disabled-bg: color-mix(in srgb, ${cssVar.colorBgContainer} 60%, transparent);\n `,\n ),\n popup: css`\n --lobe-select-available-height: min(\n var(--available-height),\n var(--lobe-select-popup-max-height, var(--available-height))\n );\n\n transform-origin: var(--transform-origin);\n\n display: flex;\n flex-direction: column;\n\n box-sizing: border-box;\n\n transition:\n opacity 150ms ${cssVar.motionEaseOut},\n transform 150ms ${cssVar.motionEaseOut};\n\n &[data-starting-style],\n &[data-ending-style] {\n transform: scaleY(0.92);\n opacity: 0;\n }\n `,\n positioner: css`\n z-index: 1100;\n outline: none;\n `,\n prefix: css`\n display: inline-flex;\n align-items: center;\n color: ${cssVar.colorTextSecondary};\n `,\n scrollArrow: css`\n cursor: default;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n height: 16px;\n\n color: ${cssVar.colorTextSecondary};\n\n background: ${cssVar.colorBgElevated};\n `,\n search: css`\n cursor: text;\n\n display: flex;\n align-items: center;\n\n min-height: 36px;\n margin-inline: -4px;\n padding-block: 8px;\n padding-inline: 12px;\n border-block-end: 1px solid ${cssVar.colorFillSecondary};\n `,\n searchInput: css`\n flex: 1;\n\n min-width: 0;\n padding-block: 0;\n padding-inline: 4px;\n border: 0;\n\n font-size: 14px;\n line-height: 20px;\n color: ${cssVar.colorText};\n\n background: transparent;\n outline: none;\n\n &::placeholder {\n color: ${cssVar.colorTextPlaceholder};\n }\n `,\n shadow: lobeStaticStylish.shadow,\n suffix: css`\n display: inline-flex;\n gap: 6px;\n align-items: center;\n color: ${cssVar.colorTextSecondary};\n `,\n tag: css`\n display: inline-flex;\n align-items: center;\n\n max-width: 100%;\n padding-block: 0;\n padding-inline: 6px;\n border-radius: ${cssVar.borderRadiusSM};\n\n font-size: 12px;\n line-height: 20px;\n color: ${cssVar.colorText};\n\n background: ${cssVar.colorFillTertiary};\n `,\n tagClose: css`\n cursor: pointer;\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n margin-inline-start: 4px;\n\n color: ${cssVar.colorTextSecondary};\n\n transition: opacity 150ms ${cssVar.motionEaseOut};\n `,\n tags: css`\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n align-items: center;\n `,\n tagsValue: css`\n flex: none;\n `,\n tagsSearch: css`\n display: flex;\n flex: 1;\n min-width: 48px;\n `,\n trigger: css`\n cursor: pointer;\n user-select: none;\n\n display: inline-flex;\n gap: 8px;\n align-items: center;\n\n box-sizing: border-box;\n width: 100%;\n border: 1px solid transparent;\n border-radius: ${cssVar.borderRadius};\n\n font-family: inherit;\n color: ${cssVar.colorText};\n\n background: transparent;\n outline: none;\n\n transition: all 150ms ${cssVar.motionEaseOut};\n\n &:not([data-disabled], [data-readonly])[data-popup-open],\n &:not([data-disabled], [data-readonly])[data-open],\n &:not([data-disabled], [data-readonly])[data-state='open'],\n &:not([data-disabled], [data-readonly])[aria-expanded='true'] {\n background: var(--lobe-select-open-bg, ${cssVar.colorFillTertiary});\n }\n\n &:focus-visible {\n outline: 2px solid ${cssVar.colorPrimaryBorder};\n outline-offset: 1px;\n }\n\n &:hover [data-role='lobe-select-clear'] {\n opacity: 1;\n }\n\n &[data-placeholder] [data-role='lobe-select-clear'] {\n pointer-events: none;\n opacity: 0;\n }\n\n &[data-disabled] {\n cursor: not-allowed;\n color: ${cssVar.colorTextDisabled};\n background: var(--lobe-select-disabled-bg, transparent);\n\n &:hover {\n background: var(--lobe-select-disabled-bg, transparent);\n }\n }\n\n &[data-readonly] {\n cursor: default;\n color: ${cssVar.colorTextSecondary};\n background: var(--lobe-select-readonly-bg, transparent);\n\n &:hover {\n background: var(--lobe-select-readonly-bg, transparent);\n }\n }\n\n &[data-disabled] [data-role='lobe-select-clear'] {\n pointer-events: none;\n opacity: 0;\n }\n `,\n triggerLarge: css`\n min-height: ${controlHeight.large}px;\n padding-block: 6px;\n padding-inline: 12px;\n\n font-size: 16px;\n line-height: 24px;\n `,\n triggerMiddle: css`\n min-height: ${controlHeight.middle}px;\n padding-block: 4px;\n padding-inline: 11px;\n\n font-size: 14px;\n line-height: 20px;\n `,\n triggerSmall: css`\n min-height: ${controlHeight.small}px;\n padding-block: 0;\n padding-inline: 8px;\n\n font-size: 12px;\n line-height: 18px;\n `,\n value: css`\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 4px;\n align-items: center;\n\n min-width: 0;\n\n color: inherit;\n\n &[data-placeholder] {\n color: ${cssVar.colorTextPlaceholder};\n }\n `,\n valueText: css`\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n `,\n}));\n\nexport const triggerVariants = cva(styles.trigger, {\n defaultVariants: {\n shadow: false,\n size: 'middle',\n variant: 'outlined',\n },\n variants: {\n shadow: {\n false: null,\n true: styles.shadow,\n },\n size: {\n large: styles.triggerLarge,\n middle: styles.triggerMiddle,\n small: styles.triggerSmall,\n },\n variant: {\n borderless: styles.borderless,\n filled: styles.filled,\n outlined: styles.outlined,\n },\n },\n});\n"],"mappings":";;;;;AAMA,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,OAAO,GAAG;;;;;;;;;;CAUV,YAAY,GACVA,cAAkB,mBAClB,GAAG;+BACwB,OAAO,kBAAkB;sDACF,OAAO,kBAAkB;sDACzB,OAAO,kBAAkB;MAE5E;CACD,OAAO,GAAG;;;;aAIC,OAAO,kBAAkB;;;;gCAIN,OAAO,cAAc;;;eAGtC,OAAO,mBAAmB;;;CAGvC,OAAO,GAAG;CACV,QAAQ,GACNA,cAAkB,eAClB,GAAG;+BACwB,OAAO,mBAAmB;sDACH,OAAO,kBAAkB;sDACzB,OAAO,kBAAkB;MAE5E;CACD,OAAO,GAAG;CACV,YAAY,GAAG;CACf,MAAM,GAAG;;;kCAGuB,OAAO,cAAc;;;;;;CAMrD,MAAM,GAAG;CACT,kBAAkB,GAAG;;;;;CAKrB,eAAe,GAAG;;;;;;;;aAQP,OAAO,aAAa;;CAE/B,UAAU,GAAG;CACb,MAAM,GAAG;;;;;;;;CAQT,gBAAgB,GAAG;;;CAGnB,UAAU,GACRA,cAAkB,iBAClB,GAAG;+BACwB,OAAO,kBAAkB;sDACF,OAAO,iBAAiB;sDACxB,OAAO,iBAAiB;MAE3E;CACD,OAAO,GAAG;;;;;;;;;;;;;;sBAcU,OAAO,cAAc;wBACnB,OAAO,cAAc;;;;;;;;CAQ3C,YAAY,GAAG;;;;CAIf,QAAQ,GAAG;;;aAGA,OAAO,mBAAmB;;CAErC,aAAa,GAAG;;;;;;;;;aASL,OAAO,mBAAmB;;kBAErB,OAAO,gBAAgB;;CAEvC,QAAQ,GAAG;;;;;;;;;;kCAUqB,OAAO,mBAAmB;;CAE1D,aAAa,GAAG;;;;;;;;;;aAUL,OAAO,UAAU;;;;;;eAMf,OAAO,qBAAqB;;;CAGzC,QAAQA,cAAkB;CAC1B,QAAQ,GAAG;;;;aAIA,OAAO,mBAAmB;;CAErC,KAAK,GAAG;;;;;;;qBAOW,OAAO,eAAe;;;;aAI9B,OAAO,UAAU;;kBAEZ,OAAO,kBAAkB;;CAEzC,UAAU,GAAG;;;;;;;;;aASF,OAAO,mBAAmB;;gCAEP,OAAO,cAAc;;CAEnD,MAAM,GAAG;;;;;;CAMT,WAAW,GAAG;;;CAGd,YAAY,GAAG;;;;;CAKf,SAAS,GAAG;;;;;;;;;;;qBAWO,OAAO,aAAa;;;aAG5B,OAAO,UAAU;;;;;4BAKF,OAAO,cAAc;;;;;;+CAMF,OAAO,kBAAkB;;;;2BAI7C,OAAO,mBAAmB;;;;;;;;;;;;;;;eAetC,OAAO,kBAAkB;;;;;;;;;;eAUzB,OAAO,mBAAmB;;;;;;;;;;;;;CAavC,cAAc,GAAG;kBACD,cAAc,MAAM;;;;;;;CAOpC,eAAe,GAAG;kBACF,cAAc,OAAO;;;;;;;CAOrC,cAAc,GAAG;kBACD,cAAc,MAAM;;;;;;;CAOpC,OAAO,GAAG;;;;;;;;;;;;eAYG,OAAO,qBAAqB;;;CAGzC,WAAW,GAAG;;;;;CAKf,EAAE;AAEH,MAAa,kBAAkB,IAAI,OAAO,SAAS;CACjD,iBAAiB;EACf,QAAQ;EACR,MAAM;EACN,SAAS;EACV;CACD,UAAU;EACR,QAAQ;GACN,OAAO;GACP,MAAM,OAAO;GACd;EACD,MAAM;GACJ,OAAO,OAAO;GACd,QAAQ,OAAO;GACf,OAAO,OAAO;GACf;EACD,SAAS;GACP,YAAY,OAAO;GACnB,QAAQ,OAAO;GACf,UAAU,OAAO;GAClB;EACF;CACF,CAAC"}
@@ -73,7 +73,7 @@ interface SelectProps<Value = string> {
73
73
  loading?: boolean;
74
74
  mode?: 'multiple' | 'tags';
75
75
  name?: string;
76
- onChange?: (value: Value | Value[] | null, option?: SelectOption<Value> | SelectOption<Value>[]) => void;
76
+ onChange?: (value: Value | Value[] | null | undefined, option?: SelectOption<Value> | SelectOption<Value>[]) => void;
77
77
  onOpenChange?: (open: boolean, eventDetails?: SelectRootChangeEventDetails) => void;
78
78
  onSelect?: (value: Value, option?: SelectOption<Value>) => void;
79
79
  open?: boolean;
@@ -47,6 +47,7 @@ const SwitchRoot = ({ checked, className, defaultChecked, onCheckedChange, onCli
47
47
  return /* @__PURE__ */ jsx(SwitchContext, {
48
48
  value: contextValue,
49
49
  children: /* @__PURE__ */ jsx(Switch.Root, {
50
+ nativeButton: true,
50
51
  checked: isChecked,
51
52
  defaultChecked,
52
53
  disabled,
@@ -1 +1 @@
1
- {"version":3,"file":"atoms.mjs","names":["useControlledState"],"sources":["../../../src/base-ui/Switch/atoms.tsx"],"sourcesContent":["'use client';\n\nimport { Switch } from '@base-ui/react/switch';\nimport { cx } from 'antd-style';\nimport { useReducedMotion } from 'motion/react';\nimport type { KeyboardEvent, MouseEvent } from 'react';\nimport { createContext, use, useMemo, useRef, useState } from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { useMotionComponent } from '@/MotionProvider';\n\nimport { rootVariants, styles, thumbVariants } from './style';\nimport type {\n SwitchChangeEventHandler,\n SwitchContextType,\n SwitchIconPosition,\n SwitchIconProps,\n SwitchRootProps,\n SwitchThumbProps,\n} from './type';\n\nconst SwitchContext = createContext<SwitchContextType | null>(null);\n\nexport const useSwitchContext = () => {\n const context = use(SwitchContext);\n if (!context) {\n throw new Error('useSwitchContext must be used within a SwitchRoot');\n }\n return context;\n};\n\ntype SwitchRootInternalProps = Omit<SwitchRootProps, 'onCheckedChange' | 'onClick'> & {\n onCheckedChange?: SwitchChangeEventHandler;\n onClick?: SwitchChangeEventHandler;\n};\n\nexport const SwitchRoot = ({\n checked,\n className,\n defaultChecked,\n onCheckedChange,\n onClick,\n size = 'default',\n children,\n disabled,\n readOnly,\n required,\n inputRef,\n id,\n name,\n ...rest\n}: SwitchRootInternalProps) => {\n const Motion = useMotionComponent();\n const [isPressed, setIsPressed] = useState(false);\n const lastEventRef = useRef<MouseEvent<HTMLButtonElement> | KeyboardEvent<HTMLButtonElement>>(\n null,\n );\n\n const [isChecked, setIsChecked] = useControlledState(defaultChecked ?? false, {\n defaultValue: defaultChecked,\n onChange: (value: boolean) => {\n if (lastEventRef.current) {\n onCheckedChange?.(value, lastEventRef.current);\n }\n },\n value: checked,\n });\n\n const baseClassName = rootVariants({ size });\n\n const contextValue = useMemo(\n () => ({\n isChecked: Boolean(isChecked),\n isPressed,\n setIsChecked: (value: boolean) => setIsChecked(value),\n setIsPressed,\n }),\n [isChecked, isPressed, setIsChecked],\n );\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n lastEventRef.current = event;\n onClick?.(!isChecked, event);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n lastEventRef.current = event;\n }\n (rest as any).onKeyDown?.(event);\n };\n\n return (\n <SwitchContext value={contextValue}>\n <Switch.Root\n checked={isChecked}\n defaultChecked={defaultChecked}\n disabled={disabled}\n id={id}\n inputRef={inputRef}\n name={name}\n readOnly={readOnly}\n required={required}\n render={\n <Motion.button\n {...rest}\n className={cx(baseClassName, className)}\n initial={false}\n whileTap=\"tap\"\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onTap={() => setIsPressed(false)}\n onTapCancel={() => setIsPressed(false)}\n onTapStart={() => setIsPressed(true)}\n />\n }\n onCheckedChange={setIsChecked}\n >\n {children}\n </Switch.Root>\n </SwitchContext>\n );\n};\n\nSwitchRoot.displayName = 'SwitchRoot';\n\nexport const SwitchThumb = ({\n className,\n pressedAnimation,\n size = 'default',\n transition = { damping: 24, stiffness: 360, type: 'spring' },\n children,\n ...rest\n}: SwitchThumbProps) => {\n const Motion = useMotionComponent();\n const { isPressed } = useSwitchContext();\n const shouldReduceMotion = useReducedMotion();\n const baseClassName = thumbVariants({ size });\n\n const defaultPressedAnimation = {\n width: size === 'small' ? 16 : 22,\n };\n\n const effectiveAnimate =\n !shouldReduceMotion && isPressed ? pressedAnimation || defaultPressedAnimation : undefined;\n const effectiveTransition = shouldReduceMotion ? { duration: 0 } : transition;\n\n return (\n <Switch.Thumb\n render={\n <Motion.span\n layout\n animate={effectiveAnimate}\n className={cx(baseClassName, className)}\n transition={effectiveTransition}\n {...rest}\n >\n {children}\n </Motion.span>\n }\n />\n );\n};\n\nSwitchThumb.displayName = 'SwitchThumb';\n\nconst getIconPositionClass = (position: SwitchIconPosition, size: 'default' | 'small') => {\n if (position === 'thumb') return styles.iconThumb;\n if (position === 'left') return size === 'small' ? styles.iconLeftSmall : styles.iconLeft;\n return size === 'small' ? styles.iconRightSmall : styles.iconRight;\n};\n\nexport const SwitchIcon = ({\n children,\n className,\n position,\n size = 'default',\n transition = { bounce: 0, type: 'spring' },\n ...rest\n}: SwitchIconProps) => {\n const Motion = useMotionComponent();\n const { isChecked } = useSwitchContext();\n const shouldReduceMotion = useReducedMotion();\n\n const isAnimated = useMemo(() => {\n if (position === 'right') return !isChecked;\n if (position === 'left') return isChecked;\n if (position === 'thumb') return true;\n return false;\n }, [position, isChecked]);\n\n const positionClass = getIconPositionClass(position, size);\n const effectiveTransition = shouldReduceMotion ? { duration: 0 } : transition;\n\n return (\n <Motion.span\n animate={isAnimated ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0 }}\n className={cx(styles.icon, positionClass, className)}\n transition={effectiveTransition}\n {...rest}\n >\n {children}\n </Motion.span>\n );\n};\n\nSwitchIcon.displayName = 'SwitchIcon';\n\nexport { styles as switchStyles } from './style';\n"],"mappings":"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"}
1
+ {"version":3,"file":"atoms.mjs","names":["useControlledState"],"sources":["../../../src/base-ui/Switch/atoms.tsx"],"sourcesContent":["'use client';\n\nimport { Switch } from '@base-ui/react/switch';\nimport { cx } from 'antd-style';\nimport { useReducedMotion } from 'motion/react';\nimport type { KeyboardEvent, MouseEvent } from 'react';\nimport { createContext, use, useMemo, useRef, useState } from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { useMotionComponent } from '@/MotionProvider';\n\nimport { rootVariants, styles, thumbVariants } from './style';\nimport type {\n SwitchChangeEventHandler,\n SwitchContextType,\n SwitchIconPosition,\n SwitchIconProps,\n SwitchRootProps,\n SwitchThumbProps,\n} from './type';\n\nconst SwitchContext = createContext<SwitchContextType | null>(null);\n\nexport const useSwitchContext = () => {\n const context = use(SwitchContext);\n if (!context) {\n throw new Error('useSwitchContext must be used within a SwitchRoot');\n }\n return context;\n};\n\ntype SwitchRootInternalProps = Omit<SwitchRootProps, 'onCheckedChange' | 'onClick'> & {\n onCheckedChange?: SwitchChangeEventHandler;\n onClick?: SwitchChangeEventHandler;\n};\n\nexport const SwitchRoot = ({\n checked,\n className,\n defaultChecked,\n onCheckedChange,\n onClick,\n size = 'default',\n children,\n disabled,\n readOnly,\n required,\n inputRef,\n id,\n name,\n ...rest\n}: SwitchRootInternalProps) => {\n const Motion = useMotionComponent();\n const [isPressed, setIsPressed] = useState(false);\n const lastEventRef = useRef<MouseEvent<HTMLButtonElement> | KeyboardEvent<HTMLButtonElement>>(\n null,\n );\n\n const [isChecked, setIsChecked] = useControlledState(defaultChecked ?? false, {\n defaultValue: defaultChecked,\n onChange: (value: boolean) => {\n if (lastEventRef.current) {\n onCheckedChange?.(value, lastEventRef.current);\n }\n },\n value: checked,\n });\n\n const baseClassName = rootVariants({ size });\n\n const contextValue = useMemo(\n () => ({\n isChecked: Boolean(isChecked),\n isPressed,\n setIsChecked: (value: boolean) => setIsChecked(value),\n setIsPressed,\n }),\n [isChecked, isPressed, setIsChecked],\n );\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n lastEventRef.current = event;\n onClick?.(!isChecked, event);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n lastEventRef.current = event;\n }\n (rest as any).onKeyDown?.(event);\n };\n\n return (\n <SwitchContext value={contextValue}>\n <Switch.Root\n nativeButton\n checked={isChecked}\n defaultChecked={defaultChecked}\n disabled={disabled}\n id={id}\n inputRef={inputRef}\n name={name}\n readOnly={readOnly}\n required={required}\n render={\n <Motion.button\n {...rest}\n className={cx(baseClassName, className)}\n initial={false}\n whileTap=\"tap\"\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onTap={() => setIsPressed(false)}\n onTapCancel={() => setIsPressed(false)}\n onTapStart={() => setIsPressed(true)}\n />\n }\n onCheckedChange={setIsChecked}\n >\n {children}\n </Switch.Root>\n </SwitchContext>\n );\n};\n\nSwitchRoot.displayName = 'SwitchRoot';\n\nexport const SwitchThumb = ({\n className,\n pressedAnimation,\n size = 'default',\n transition = { damping: 24, stiffness: 360, type: 'spring' },\n children,\n ...rest\n}: SwitchThumbProps) => {\n const Motion = useMotionComponent();\n const { isPressed } = useSwitchContext();\n const shouldReduceMotion = useReducedMotion();\n const baseClassName = thumbVariants({ size });\n\n const defaultPressedAnimation = {\n width: size === 'small' ? 16 : 22,\n };\n\n const effectiveAnimate =\n !shouldReduceMotion && isPressed ? pressedAnimation || defaultPressedAnimation : undefined;\n const effectiveTransition = shouldReduceMotion ? { duration: 0 } : transition;\n\n return (\n <Switch.Thumb\n render={\n <Motion.span\n layout\n animate={effectiveAnimate}\n className={cx(baseClassName, className)}\n transition={effectiveTransition}\n {...rest}\n >\n {children}\n </Motion.span>\n }\n />\n );\n};\n\nSwitchThumb.displayName = 'SwitchThumb';\n\nconst getIconPositionClass = (position: SwitchIconPosition, size: 'default' | 'small') => {\n if (position === 'thumb') return styles.iconThumb;\n if (position === 'left') return size === 'small' ? styles.iconLeftSmall : styles.iconLeft;\n return size === 'small' ? styles.iconRightSmall : styles.iconRight;\n};\n\nexport const SwitchIcon = ({\n children,\n className,\n position,\n size = 'default',\n transition = { bounce: 0, type: 'spring' },\n ...rest\n}: SwitchIconProps) => {\n const Motion = useMotionComponent();\n const { isChecked } = useSwitchContext();\n const shouldReduceMotion = useReducedMotion();\n\n const isAnimated = useMemo(() => {\n if (position === 'right') return !isChecked;\n if (position === 'left') return isChecked;\n if (position === 'thumb') return true;\n return false;\n }, [position, isChecked]);\n\n const positionClass = getIconPositionClass(position, size);\n const effectiveTransition = shouldReduceMotion ? { duration: 0 } : transition;\n\n return (\n <Motion.span\n animate={isAnimated ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0 }}\n className={cx(styles.icon, positionClass, className)}\n transition={effectiveTransition}\n {...rest}\n >\n {children}\n </Motion.span>\n );\n};\n\nSwitchIcon.displayName = 'SwitchIcon';\n\nexport { styles as switchStyles } from './style';\n"],"mappings":"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"}
@@ -6,8 +6,9 @@ import { cx } from "antd-style";
6
6
  import useMergeState from "use-merge-value";
7
7
  //#region src/base-ui/Tabs/Tabs.tsx
8
8
  const Tabs = ({ activeKey, className, classNames, defaultActiveKey, items, onChange, orientation = "horizontal", ref, size = "middle", style, styles: customStyles, variant = "rounded" }) => {
9
- const [value, setValue] = useMergeState(defaultActiveKey ?? null, {
10
- defaultValue: defaultActiveKey,
9
+ const initialActiveKey = defaultActiveKey ?? items?.find((item) => !item.disabled)?.key ?? null;
10
+ const [value, setValue] = useMergeState(initialActiveKey, {
11
+ defaultValue: initialActiveKey,
11
12
  onChange: (next) => {
12
13
  if (next != null) onChange?.(next);
13
14
  },
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.mjs","names":["useControlledState"],"sources":["../../../src/base-ui/Tabs/Tabs.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { type FC } from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { TabsIndicator, TabsList, TabsPanel, TabsRoot, TabsTab } from './atoms';\nimport { styles } from './style';\nimport type { TabsProps } from './type';\n\nconst Tabs: FC<TabsProps> = ({\n activeKey,\n className,\n classNames,\n defaultActiveKey,\n items,\n onChange,\n orientation = 'horizontal',\n ref,\n size = 'middle',\n style,\n styles: customStyles,\n variant = 'rounded',\n}) => {\n const [value, setValue] = useControlledState<string | null>(defaultActiveKey ?? null, {\n defaultValue: defaultActiveKey,\n onChange: (next) => {\n if (next != null) onChange?.(next);\n },\n value: activeKey,\n });\n\n const hasPanels = items?.some((item) => item.children != null);\n\n return (\n <TabsRoot\n className={cx(styles.root, classNames?.root, className)}\n orientation={orientation}\n ref={ref}\n size={size}\n style={{ ...style, ...customStyles?.root }}\n value={value}\n variant={variant}\n onValueChange={(next) => setValue(next ?? null)}\n >\n <TabsList className={cx(classNames?.list)} style={customStyles?.list}>\n <TabsIndicator className={cx(classNames?.indicator)} style={customStyles?.indicator} />\n {items?.map((item) => (\n <TabsTab\n className={cx(classNames?.tab)}\n disabled={item.disabled}\n key={item.key}\n style={customStyles?.tab}\n value={item.key}\n >\n {item.icon}\n {item.label}\n </TabsTab>\n ))}\n </TabsList>\n {hasPanels &&\n items?.map((item) => (\n <TabsPanel\n className={cx(classNames?.panel)}\n key={item.key}\n style={customStyles?.panel}\n value={item.key}\n >\n {item.children}\n </TabsPanel>\n ))}\n </TabsRoot>\n );\n};\n\nTabs.displayName = 'Tabs';\n\nexport default Tabs;\n"],"mappings":";;;;;;;AAUA,MAAM,QAAuB,EAC3B,WACA,WACA,YACA,kBACA,OACA,UACA,cAAc,cACd,KACA,OAAO,UACP,OACA,QAAQ,cACR,UAAU,gBACN;CACJ,MAAM,CAAC,OAAO,YAAYA,cAAkC,oBAAoB,MAAM;EACpF,cAAc;EACd,WAAW,SAAS;AAClB,OAAI,QAAQ,KAAM,YAAW,KAAK;;EAEpC,OAAO;EACR,CAAC;CAEF,MAAM,YAAY,OAAO,MAAM,SAAS,KAAK,YAAY,KAAK;AAE9D,QACE,qBAAC,UAAD;EACE,WAAW,GAAG,OAAO,MAAM,YAAY,MAAM,UAAU;EAC1C;EACR;EACC;EACN,OAAO;GAAE,GAAG;GAAO,GAAG,cAAc;GAAM;EACnC;EACE;EACT,gBAAgB,SAAS,SAAS,QAAQ,KAAK;YARjD,CAUE,qBAAC,UAAD;GAAU,WAAW,GAAG,YAAY,KAAK;GAAE,OAAO,cAAc;aAAhE,CACE,oBAAC,eAAD;IAAe,WAAW,GAAG,YAAY,UAAU;IAAE,OAAO,cAAc;IAAa,CAAA,EACtF,OAAO,KAAK,SACX,qBAAC,SAAD;IACE,WAAW,GAAG,YAAY,IAAI;IAC9B,UAAU,KAAK;IAEf,OAAO,cAAc;IACrB,OAAO,KAAK;cALd,CAOG,KAAK,MACL,KAAK,MACE;MANH,KAAK,IAMF,CACV,CACO;MACV,aACC,OAAO,KAAK,SACV,oBAAC,WAAD;GACE,WAAW,GAAG,YAAY,MAAM;GAEhC,OAAO,cAAc;GACrB,OAAO,KAAK;aAEX,KAAK;GACI,EALL,KAAK,IAKA,CACZ,CACK;;;AAIf,KAAK,cAAc"}
1
+ {"version":3,"file":"Tabs.mjs","names":["useControlledState"],"sources":["../../../src/base-ui/Tabs/Tabs.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { type FC } from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { TabsIndicator, TabsList, TabsPanel, TabsRoot, TabsTab } from './atoms';\nimport { styles } from './style';\nimport type { TabsProps } from './type';\n\nconst Tabs: FC<TabsProps> = ({\n activeKey,\n className,\n classNames,\n defaultActiveKey,\n items,\n onChange,\n orientation = 'horizontal',\n ref,\n size = 'middle',\n style,\n styles: customStyles,\n variant = 'rounded',\n}) => {\n const initialActiveKey = defaultActiveKey ?? items?.find((item) => !item.disabled)?.key ?? null;\n const [value, setValue] = useControlledState<string | null>(initialActiveKey, {\n defaultValue: initialActiveKey,\n onChange: (next) => {\n if (next != null) onChange?.(next);\n },\n value: activeKey,\n });\n\n const hasPanels = items?.some((item) => item.children != null);\n\n return (\n <TabsRoot\n className={cx(styles.root, classNames?.root, className)}\n orientation={orientation}\n ref={ref}\n size={size}\n style={{ ...style, ...customStyles?.root }}\n value={value}\n variant={variant}\n onValueChange={(next) => setValue(next ?? null)}\n >\n <TabsList className={cx(classNames?.list)} style={customStyles?.list}>\n <TabsIndicator className={cx(classNames?.indicator)} style={customStyles?.indicator} />\n {items?.map((item) => (\n <TabsTab\n className={cx(classNames?.tab)}\n disabled={item.disabled}\n key={item.key}\n style={customStyles?.tab}\n value={item.key}\n >\n {item.icon}\n {item.label}\n </TabsTab>\n ))}\n </TabsList>\n {hasPanels &&\n items?.map((item) => (\n <TabsPanel\n className={cx(classNames?.panel)}\n key={item.key}\n style={customStyles?.panel}\n value={item.key}\n >\n {item.children}\n </TabsPanel>\n ))}\n </TabsRoot>\n );\n};\n\nTabs.displayName = 'Tabs';\n\nexport default Tabs;\n"],"mappings":";;;;;;;AAUA,MAAM,QAAuB,EAC3B,WACA,WACA,YACA,kBACA,OACA,UACA,cAAc,cACd,KACA,OAAO,UACP,OACA,QAAQ,cACR,UAAU,gBACN;CACJ,MAAM,mBAAmB,oBAAoB,OAAO,MAAM,SAAS,CAAC,KAAK,SAAS,EAAE,OAAO;CAC3F,MAAM,CAAC,OAAO,YAAYA,cAAkC,kBAAkB;EAC5E,cAAc;EACd,WAAW,SAAS;AAClB,OAAI,QAAQ,KAAM,YAAW,KAAK;;EAEpC,OAAO;EACR,CAAC;CAEF,MAAM,YAAY,OAAO,MAAM,SAAS,KAAK,YAAY,KAAK;AAE9D,QACE,qBAAC,UAAD;EACE,WAAW,GAAG,OAAO,MAAM,YAAY,MAAM,UAAU;EAC1C;EACR;EACC;EACN,OAAO;GAAE,GAAG;GAAO,GAAG,cAAc;GAAM;EACnC;EACE;EACT,gBAAgB,SAAS,SAAS,QAAQ,KAAK;YARjD,CAUE,qBAAC,UAAD;GAAU,WAAW,GAAG,YAAY,KAAK;GAAE,OAAO,cAAc;aAAhE,CACE,oBAAC,eAAD;IAAe,WAAW,GAAG,YAAY,UAAU;IAAE,OAAO,cAAc;IAAa,CAAA,EACtF,OAAO,KAAK,SACX,qBAAC,SAAD;IACE,WAAW,GAAG,YAAY,IAAI;IAC9B,UAAU,KAAK;IAEf,OAAO,cAAc;IACrB,OAAO,KAAK;cALd,CAOG,KAAK,MACL,KAAK,MACE;MANH,KAAK,IAMF,CACV,CACO;MACV,aACC,OAAO,KAAK,SACV,oBAAC,WAAD;GACE,WAAW,GAAG,YAAY,MAAM;GAEhC,OAAO,cAAc;GACrB,OAAO,KAAK;aAEX,KAAK;GACI,EALL,KAAK,IAKA,CACZ,CACK;;;AAIf,KAAK,cAAc"}
@@ -12,6 +12,7 @@ const NATIVE_BUTTON_MAP = {
12
12
  Alert: false,
13
13
  Avatar: false,
14
14
  AvatarGroup: false,
15
+ BaseButton: true,
15
16
  Block: false,
16
17
  BottomGradientButton: true,
17
18
  Burger: false,
@@ -1 +1 @@
1
- {"version":3,"file":"useNativeButton.mjs","names":[],"sources":["../../src/hooks/useNativeButton.ts"],"sourcesContent":["import { isValidElement, type ReactElement, type ReactNode, useMemo } from 'react';\n\nexport interface UseNativeButtonOptions {\n /**\n * The children element that will be used as the trigger\n */\n children: ReactNode;\n /**\n * User-provided nativeButton prop\n */\n nativeButton?: boolean;\n /**\n * Additional nativeButton from trigger props (for DropdownMenu)\n */\n triggerNativeButton?: boolean;\n}\n\nexport interface UseNativeButtonResult {\n /**\n * Whether the trigger element is a native button\n */\n isNativeButtonTriggerElement: boolean;\n /**\n * The resolved nativeButton value to pass to Base UI components\n */\n resolvedNativeButton: boolean | undefined;\n}\n\n/**\n * Map of component displayNames to their nativeButton values.\n * Components that render native <button> elements should be true,\n * components that render non-button elements should be false.\n */\nconst NATIVE_BUTTON_MAP: Record<string, boolean> = {\n A: false,\n ActionIcon: false,\n ActionIconGroup: false,\n Alert: false,\n Avatar: false,\n AvatarGroup: false,\n Block: false,\n BottomGradientButton: true,\n Burger: false,\n Button: true,\n Center: false,\n Checkbox: false,\n CheckboxGroup: false,\n Collapse: false,\n ColorSwatches: false,\n CopyButton: false,\n DownloadButton: false,\n EditableText: false,\n Empty: false,\n FileTypeIcon: false,\n Flexbox: false,\n FluentEmoji: false,\n GradientButton: true,\n Highlighter: false,\n Hotkey: false,\n Icon: false,\n Image: false,\n Img: false,\n Input: false,\n InputNumber: false,\n InputPassword: false,\n List: false,\n ListItem: false,\n Select: false,\n Switch: false,\n Markdown: false,\n MaterialFileTypeIcon: false,\n Segmented: false,\n Skeleton: false,\n SkeletonAvatar: false,\n SkeletonBlock: false,\n SkeletonButton: false,\n SkeletonParagraph: false,\n SkeletonTags: false,\n SkeletonTitle: false,\n Snippet: false,\n Tag: false,\n Text: false,\n TextArea: false,\n ThemeSwitch: false,\n Video: false,\n};\n\n/**\n * Get the displayName of a React component from an element.\n * Handles function components, forwardRef, memo, etc.\n */\nfunction getComponentDisplayName(element: ReactElement): string | undefined {\n const type = element.type;\n\n if (typeof type === 'string') return undefined;\n\n if (typeof type === 'function') {\n return (type as any).displayName || type.name;\n }\n\n if (typeof type === 'object' && type !== null) {\n // Handle forwardRef, memo, etc.\n const displayName =\n (type as any).displayName ||\n (type as any).render?.displayName ||\n (type as any).render?.name ||\n (type as any).type?.displayName ||\n (type as any).type?.name;\n return displayName;\n }\n\n return undefined;\n}\n\n/**\n * Hook to resolve nativeButton prop for Base UI trigger components.\n *\n * When using `render`, Base UI expects the rendered element to be a native <button> by default.\n * If we can infer it's not, we opt out to avoid warnings (users can still override via `nativeButton`).\n */\nexport function useNativeButton({\n children,\n nativeButton,\n triggerNativeButton,\n}: UseNativeButtonOptions): UseNativeButtonResult {\n const isNativeButtonTriggerElement = useMemo(() => {\n if (!isValidElement(children)) return false;\n return typeof children.type === 'string' && children.type === 'button';\n }, [children]);\n\n const resolvedNativeButton = useMemo(() => {\n // User-provided nativeButton takes highest priority\n if (nativeButton !== undefined) return nativeButton;\n // Trigger props nativeButton (for DropdownMenu) takes second priority\n if (triggerNativeButton !== undefined) return triggerNativeButton;\n // If it's a native button element, return true\n if (isNativeButtonTriggerElement) return true;\n // If children is not a valid element, let Base UI decide\n if (!isValidElement(children)) return undefined;\n // If it's a string type but not a button (e.g., 'div'), return false\n if (typeof children.type === 'string') return false;\n\n // Check if it's a known component from the library\n const displayName = getComponentDisplayName(children);\n if (displayName && displayName in NATIVE_BUTTON_MAP) {\n return NATIVE_BUTTON_MAP[displayName];\n }\n\n // For unknown React components, default to false to avoid warnings\n // since most custom components don't render native buttons\n return false;\n }, [children, isNativeButtonTriggerElement, nativeButton, triggerNativeButton]);\n\n return {\n isNativeButtonTriggerElement,\n resolvedNativeButton,\n };\n}\n"],"mappings":";;;;;;;AAiCA,MAAM,oBAA6C;CACjD,GAAG;CACH,YAAY;CACZ,iBAAiB;CACjB,OAAO;CACP,QAAQ;CACR,aAAa;CACb,OAAO;CACP,sBAAsB;CACtB,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,eAAe;CACf,UAAU;CACV,eAAe;CACf,YAAY;CACZ,gBAAgB;CAChB,cAAc;CACd,OAAO;CACP,cAAc;CACd,SAAS;CACT,aAAa;CACb,gBAAgB;CAChB,aAAa;CACb,QAAQ;CACR,MAAM;CACN,OAAO;CACP,KAAK;CACL,OAAO;CACP,aAAa;CACb,eAAe;CACf,MAAM;CACN,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,sBAAsB;CACtB,WAAW;CACX,UAAU;CACV,gBAAgB;CAChB,eAAe;CACf,gBAAgB;CAChB,mBAAmB;CACnB,cAAc;CACd,eAAe;CACf,SAAS;CACT,KAAK;CACL,MAAM;CACN,UAAU;CACV,aAAa;CACb,OAAO;CACR;;;;;AAMD,SAAS,wBAAwB,SAA2C;CAC1E,MAAM,OAAO,QAAQ;AAErB,KAAI,OAAO,SAAS,SAAU,QAAO,KAAA;AAErC,KAAI,OAAO,SAAS,WAClB,QAAQ,KAAa,eAAe,KAAK;AAG3C,KAAI,OAAO,SAAS,YAAY,SAAS,KAQvC,QALG,KAAa,eACb,KAAa,QAAQ,eACrB,KAAa,QAAQ,QACrB,KAAa,MAAM,eACnB,KAAa,MAAM;;;;;;;;AAa1B,SAAgB,gBAAgB,EAC9B,UACA,cACA,uBACgD;CAChD,MAAM,+BAA+B,cAAc;AACjD,MAAI,CAAC,eAAe,SAAS,CAAE,QAAO;AACtC,SAAO,OAAO,SAAS,SAAS,YAAY,SAAS,SAAS;IAC7D,CAAC,SAAS,CAAC;AAyBd,QAAO;EACL;EACA,sBAzB2B,cAAc;AAEzC,OAAI,iBAAiB,KAAA,EAAW,QAAO;AAEvC,OAAI,wBAAwB,KAAA,EAAW,QAAO;AAE9C,OAAI,6BAA8B,QAAO;AAEzC,OAAI,CAAC,eAAe,SAAS,CAAE,QAAO,KAAA;AAEtC,OAAI,OAAO,SAAS,SAAS,SAAU,QAAO;GAG9C,MAAM,cAAc,wBAAwB,SAAS;AACrD,OAAI,eAAe,eAAe,kBAChC,QAAO,kBAAkB;AAK3B,UAAO;KACN;GAAC;GAAU;GAA8B;GAAc;GAAoB,CAIxD;EACrB"}
1
+ {"version":3,"file":"useNativeButton.mjs","names":[],"sources":["../../src/hooks/useNativeButton.ts"],"sourcesContent":["import { isValidElement, type ReactElement, type ReactNode, useMemo } from 'react';\n\nexport interface UseNativeButtonOptions {\n /**\n * The children element that will be used as the trigger\n */\n children: ReactNode;\n /**\n * User-provided nativeButton prop\n */\n nativeButton?: boolean;\n /**\n * Additional nativeButton from trigger props (for DropdownMenu)\n */\n triggerNativeButton?: boolean;\n}\n\nexport interface UseNativeButtonResult {\n /**\n * Whether the trigger element is a native button\n */\n isNativeButtonTriggerElement: boolean;\n /**\n * The resolved nativeButton value to pass to Base UI components\n */\n resolvedNativeButton: boolean | undefined;\n}\n\n/**\n * Map of component displayNames to their nativeButton values.\n * Components that render native <button> elements should be true,\n * components that render non-button elements should be false.\n */\nconst NATIVE_BUTTON_MAP: Record<string, boolean> = {\n A: false,\n ActionIcon: false,\n ActionIconGroup: false,\n Alert: false,\n Avatar: false,\n AvatarGroup: false,\n BaseButton: true,\n Block: false,\n BottomGradientButton: true,\n Burger: false,\n Button: true,\n Center: false,\n Checkbox: false,\n CheckboxGroup: false,\n Collapse: false,\n ColorSwatches: false,\n CopyButton: false,\n DownloadButton: false,\n EditableText: false,\n Empty: false,\n FileTypeIcon: false,\n Flexbox: false,\n FluentEmoji: false,\n GradientButton: true,\n Highlighter: false,\n Hotkey: false,\n Icon: false,\n Image: false,\n Img: false,\n Input: false,\n InputNumber: false,\n InputPassword: false,\n List: false,\n ListItem: false,\n Select: false,\n Switch: false,\n Markdown: false,\n MaterialFileTypeIcon: false,\n Segmented: false,\n Skeleton: false,\n SkeletonAvatar: false,\n SkeletonBlock: false,\n SkeletonButton: false,\n SkeletonParagraph: false,\n SkeletonTags: false,\n SkeletonTitle: false,\n Snippet: false,\n Tag: false,\n Text: false,\n TextArea: false,\n ThemeSwitch: false,\n Video: false,\n};\n\n/**\n * Get the displayName of a React component from an element.\n * Handles function components, forwardRef, memo, etc.\n */\nfunction getComponentDisplayName(element: ReactElement): string | undefined {\n const type = element.type;\n\n if (typeof type === 'string') return undefined;\n\n if (typeof type === 'function') {\n return (type as any).displayName || type.name;\n }\n\n if (typeof type === 'object' && type !== null) {\n // Handle forwardRef, memo, etc.\n const displayName =\n (type as any).displayName ||\n (type as any).render?.displayName ||\n (type as any).render?.name ||\n (type as any).type?.displayName ||\n (type as any).type?.name;\n return displayName;\n }\n\n return undefined;\n}\n\n/**\n * Hook to resolve nativeButton prop for Base UI trigger components.\n *\n * When using `render`, Base UI expects the rendered element to be a native <button> by default.\n * If we can infer it's not, we opt out to avoid warnings (users can still override via `nativeButton`).\n */\nexport function useNativeButton({\n children,\n nativeButton,\n triggerNativeButton,\n}: UseNativeButtonOptions): UseNativeButtonResult {\n const isNativeButtonTriggerElement = useMemo(() => {\n if (!isValidElement(children)) return false;\n return typeof children.type === 'string' && children.type === 'button';\n }, [children]);\n\n const resolvedNativeButton = useMemo(() => {\n // User-provided nativeButton takes highest priority\n if (nativeButton !== undefined) return nativeButton;\n // Trigger props nativeButton (for DropdownMenu) takes second priority\n if (triggerNativeButton !== undefined) return triggerNativeButton;\n // If it's a native button element, return true\n if (isNativeButtonTriggerElement) return true;\n // If children is not a valid element, let Base UI decide\n if (!isValidElement(children)) return undefined;\n // If it's a string type but not a button (e.g., 'div'), return false\n if (typeof children.type === 'string') return false;\n\n // Check if it's a known component from the library\n const displayName = getComponentDisplayName(children);\n if (displayName && displayName in NATIVE_BUTTON_MAP) {\n return NATIVE_BUTTON_MAP[displayName];\n }\n\n // For unknown React components, default to false to avoid warnings\n // since most custom components don't render native buttons\n return false;\n }, [children, isNativeButtonTriggerElement, nativeButton, triggerNativeButton]);\n\n return {\n isNativeButtonTriggerElement,\n resolvedNativeButton,\n };\n}\n"],"mappings":";;;;;;;AAiCA,MAAM,oBAA6C;CACjD,GAAG;CACH,YAAY;CACZ,iBAAiB;CACjB,OAAO;CACP,QAAQ;CACR,aAAa;CACb,YAAY;CACZ,OAAO;CACP,sBAAsB;CACtB,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,eAAe;CACf,UAAU;CACV,eAAe;CACf,YAAY;CACZ,gBAAgB;CAChB,cAAc;CACd,OAAO;CACP,cAAc;CACd,SAAS;CACT,aAAa;CACb,gBAAgB;CAChB,aAAa;CACb,QAAQ;CACR,MAAM;CACN,OAAO;CACP,KAAK;CACL,OAAO;CACP,aAAa;CACb,eAAe;CACf,MAAM;CACN,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,sBAAsB;CACtB,WAAW;CACX,UAAU;CACV,gBAAgB;CAChB,eAAe;CACf,gBAAgB;CAChB,mBAAmB;CACnB,cAAc;CACd,eAAe;CACf,SAAS;CACT,KAAK;CACL,MAAM;CACN,UAAU;CACV,aAAa;CACb,OAAO;CACR;;;;;AAMD,SAAS,wBAAwB,SAA2C;CAC1E,MAAM,OAAO,QAAQ;AAErB,KAAI,OAAO,SAAS,SAAU,QAAO,KAAA;AAErC,KAAI,OAAO,SAAS,WAClB,QAAQ,KAAa,eAAe,KAAK;AAG3C,KAAI,OAAO,SAAS,YAAY,SAAS,KAQvC,QALG,KAAa,eACb,KAAa,QAAQ,eACrB,KAAa,QAAQ,QACrB,KAAa,MAAM,eACnB,KAAa,MAAM;;;;;;;;AAa1B,SAAgB,gBAAgB,EAC9B,UACA,cACA,uBACgD;CAChD,MAAM,+BAA+B,cAAc;AACjD,MAAI,CAAC,eAAe,SAAS,CAAE,QAAO;AACtC,SAAO,OAAO,SAAS,SAAS,YAAY,SAAS,SAAS;IAC7D,CAAC,SAAS,CAAC;AAyBd,QAAO;EACL;EACA,sBAzB2B,cAAc;AAEzC,OAAI,iBAAiB,KAAA,EAAW,QAAO;AAEvC,OAAI,wBAAwB,KAAA,EAAW,QAAO;AAE9C,OAAI,6BAA8B,QAAO;AAEzC,OAAI,CAAC,eAAe,SAAS,CAAE,QAAO,KAAA;AAEtC,OAAI,OAAO,SAAS,SAAS,SAAU,QAAO;GAG9C,MAAM,cAAc,wBAAwB,SAAS;AACrD,OAAI,eAAe,eAAe,kBAChC,QAAO,kBAAkB;AAK3B,UAAO;KACN;GAAC;GAAU;GAA8B;GAAc;GAAoB,CAIxD;EACrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/ui",
3
- "version": "5.20.1",
3
+ "version": "5.20.3",
4
4
  "description": "Lobe UI is an open-source UI component library for building AIGC web apps",
5
5
  "keywords": [
6
6
  "lobehub",