@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.
- package/es/base-ui/Button/Button.mjs +17 -7
- package/es/base-ui/Button/Button.mjs.map +1 -1
- package/es/base-ui/Select/Select.mjs +35 -6
- package/es/base-ui/Select/Select.mjs.map +1 -1
- package/es/base-ui/Select/helpers.mjs +1 -1
- package/es/base-ui/Select/helpers.mjs.map +1 -1
- package/es/base-ui/Select/hooks.mjs +13 -3
- package/es/base-ui/Select/hooks.mjs.map +1 -1
- package/es/base-ui/Select/parts.mjs +28 -9
- package/es/base-ui/Select/parts.mjs.map +1 -1
- package/es/base-ui/Select/style.mjs +24 -0
- package/es/base-ui/Select/style.mjs.map +1 -1
- package/es/base-ui/Select/type.d.mts +1 -1
- package/es/base-ui/Switch/atoms.mjs +1 -0
- package/es/base-ui/Switch/atoms.mjs.map +1 -1
- package/es/base-ui/Tabs/Tabs.mjs +3 -2
- package/es/base-ui/Tabs/Tabs.mjs.map +1 -1
- package/es/hooks/useNativeButton.mjs +1 -0
- package/es/hooks/useNativeButton.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
|
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 =
|
|
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 (
|
|
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-
|
|
90
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
|
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__ */
|
|
54
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
55
55
|
className: styles$1.tag,
|
|
56
|
-
|
|
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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"}
|
package/es/base-ui/Tabs/Tabs.mjs
CHANGED
|
@@ -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
|
|
10
|
-
|
|
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>(
|
|
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"}
|
|
@@ -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"}
|