@lobehub/ui 5.43.1 → 5.45.0
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/Accordion/atoms.mjs +8 -3
- package/es/base-ui/Accordion/atoms.mjs.map +1 -1
- package/es/base-ui/Accordion/style.d.mts +1 -0
- package/es/base-ui/Accordion/style.mjs +10 -0
- package/es/base-ui/Accordion/style.mjs.map +1 -1
- package/es/base-ui/Accordion/type.d.mts +1 -1
- package/es/base-ui/ContextMenu/ContextMenuHost.mjs +5 -1
- package/es/base-ui/ContextMenu/ContextMenuHost.mjs.map +1 -1
- package/es/base-ui/ContextMenu/ContextMenuTrigger.d.mts +3 -1
- package/es/base-ui/ContextMenu/ContextMenuTrigger.mjs +7 -3
- package/es/base-ui/ContextMenu/ContextMenuTrigger.mjs.map +1 -1
- package/es/base-ui/ContextMenu/store.d.mts +3 -1
- package/es/base-ui/ContextMenu/store.mjs +6 -2
- package/es/base-ui/ContextMenu/store.mjs.map +1 -1
- package/es/base-ui/DropdownMenu/DropdownMenu.mjs +6 -2
- package/es/base-ui/DropdownMenu/DropdownMenu.mjs.map +1 -1
- package/es/base-ui/DropdownMenu/atoms.d.mts +4 -2
- package/es/base-ui/DropdownMenu/atoms.mjs +17 -5
- package/es/base-ui/DropdownMenu/atoms.mjs.map +1 -1
- package/es/base-ui/DropdownMenu/sharedStyle.mjs +26 -3
- package/es/base-ui/DropdownMenu/sharedStyle.mjs.map +1 -1
- package/es/base-ui/DropdownMenu/type.d.mts +3 -1
- package/es/base-ui/ScrollArea/atoms.mjs +4 -4
- package/es/base-ui/ScrollArea/atoms.mjs.map +1 -1
- package/es/base-ui/Select/Select.mjs +1 -3
- package/es/base-ui/Select/Select.mjs.map +1 -1
- package/es/base-ui/Select/hooks.mjs +1 -40
- package/es/base-ui/Select/hooks.mjs.map +1 -1
- package/es/base-ui/Select/parts.mjs +20 -18
- package/es/base-ui/Select/parts.mjs.map +1 -1
- package/es/base-ui/Select/renderOptions.mjs +1 -2
- package/es/base-ui/Select/renderOptions.mjs.map +1 -1
- package/es/base-ui/Select/style.mjs +2 -4
- package/es/base-ui/Select/style.mjs.map +1 -1
- package/es/base-ui/Select/type.d.mts +3 -3
- package/es/base-ui/index.d.mts +4 -2
- package/es/base-ui/index.mjs +1 -1
- package/es/base-ui/virtual/MenuVirtualList.d.mts +3 -0
- package/es/base-ui/virtual/MenuVirtualList.mjs +28 -0
- package/es/base-ui/virtual/MenuVirtualList.mjs.map +1 -0
- package/es/base-ui/virtual/VirtualScrollArea.d.mts +3 -0
- package/es/base-ui/virtual/VirtualScrollArea.mjs +82 -0
- package/es/base-ui/virtual/VirtualScrollArea.mjs.map +1 -0
- package/es/base-ui/virtual/index.d.mts +5 -0
- package/es/base-ui/virtual/type.d.mts +26 -0
- package/es/base-ui/virtual/useMenuVirtualList.d.mts +3 -0
- package/es/base-ui/virtual/useMenuVirtualList.mjs +256 -0
- package/es/base-ui/virtual/useMenuVirtualList.mjs.map +1 -0
- package/es/index.d.mts +1 -1
- package/es/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -28,12 +28,23 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
28
28
|
padding-block: 8px;
|
|
29
29
|
padding-inline: 12px;
|
|
30
30
|
border-block-start: 1px solid ${cssVar.colorBorder};
|
|
31
|
+
|
|
32
|
+
/* A menu item pinned in a slot keeps the same inset as the rows above it. */
|
|
33
|
+
&:has(> [role^='menuitem']) {
|
|
34
|
+
padding-block: 4px;
|
|
35
|
+
padding-inline: 0;
|
|
36
|
+
}
|
|
31
37
|
`,
|
|
32
38
|
header: css`
|
|
33
39
|
flex-shrink: 0;
|
|
34
40
|
padding-block: 8px;
|
|
35
41
|
padding-inline: 12px;
|
|
36
42
|
border-block-end: 1px solid ${cssVar.colorBorder};
|
|
43
|
+
|
|
44
|
+
&:has(> [role^='menuitem']) {
|
|
45
|
+
padding-block: 4px;
|
|
46
|
+
padding-inline: 0;
|
|
47
|
+
}
|
|
37
48
|
`,
|
|
38
49
|
groupLabel: css`
|
|
39
50
|
user-select: none;
|
|
@@ -164,11 +175,13 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
164
175
|
white-space: nowrap;
|
|
165
176
|
`,
|
|
166
177
|
popup: css`
|
|
178
|
+
--lobe-menu-popup-padding: 4px;
|
|
179
|
+
|
|
167
180
|
overflow-y: auto;
|
|
168
181
|
|
|
169
182
|
min-width: 220px;
|
|
170
183
|
max-height: var(--available-height);
|
|
171
|
-
padding:
|
|
184
|
+
padding: var(--lobe-menu-popup-padding);
|
|
172
185
|
border-radius: ${cssVar.borderRadius};
|
|
173
186
|
|
|
174
187
|
background: ${cssVar.colorBgElevated};
|
|
@@ -178,14 +191,24 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
178
191
|
0 4px 12px 0 rgb(0 0 0 / 8%),
|
|
179
192
|
0 1px 3px 0 rgb(0 0 0 / 6%);
|
|
180
193
|
|
|
181
|
-
&[data-has-header]
|
|
194
|
+
&[data-has-header],
|
|
195
|
+
&:has(> [data-slot='header']) {
|
|
182
196
|
padding-block-start: 0;
|
|
183
197
|
}
|
|
184
198
|
|
|
185
|
-
&[data-has-footer]
|
|
199
|
+
&[data-has-footer],
|
|
200
|
+
&:has(> [data-slot='footer']) {
|
|
186
201
|
padding-block-end: 0;
|
|
187
202
|
}
|
|
188
203
|
|
|
204
|
+
&:has(> [data-virtual]) {
|
|
205
|
+
--lobe-virtual-scroll-inset: var(--lobe-menu-popup-padding);
|
|
206
|
+
|
|
207
|
+
overflow: hidden;
|
|
208
|
+
display: flex;
|
|
209
|
+
flex-direction: column;
|
|
210
|
+
}
|
|
211
|
+
|
|
189
212
|
/* Base UI moves data-highlighted with the arrow keys, but :hover keeps painting
|
|
190
213
|
whatever the resting cursor sits on, so two items light up at once. */
|
|
191
214
|
&:has([data-highlighted]) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sharedStyle.mjs","names":[],"sources":["../../../src/base-ui/DropdownMenu/sharedStyle.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n danger: css`\n --lobe-menu-icon-color: ${cssVar.colorError};\n\n color: ${cssVar.colorError} !important;\n\n &:hover {\n background: ${cssVar.colorErrorBg} !important;\n }\n `,\n\n empty: css`\n cursor: default;\n font-style: italic;\n color: ${cssVar.colorTextTertiary};\n `,\n\n extra: css`\n margin-inline-start: auto;\n padding-inline-start: 16px;\n\n font-family: ${cssVar.fontFamilyCode};\n font-size: 12px;\n color: ${cssVar.colorTextTertiary};\n `,\n\n footer: css`\n flex-shrink: 0;\n padding-block: 8px;\n padding-inline: 12px;\n border-block-start: 1px solid ${cssVar.colorBorder};\n `,\n\n header: css`\n flex-shrink: 0;\n padding-block: 8px;\n padding-inline: 12px;\n border-block-end: 1px solid ${cssVar.colorBorder};\n `,\n\n groupLabel: css`\n user-select: none;\n\n padding-block: 8px 4px;\n padding-inline: 12px;\n\n font-size: 10px;\n font-weight: 600;\n line-height: 14px;\n color: ${cssVar.colorTextTertiary};\n text-transform: uppercase;\n letter-spacing: 0.6px;\n\n [role='group']:first-child > & {\n padding-block-start: 4px;\n }\n `,\n\n icon: css`\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n\n width: 14px;\n height: 14px;\n margin-inline-end: 12px;\n\n color: var(--lobe-menu-icon-color, ${cssVar.colorTextSecondary});\n\n & svg {\n width: 100%;\n height: 100%;\n }\n `,\n\n item: css`\n user-select: none;\n\n position: relative;\n\n overflow: hidden;\n display: flex;\n align-items: center;\n\n width: 100%;\n min-height: 32px;\n padding-block: 6px;\n padding-inline: 12px;\n border-radius: ${cssVar.borderRadiusSM};\n\n font-size: 14px;\n line-height: 20px;\n color: ${cssVar.colorText};\n\n outline: none;\n\n transition: all 150ms ${cssVar.motionEaseOut};\n\n &:hover {\n background: ${cssVar.colorFillTertiary};\n }\n\n &:active {\n background: ${cssVar.colorFillSecondary};\n }\n\n &[data-disabled] {\n cursor: not-allowed;\n color: ${cssVar.colorTextDisabled};\n opacity: 0.5;\n\n &:hover {\n background: transparent;\n }\n }\n\n &[data-highlighted]:not([data-disabled]) {\n background: ${cssVar.colorFillTertiary};\n }\n\n &[data-state='open']:not([data-disabled]),\n &[data-open]:not([data-disabled]),\n &[aria-expanded='true']:not([data-disabled]) {\n background: ${cssVar.colorFillTertiary};\n }\n `,\n\n itemContent: css`\n display: flex;\n flex: 1;\n gap: 0;\n align-items: center;\n `,\n\n itemContentAlignStart: css`\n align-items: flex-start;\n `,\n\n iconAlignStart: css`\n align-self: flex-start;\n margin-block-start: 2px;\n `,\n\n label: css`\n overflow: hidden;\n flex: 1;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n & a,\n & a:visited,\n & a:hover,\n & a:active {\n color: inherit;\n }\n `,\n\n labelGroup: css`\n overflow: hidden;\n display: flex;\n flex: 1;\n flex-direction: column;\n\n min-width: 0;\n `,\n\n desc: css`\n overflow: hidden;\n\n font-size: 12px;\n line-height: 16px;\n color: ${cssVar.colorTextTertiary};\n text-overflow: ellipsis;\n white-space: nowrap;\n `,\n\n popup: css`\n overflow-y: auto;\n\n min-width: 220px;\n max-height: var(--available-height);\n padding:
|
|
1
|
+
{"version":3,"file":"sharedStyle.mjs","names":[],"sources":["../../../src/base-ui/DropdownMenu/sharedStyle.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n danger: css`\n --lobe-menu-icon-color: ${cssVar.colorError};\n\n color: ${cssVar.colorError} !important;\n\n &:hover {\n background: ${cssVar.colorErrorBg} !important;\n }\n `,\n\n empty: css`\n cursor: default;\n font-style: italic;\n color: ${cssVar.colorTextTertiary};\n `,\n\n extra: css`\n margin-inline-start: auto;\n padding-inline-start: 16px;\n\n font-family: ${cssVar.fontFamilyCode};\n font-size: 12px;\n color: ${cssVar.colorTextTertiary};\n `,\n\n footer: css`\n flex-shrink: 0;\n padding-block: 8px;\n padding-inline: 12px;\n border-block-start: 1px solid ${cssVar.colorBorder};\n\n /* A menu item pinned in a slot keeps the same inset as the rows above it. */\n &:has(> [role^='menuitem']) {\n padding-block: 4px;\n padding-inline: 0;\n }\n `,\n\n header: css`\n flex-shrink: 0;\n padding-block: 8px;\n padding-inline: 12px;\n border-block-end: 1px solid ${cssVar.colorBorder};\n\n &:has(> [role^='menuitem']) {\n padding-block: 4px;\n padding-inline: 0;\n }\n `,\n\n groupLabel: css`\n user-select: none;\n\n padding-block: 8px 4px;\n padding-inline: 12px;\n\n font-size: 10px;\n font-weight: 600;\n line-height: 14px;\n color: ${cssVar.colorTextTertiary};\n text-transform: uppercase;\n letter-spacing: 0.6px;\n\n [role='group']:first-child > & {\n padding-block-start: 4px;\n }\n `,\n\n icon: css`\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n\n width: 14px;\n height: 14px;\n margin-inline-end: 12px;\n\n color: var(--lobe-menu-icon-color, ${cssVar.colorTextSecondary});\n\n & svg {\n width: 100%;\n height: 100%;\n }\n `,\n\n item: css`\n user-select: none;\n\n position: relative;\n\n overflow: hidden;\n display: flex;\n align-items: center;\n\n width: 100%;\n min-height: 32px;\n padding-block: 6px;\n padding-inline: 12px;\n border-radius: ${cssVar.borderRadiusSM};\n\n font-size: 14px;\n line-height: 20px;\n color: ${cssVar.colorText};\n\n outline: none;\n\n transition: all 150ms ${cssVar.motionEaseOut};\n\n &:hover {\n background: ${cssVar.colorFillTertiary};\n }\n\n &:active {\n background: ${cssVar.colorFillSecondary};\n }\n\n &[data-disabled] {\n cursor: not-allowed;\n color: ${cssVar.colorTextDisabled};\n opacity: 0.5;\n\n &:hover {\n background: transparent;\n }\n }\n\n &[data-highlighted]:not([data-disabled]) {\n background: ${cssVar.colorFillTertiary};\n }\n\n &[data-state='open']:not([data-disabled]),\n &[data-open]:not([data-disabled]),\n &[aria-expanded='true']:not([data-disabled]) {\n background: ${cssVar.colorFillTertiary};\n }\n `,\n\n itemContent: css`\n display: flex;\n flex: 1;\n gap: 0;\n align-items: center;\n `,\n\n itemContentAlignStart: css`\n align-items: flex-start;\n `,\n\n iconAlignStart: css`\n align-self: flex-start;\n margin-block-start: 2px;\n `,\n\n label: css`\n overflow: hidden;\n flex: 1;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n & a,\n & a:visited,\n & a:hover,\n & a:active {\n color: inherit;\n }\n `,\n\n labelGroup: css`\n overflow: hidden;\n display: flex;\n flex: 1;\n flex-direction: column;\n\n min-width: 0;\n `,\n\n desc: css`\n overflow: hidden;\n\n font-size: 12px;\n line-height: 16px;\n color: ${cssVar.colorTextTertiary};\n text-overflow: ellipsis;\n white-space: nowrap;\n `,\n\n popup: css`\n --lobe-menu-popup-padding: 4px;\n\n overflow-y: auto;\n\n min-width: 220px;\n max-height: var(--available-height);\n padding: var(--lobe-menu-popup-padding);\n border-radius: ${cssVar.borderRadius};\n\n background: ${cssVar.colorBgElevated};\n outline: none;\n box-shadow:\n 0 0 0 1px ${cssVar.colorBorder},\n 0 4px 12px 0 rgb(0 0 0 / 8%),\n 0 1px 3px 0 rgb(0 0 0 / 6%);\n\n &[data-has-header],\n &:has(> [data-slot='header']) {\n padding-block-start: 0;\n }\n\n &[data-has-footer],\n &:has(> [data-slot='footer']) {\n padding-block-end: 0;\n }\n\n &:has(> [data-virtual]) {\n --lobe-virtual-scroll-inset: var(--lobe-menu-popup-padding);\n\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n /* Base UI moves data-highlighted with the arrow keys, but :hover keeps painting\n whatever the resting cursor sits on, so two items light up at once. */\n &:has([data-highlighted]) {\n [role^='menuitem']:hover:not([data-highlighted]),\n [role='option']:hover:not([data-highlighted]) {\n background: transparent !important;\n }\n }\n `,\n\n popupWithSlots: css`\n overflow: hidden;\n display: flex;\n flex-direction: column;\n max-height: var(--available-height);\n `,\n\n slotViewport: css`\n overflow-y: auto;\n flex: 1;\n min-height: 0;\n `,\n\n positioner: css`\n --lobe-dropdown-animation-duration: 140ms;\n --lobe-dropdown-animation-scale-y: 0.92;\n --lobe-dropdown-animation-ease-in: ease-in;\n --lobe-dropdown-animation-ease-out: ${cssVar.motionEaseOut};\n\n z-index: 1100;\n\n & > * {\n will-change: opacity, transform;\n transform-origin: var(--transform-origin);\n animation: none;\n }\n\n &[data-open] > * {\n transform: scaleY(1);\n opacity: 1;\n transition:\n opacity var(--lobe-dropdown-animation-duration) var(--lobe-dropdown-animation-ease-out),\n transform var(--lobe-dropdown-animation-duration) var(--lobe-dropdown-animation-ease-out);\n }\n\n &[data-open] > *[data-starting-style] {\n transform: scaleY(var(--lobe-dropdown-animation-scale-y));\n opacity: 0;\n }\n\n &[data-closed] > * {\n transform: scaleY(var(--lobe-dropdown-animation-scale-y));\n opacity: 0;\n transition:\n opacity var(--lobe-dropdown-animation-duration) var(--lobe-dropdown-animation-ease-in),\n transform var(--lobe-dropdown-animation-duration) var(--lobe-dropdown-animation-ease-in);\n }\n\n &[data-hover-trigger] {\n --lobe-dropdown-animation-duration: 140ms;\n }\n\n &[data-submenu],\n &[data-nested] {\n --lobe-dropdown-animation-duration: 0ms;\n --lobe-dropdown-animation-scale-y: 1;\n\n z-index: 1199;\n }\n\n &[data-side='left'],\n &[data-side='right'] {\n --lobe-dropdown-animation-duration: 0ms;\n --lobe-dropdown-animation-scale-y: 1;\n }\n `,\n\n separator: css`\n height: 1px;\n margin-block: 4px;\n margin-inline: 0;\n background: ${cssVar.colorBorder};\n `,\n\n submenuArrow: css`\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n\n width: 16px;\n height: 16px;\n margin-inline-start: 8px;\n\n color: var(--lobe-menu-icon-color, ${cssVar.colorTextSecondary});\n\n & svg {\n width: 12px;\n height: 12px;\n }\n `,\n}));\n"],"mappings":";;AAEA,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,QAAQ,GAAG;8BACiB,OAAO,WAAW;;aAEnC,OAAO,WAAW;;;oBAGX,OAAO,aAAa;;;CAItC,OAAO,GAAG;;;aAGC,OAAO,kBAAkB;;CAGpC,OAAO,GAAG;;;;mBAIO,OAAO,eAAe;;aAE5B,OAAO,kBAAkB;;CAGpC,QAAQ,GAAG;;;;oCAIuB,OAAO,YAAY;;;;;;;;CASrD,QAAQ,GAAG;;;;kCAIqB,OAAO,YAAY;;;;;;;CAQnD,YAAY,GAAG;;;;;;;;;aASJ,OAAO,kBAAkB;;;;;;;;CASpC,MAAM,GAAG;;;;;;;;;;yCAU8B,OAAO,mBAAmB;;;;;;;CAQjE,MAAM,GAAG;;;;;;;;;;;;;qBAaU,OAAO,eAAe;;;;aAI9B,OAAO,UAAU;;;;4BAIF,OAAO,cAAc;;;oBAG7B,OAAO,kBAAkB;;;;oBAIzB,OAAO,mBAAmB;;;;;eAK/B,OAAO,kBAAkB;;;;;;;;;oBASpB,OAAO,kBAAkB;;;;;;oBAMzB,OAAO,kBAAkB;;;CAI3C,aAAa,GAAG;;;;;;CAOhB,uBAAuB,GAAG;;;CAI1B,gBAAgB,GAAG;;;;CAKnB,OAAO,GAAG;;;;;;;;;;;;;CAcV,YAAY,GAAG;;;;;;;;CASf,MAAM,GAAG;;;;;aAKE,OAAO,kBAAkB;;;;CAKpC,OAAO,GAAG;;;;;;;;qBAQS,OAAO,aAAa;;kBAEvB,OAAO,gBAAgB;;;kBAGvB,OAAO,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCnC,gBAAgB,GAAG;;;;;;CAOnB,cAAc,GAAG;;;;;CAMjB,YAAY,GAAG;;;;0CAIyB,OAAO,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkD7D,WAAW,GAAG;;;;kBAIE,OAAO,YAAY;;CAGnC,cAAc,GAAG;;;;;;;;;;yCAUsB,OAAO,mBAAmB;;;;;;;AAOnE,EAAE"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Trigger } from "../../types/trigger.mjs";
|
|
2
2
|
import "../../types/index.mjs";
|
|
3
3
|
import { Placement } from "../../utils/placement.mjs";
|
|
4
|
+
import { VirtualListProps } from "../virtual/type.mjs";
|
|
5
|
+
import "../virtual/index.mjs";
|
|
4
6
|
import { MenuCheckboxItemType } from "../../Menu/checkboxItem.mjs";
|
|
5
7
|
import { MenuSwitchItemType } from "../../Menu/switchItem.mjs";
|
|
6
8
|
import { BaseMenuItemType } from "../../Menu/baseItem.mjs";
|
|
@@ -14,7 +16,7 @@ type DropdownMenuPlacement = Placement;
|
|
|
14
16
|
type DropdownMenuCheckboxItem = MenuCheckboxItemType;
|
|
15
17
|
type DropdownMenuSwitchItem = MenuSwitchItemType;
|
|
16
18
|
type DropdownItem = BaseMenuItemType;
|
|
17
|
-
interface DropdownMenuProps<Payload = unknown> extends Omit<MenuRootProps<Payload>, 'children'> {
|
|
19
|
+
interface DropdownMenuProps<Payload = unknown> extends Omit<MenuRootProps<Payload>, 'children'>, Pick<VirtualListProps, 'virtual' | 'listItemHeight'> {
|
|
18
20
|
children: ReactNode;
|
|
19
21
|
/**
|
|
20
22
|
* 底部固定插槽,渲染于可滚动的 items 区域下方,自带分隔边框
|
|
@@ -10,10 +10,10 @@ const mergeStateClassName = (base, className) => {
|
|
|
10
10
|
return cx(base, className);
|
|
11
11
|
};
|
|
12
12
|
const ScrollAreaRoot = ({ className, ...rest }) => {
|
|
13
|
-
return /* @__PURE__ */ jsx(ScrollArea.Root, {
|
|
13
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ScrollAreaGlobalStyle, {}), /* @__PURE__ */ jsx(ScrollArea.Root, {
|
|
14
14
|
...rest,
|
|
15
15
|
className: mergeStateClassName(styles.root, className)
|
|
16
|
-
});
|
|
16
|
+
})] });
|
|
17
17
|
};
|
|
18
18
|
ScrollAreaRoot.displayName = "ScrollAreaRoot";
|
|
19
19
|
const resolveFadeClass = (scrollFade) => {
|
|
@@ -24,10 +24,10 @@ const resolveFadeClass = (scrollFade) => {
|
|
|
24
24
|
return styles.viewportFade;
|
|
25
25
|
};
|
|
26
26
|
const ScrollAreaViewport = ({ className, scrollFade = false, ...rest }) => {
|
|
27
|
-
return /* @__PURE__ */
|
|
27
|
+
return /* @__PURE__ */ jsx(ScrollArea.Viewport, {
|
|
28
28
|
...rest,
|
|
29
29
|
className: mergeStateClassName(cx(styles.viewport, resolveFadeClass(scrollFade)), className)
|
|
30
|
-
})
|
|
30
|
+
});
|
|
31
31
|
};
|
|
32
32
|
ScrollAreaViewport.displayName = "ScrollAreaViewport";
|
|
33
33
|
const ScrollAreaContent = ScrollArea.Content;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atoms.mjs","names":["BaseScrollArea"],"sources":["../../../src/base-ui/ScrollArea/atoms.tsx"],"sourcesContent":["'use client';\n\nimport { ScrollArea as BaseScrollArea } from '@base-ui/react/scroll-area';\nimport { cx } from 'antd-style';\nimport type React from 'react';\n\nimport ScrollAreaGlobalStyle from './globalStyle';\nimport { styles } from './style';\n\nconst mergeStateClassName = <TState,>(\n base: string,\n className: string | ((state: TState) => string | undefined) | undefined,\n) => {\n if (typeof className === 'function') return (state: TState) => cx(base, className(state));\n return cx(base, className);\n};\n\nexport type ScrollAreaRootProps = React.ComponentProps<typeof BaseScrollArea.Root>;\n\nexport type ScrollAreaFadeOrientation = 'vertical' | 'horizontal' | 'both';\n\nexport type ScrollAreaViewportProps = React.ComponentProps<typeof BaseScrollArea.Viewport> & {\n /**\n * Enable gradient scroll fade on the viewport edges.\n *\n * - `true` / `'vertical'`: fade top and bottom edges.\n * - `'horizontal'`: fade start and end edges.\n * - `'both'`: fade all four edges (combined via `mask-composite: intersect`).\n * - `false`: no fade.\n *\n * @default false\n */\n scrollFade?: boolean | ScrollAreaFadeOrientation;\n};\nexport type ScrollAreaContentProps = React.ComponentProps<typeof BaseScrollArea.Content>;\nexport type ScrollAreaScrollbarProps = React.ComponentProps<typeof BaseScrollArea.Scrollbar>;\nexport type ScrollAreaThumbProps = React.ComponentProps<typeof BaseScrollArea.Thumb>;\nexport type ScrollAreaCornerProps = React.ComponentProps<typeof BaseScrollArea.Corner>;\n\nexport const ScrollAreaRoot = ({ className, ...rest }: ScrollAreaRootProps) => {\n return (\n <BaseScrollArea.Root
|
|
1
|
+
{"version":3,"file":"atoms.mjs","names":["BaseScrollArea"],"sources":["../../../src/base-ui/ScrollArea/atoms.tsx"],"sourcesContent":["'use client';\n\nimport { ScrollArea as BaseScrollArea } from '@base-ui/react/scroll-area';\nimport { cx } from 'antd-style';\nimport type React from 'react';\n\nimport ScrollAreaGlobalStyle from './globalStyle';\nimport { styles } from './style';\n\nconst mergeStateClassName = <TState,>(\n base: string,\n className: string | ((state: TState) => string | undefined) | undefined,\n) => {\n if (typeof className === 'function') return (state: TState) => cx(base, className(state));\n return cx(base, className);\n};\n\nexport type ScrollAreaRootProps = React.ComponentProps<typeof BaseScrollArea.Root>;\n\nexport type ScrollAreaFadeOrientation = 'vertical' | 'horizontal' | 'both';\n\nexport type ScrollAreaViewportProps = React.ComponentProps<typeof BaseScrollArea.Viewport> & {\n /**\n * Enable gradient scroll fade on the viewport edges.\n *\n * - `true` / `'vertical'`: fade top and bottom edges.\n * - `'horizontal'`: fade start and end edges.\n * - `'both'`: fade all four edges (combined via `mask-composite: intersect`).\n * - `false`: no fade.\n *\n * @default false\n */\n scrollFade?: boolean | ScrollAreaFadeOrientation;\n};\nexport type ScrollAreaContentProps = React.ComponentProps<typeof BaseScrollArea.Content>;\nexport type ScrollAreaScrollbarProps = React.ComponentProps<typeof BaseScrollArea.Scrollbar>;\nexport type ScrollAreaThumbProps = React.ComponentProps<typeof BaseScrollArea.Thumb>;\nexport type ScrollAreaCornerProps = React.ComponentProps<typeof BaseScrollArea.Corner>;\n\nexport const ScrollAreaRoot = ({ className, ...rest }: ScrollAreaRootProps) => {\n return (\n <>\n <ScrollAreaGlobalStyle />\n <BaseScrollArea.Root\n {...rest}\n className={mergeStateClassName(styles.root, className) as any}\n />\n </>\n );\n};\n\nScrollAreaRoot.displayName = 'ScrollAreaRoot';\n\nconst resolveFadeClass = (\n scrollFade: ScrollAreaViewportProps['scrollFade'],\n): string | undefined => {\n if (!scrollFade) return undefined;\n const orientation: ScrollAreaFadeOrientation = scrollFade === true ? 'vertical' : scrollFade;\n if (orientation === 'horizontal') return styles.viewportFadeHorizontal;\n if (orientation === 'both') return styles.viewportFadeBoth;\n return styles.viewportFade;\n};\n\nexport const ScrollAreaViewport = ({\n className,\n scrollFade = false,\n ...rest\n}: ScrollAreaViewportProps) => {\n return (\n <BaseScrollArea.Viewport\n {...rest}\n className={\n mergeStateClassName(cx(styles.viewport, resolveFadeClass(scrollFade)), className) as any\n }\n />\n );\n};\n\nScrollAreaViewport.displayName = 'ScrollAreaViewport';\n\nexport const ScrollAreaContent = BaseScrollArea.Content;\n\nexport const ScrollAreaScrollbar = ({ className, ...rest }: ScrollAreaScrollbarProps) => {\n return (\n <BaseScrollArea.Scrollbar\n {...rest}\n className={mergeStateClassName(styles.scrollbar, className) as any}\n />\n );\n};\n\nScrollAreaScrollbar.displayName = 'ScrollAreaScrollbar';\n\nexport const ScrollAreaThumb = ({ className, ...rest }: ScrollAreaThumbProps) => {\n return (\n <BaseScrollArea.Thumb\n {...rest}\n className={mergeStateClassName(styles.thumb, className) as any}\n />\n );\n};\n\nScrollAreaThumb.displayName = 'ScrollAreaThumb';\n\nexport const ScrollAreaCorner = ({ className, ...rest }: ScrollAreaCornerProps) => {\n return (\n <BaseScrollArea.Corner\n {...rest}\n className={mergeStateClassName(styles.corner, className) as any}\n />\n );\n};\n\nScrollAreaCorner.displayName = 'ScrollAreaCorner';\n"],"mappings":";;;;;;;AASA,MAAM,uBACJ,MACA,cACG;CACH,IAAI,OAAO,cAAc,YAAY,QAAQ,UAAkB,GAAG,MAAM,UAAU,KAAK,CAAC;CACxF,OAAO,GAAG,MAAM,SAAS;AAC3B;AAwBA,MAAa,kBAAkB,EAAE,WAAW,GAAG,WAAgC;CAC7E,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,uBAAD,CAAwB,CAAA,GACxB,oBAACA,WAAe,MAAhB;EACE,GAAI;EACJ,WAAW,oBAAoB,OAAO,MAAM,SAAS;CACtD,CAAA,CACD,EAAA,CAAA;AAEN;AAEA,eAAe,cAAc;AAE7B,MAAM,oBACJ,eACuB;CACvB,IAAI,CAAC,YAAY,OAAO,KAAA;CACxB,MAAM,cAAyC,eAAe,OAAO,aAAa;CAClF,IAAI,gBAAgB,cAAc,OAAO,OAAO;CAChD,IAAI,gBAAgB,QAAQ,OAAO,OAAO;CAC1C,OAAO,OAAO;AAChB;AAEA,MAAa,sBAAsB,EACjC,WACA,aAAa,OACb,GAAG,WAC0B;CAC7B,OACE,oBAACA,WAAe,UAAhB;EACE,GAAI;EACJ,WACE,oBAAoB,GAAG,OAAO,UAAU,iBAAiB,UAAU,CAAC,GAAG,SAAS;CAEnF,CAAA;AAEL;AAEA,mBAAmB,cAAc;AAEjC,MAAa,oBAAoBA,WAAe;AAEhD,MAAa,uBAAuB,EAAE,WAAW,GAAG,WAAqC;CACvF,OACE,oBAACA,WAAe,WAAhB;EACE,GAAI;EACJ,WAAW,oBAAoB,OAAO,WAAW,SAAS;CAC3D,CAAA;AAEL;AAEA,oBAAoB,cAAc;AAElC,MAAa,mBAAmB,EAAE,WAAW,GAAG,WAAiC;CAC/E,OACE,oBAACA,WAAe,OAAhB;EACE,GAAI;EACJ,WAAW,oBAAoB,OAAO,OAAO,SAAS;CACvD,CAAA;AAEL;AAEA,gBAAgB,cAAc;AAE9B,MAAa,oBAAoB,EAAE,WAAW,GAAG,WAAkC;CACjF,OACE,oBAACA,WAAe,QAAhB;EACE,GAAI;EACJ,WAAW,oBAAoB,OAAO,QAAQ,SAAS;CACxD,CAAA;AAEL;AAEA,iBAAiB,cAAc"}
|
|
@@ -128,9 +128,7 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
|
|
|
128
128
|
items: filteredOptions,
|
|
129
129
|
itemTextClassName,
|
|
130
130
|
listItemHeight,
|
|
131
|
-
optionRender
|
|
132
|
-
renderVirtualItem: virtualState.renderVirtualItem,
|
|
133
|
-
virtual
|
|
131
|
+
optionRender
|
|
134
132
|
});
|
|
135
133
|
return /* @__PURE__ */ jsxs(Select.Root, {
|
|
136
134
|
disabled,
|
|
@@ -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 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 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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"}
|
|
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 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 })\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":";;;;;;;;;;;;;AA+BA,MAAMA,WAAS,MACZ,EACC,YACA,WACA,WACA,YACA,aACA,cACA,UACA,IACA,aACA,aAAa,KACb,gBACA,SACA,MACA,MACA,UACA,cACA,UACA,MACA,cACA,SACA,aACA,gBACA,uBACA,QACA,UACA,UACA,kBAAkB,WAClB,2BAA2B,SAC3B,QACA,YACA,OAAO,UACP,OACA,YACA,iBACA,iBACA,OACA,SACA,cACI;CACJ,MAAM,EAAE,eAAe,aAAa;CACpC,MAAM,kBAAkB,YAAY,aAAa,WAAW;CAC5D,MAAM,SAAS,SAAS;CACxB,MAAM,aAAa,SAAS,cAAc,SAAS;CACnD,MAAM,gBAAgB,oBAAoB;CAE1C,MAAM,CAAC,cAAc,mBAAmB,SAA8B,CAAC,CAAC;CAExE,gBAAgB;EACd,IAAI,SAAS,UAAU,aAAa,SAAS,GAC3C,gBAAgB,CAAC,CAAC;CAEtB,GAAG,CAAC,MAAM,aAAa,MAAM,CAAC;CAE9B,MAAM,EACJ,iBACA,WACA,mBACA,iBACA,gBACA,oBACA,iBACA,eACE,eAAe;EACjB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,kBAAkB,eAAe,cAAc;EAAE;EAAa;EAAc;CAAK,CAAC;CAE1F,MAAM,wBAAwB,aAC3B,cAAmB;EAClB,IAAI,EAAE,UAAU,CAAC,aAAa,kBAAkB,SAAS;CAC3D,GACA;EAAC;EAAmB;EAAQ;CAAU,CACxC;CAEA,MAAM,kBAAkB,aACrB,UACC,kBAAkB,WAAW,QAAQ,GAAG,cAAc,cAAc,KAAK,CAAC,GAC5E,CAAC,mBAAmB,UAAU,CAChC;CAEA,MAAM,EACJ,iBACA,oBACA,qBACA,aACA,kBACA,0BACE,gBAAgB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,eAAe,iBAAiB;EACpC;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,kBAAkB,mBAAmB;CAE3C,MAAM,cAAc,cAEhB,2BAA2B;EACzB;EACA;EACA;EACA;EACA;EACA,eAAe;EACf,aAAa,SAAS,KAAA,IAAY;CACpC,CAAC,GACH;EAAC;EAAW;EAAiB;EAAY;EAAQ;EAAa;EAAgB;CAAW,CAC3F;CAEA,MAAM,WAAW,aAAa,WAAW,SAAS,IAAI,CAAC,aAAa,eAAe;CACnF,MAAM,YAAY,QAAQ,cAAc,YAAY,CAAC,YAAY,CAAC,QAAQ;CAE1E,MAAM,cAAc,aACjB,UAAsB;EACrB,MAAM,eAAe;EACrB,MAAM,gBAAgB;EACtB,kBAAkB,aAAa,CAAC,IAAI,IAAI;CAC1C,GACA,CAAC,mBAAmB,UAAU,CAChC;CAEA,MAAM,aAAa,cAAc,gBAAgB,MAAM,GAAG,CAAC,MAAM,CAAC;CAClE,MAAM,iBAAiB,cACf,kBAAkB,YAAY,iBAAiB,OAAO,GAC5D;EAAC;EAAS;EAAY;CAAe,CACvC;CAEA,MAAM,aAAa,cAAc;EAC/B,MAAM,YAAY,gBAAgB,SAAS,GAAG,WAAW;EACzD,MAAM,YAAiC;GACrC,UAAU;GACV,UAAU;IACT,mCAA0C;EAC7C;EAEA,IAAI,0BAA0B,KAAA,KAAa,0BAA0B,MACnE,OAAO;EAET,IAAI,OAAO,0BAA0B,UACnC,OAAO;GACL,GAAG;GACH,UAAU;GACV,OAAO;EACT;EAEF,OAAO;GAAE,GAAG;GAAW,UAAU;EAAc;CACjD,GAAG;EAAC;EAAe;EAAY;CAAqB,CAAC;CAErD,MAAM,mBAAmB,GACvB,gBAAgB;EAAE;EAAQ;EAAM,SAAS;CAAgB,CAAC,GAC1D,WACA,YAAY,MACZ,YAAY,OACd;CAEA,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,oBAAoB,GACxB,eAAeC,OAAW,cAAcA,OAAW,OACnDC,SAAO,UACP,YAAY,QACd;CAEA,MAAM,UAAU,gBAAgB,WAAW;CAC3C,MAAM,cAAc,UAClB,oBAAC,cAAD,EAA0B,WAAa,CAAA,IAEvC,cAAc;EACZ;EACA;EACA,OAAO;EACP;EACA;EACA;CACF,CAAC;CAGH,OACE,qBAACC,OAAW,MAAZ;EACY;EACN;EACJ,OAAO;EACP,UAAU;EACJ;EACN,MAAM;EACI;EACA;EACV,OAAO;EACP,cAAc;EACd,eAAe;EAXjB,UAAA,CAaE,qBAACA,OAAW,SAAZ;GACE,WAAW,CAAC,UAAU;GACtB,WAAW;GACD;GACV,cAAc,CAAC;GACf,QAAQ,SAAS,oBAAC,OAAD,CAAM,CAAA,IAAI,KAAA;GACpB;GANT,UAAA;IAQG,eAAe,QAAQ,eAAe,KAAA,KACrC,oBAAC,QAAD;KAAM,WAAW,GAAGD,SAAO,QAAQ,YAAY,MAAM;KAAI,UAAA;IAAiB,CAAA;IAE5E,oBAACC,OAAW,OAAZ;KACE,WAAW,GAAGD,SAAO,OAAO,UAAUA,SAAO,WAAW,YAAY,KAAK;KAExE,UAAA;IACe,CAAA;IACjB,UACC,oBAAC,mBAAD;KACE,QAAA;KACW;KACC;KACF;KACV,aAAa,WAAW,WAAW,IAAI,cAAc,KAAA;KAC3C;KACV,iBAAiB;KACjB,OAAO;KACP,UAAU;KACV,WAAW;IACZ,CAAA;IAEH,oBAAC,qBAAD;KACc;KACD;KACK;KAChB,SAAS;IACV,CAAA;GACiB;EAEpB,CAAA,GAAA,oBAACC,OAAW,QAAZ;GAAmB,WAAW;GAC5B,UAAA,oBAAC,kBAAD;IACE,OAAM;IACN,sBAAsB;IACtB,WAAWD,SAAO;IAClB,MAAK;IACL,YAAY;IAEZ,UAAA,qBAACC,OAAW,OAAZ;KACE,OAAO;KACP,WAAW,GACTF,OAAW,OACXC,SAAO,OACP,gBACA,YAAY,OACZ,YAAY,QACd;KARF,UAAA,CAUG,oBAAoB,CAAC,UACpB,oBAAC,mBAAD;MACc;MACC;MACb,iBAAiB;MACjB,OAAO;MACP,UAAU;MACV,WAAW;KACZ,CAAA,GAEH,oBAAC,mBAAD;MACc;MACZ,WAAW,oBAAoB,CAAC;MACvB;MACI;MACG;MACP;MACK;KACf,CAAA,CACe;;GACF,CAAA;EACD,CAAA,CACJ;;AAErB,CACF;AAEA,SAAO,cAAc"}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { useAppElement } from "../../ThemeProvider/AppElementContext.mjs";
|
|
3
3
|
import { countVirtualItems, getOptionSearchText, isGroupOption, isValueEmpty, normalizeValueFor, splitBySeparators } from "./helpers.mjs";
|
|
4
4
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
-
import { jsx } from "react/jsx-runtime";
|
|
6
5
|
//#region src/base-ui/Select/hooks.tsx
|
|
7
6
|
function useSelectValue({ defaultValue, extraOptions, isMultiple, onChange, onSelect, options, setExtraOptions, value }) {
|
|
8
7
|
const [uncontrolledValue, setUncontrolledValue] = useState(() => {
|
|
@@ -217,40 +216,6 @@ function useSelectSearch({ appendTagValues, handleOpenChange, mergedOpen, mode,
|
|
|
217
216
|
};
|
|
218
217
|
}
|
|
219
218
|
function useSelectVirtual({ filteredOptions, listItemHeight, size, valueArray, virtual }) {
|
|
220
|
-
const listRef = useRef(null);
|
|
221
|
-
const pointerScrollRef = useRef(false);
|
|
222
|
-
const pointerScrollTimeoutRef = useRef(null);
|
|
223
|
-
const renderVirtualItem = useCallback((props) => {
|
|
224
|
-
const { ref, ...rest } = props;
|
|
225
|
-
return /* @__PURE__ */ jsx("div", {
|
|
226
|
-
...rest,
|
|
227
|
-
ref: (node) => {
|
|
228
|
-
if (node) node.scrollIntoView = (...args) => {
|
|
229
|
-
if (!pointerScrollRef.current) HTMLElement.prototype.scrollIntoView.call(node, ...args);
|
|
230
|
-
};
|
|
231
|
-
if (typeof ref === "function") ref(node);
|
|
232
|
-
else if (ref && "current" in ref) ref.current = node;
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
}, []);
|
|
236
|
-
const markPointerScroll = useCallback(() => {
|
|
237
|
-
pointerScrollRef.current = true;
|
|
238
|
-
if (pointerScrollTimeoutRef.current) clearTimeout(pointerScrollTimeoutRef.current);
|
|
239
|
-
pointerScrollTimeoutRef.current = setTimeout(() => {
|
|
240
|
-
pointerScrollRef.current = false;
|
|
241
|
-
}, 120);
|
|
242
|
-
}, []);
|
|
243
|
-
const handleListScroll = useCallback(() => {
|
|
244
|
-
if (!virtual || !pointerScrollRef.current) return;
|
|
245
|
-
const listElement = listRef.current;
|
|
246
|
-
const activeElement = document.activeElement;
|
|
247
|
-
if (listElement && activeElement && listElement.contains(activeElement)) listElement.focus({ preventScroll: true });
|
|
248
|
-
}, [virtual]);
|
|
249
|
-
useEffect(() => {
|
|
250
|
-
return () => {
|
|
251
|
-
if (pointerScrollTimeoutRef.current) clearTimeout(pointerScrollTimeoutRef.current);
|
|
252
|
-
};
|
|
253
|
-
}, []);
|
|
254
219
|
const virtualListStyle = useMemo(() => {
|
|
255
220
|
if (!virtual) return void 0;
|
|
256
221
|
const rowCount = countVirtualItems(filteredOptions);
|
|
@@ -262,8 +227,7 @@ function useSelectVirtual({ filteredOptions, listItemHeight, size, valueArray, v
|
|
|
262
227
|
virtual
|
|
263
228
|
]);
|
|
264
229
|
return {
|
|
265
|
-
|
|
266
|
-
keepMountedIndices: useMemo(() => {
|
|
230
|
+
selectedIndices: useMemo(() => {
|
|
267
231
|
if (!virtual || valueArray.length === 0) return void 0;
|
|
268
232
|
const selectedSet = new Set(valueArray);
|
|
269
233
|
const indices = [];
|
|
@@ -283,9 +247,6 @@ function useSelectVirtual({ filteredOptions, listItemHeight, size, valueArray, v
|
|
|
283
247
|
valueArray,
|
|
284
248
|
virtual
|
|
285
249
|
]),
|
|
286
|
-
listRef,
|
|
287
|
-
markPointerScroll,
|
|
288
|
-
renderVirtualItem,
|
|
289
250
|
virtualListStyle
|
|
290
251
|
};
|
|
291
252
|
}
|
|
@@ -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 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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"}
|
|
1
|
+
{"version":3,"file":"hooks.mjs","names":[],"sources":["../../../src/base-ui/Select/hooks.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ChangeEvent,\n type KeyboardEvent,\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 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 selectedIndices = 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 { selectedIndices, virtualListStyle };\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,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import Icon from "../../Icon/Icon.mjs";
|
|
3
|
+
import { VirtualScrollArea } from "../virtual/VirtualScrollArea.mjs";
|
|
4
|
+
import { useMenuVirtualList } from "../virtual/useMenuVirtualList.mjs";
|
|
3
5
|
import { styles } from "../DropdownMenu/sharedStyle.mjs";
|
|
4
6
|
import { styles as styles$1 } from "./style.mjs";
|
|
5
7
|
import { isValueEmpty } from "./helpers.mjs";
|
|
@@ -8,7 +10,6 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
8
10
|
import { cx } from "antd-style";
|
|
9
11
|
import { ChevronDown, Loader2, X } from "lucide-react";
|
|
10
12
|
import { Select } from "@base-ui/react/select";
|
|
11
|
-
import { Virtualizer } from "virtua";
|
|
12
13
|
//#region src/base-ui/Select/parts.tsx
|
|
13
14
|
function resolveIconNode(node) {
|
|
14
15
|
if (node === void 0 || node === null) return null;
|
|
@@ -86,27 +87,28 @@ function createTriggerValueRenderer({ getOption, isMultiple, isTags, labelRender
|
|
|
86
87
|
}
|
|
87
88
|
function SelectListSection({ classNames, hasSearch, isEmpty, listContent, listItemHeight, virtual, virtualState }) {
|
|
88
89
|
const listClassName = cx(styles$1.list, hasSearch && styles$1.listWithSearch, classNames?.list);
|
|
89
|
-
|
|
90
|
+
const enabled = Boolean(virtual) && !isEmpty;
|
|
91
|
+
const { keepMountedIndices, viewportProps, viewportRef, virtualChildren, virtualizerRef } = useMenuVirtualList({
|
|
92
|
+
children: listContent,
|
|
93
|
+
enabled,
|
|
94
|
+
keepMounted: virtualState.selectedIndices
|
|
95
|
+
});
|
|
96
|
+
if (!enabled) return /* @__PURE__ */ jsx(Select.List, {
|
|
90
97
|
className: listClassName,
|
|
91
98
|
"data-virtual": virtual || void 0,
|
|
92
99
|
children: listContent
|
|
93
100
|
});
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
children: /* @__PURE__ */ jsx(Virtualizer, {
|
|
106
|
-
itemSize: listItemHeight,
|
|
107
|
-
keepMounted: keepMountedIndices,
|
|
108
|
-
children: listContent
|
|
109
|
-
})
|
|
101
|
+
return /* @__PURE__ */ jsx(VirtualScrollArea, {
|
|
102
|
+
itemSize: listItemHeight,
|
|
103
|
+
keepMounted: keepMountedIndices,
|
|
104
|
+
style: virtualState.virtualListStyle,
|
|
105
|
+
viewport: /* @__PURE__ */ jsx(Select.List, { className: listClassName }),
|
|
106
|
+
viewportProps: {
|
|
107
|
+
ref: viewportRef,
|
|
108
|
+
...viewportProps
|
|
109
|
+
},
|
|
110
|
+
virtualizerRef,
|
|
111
|
+
children: virtualChildren
|
|
110
112
|
});
|
|
111
113
|
}
|
|
112
114
|
function EmptyContent({ classNames }) {
|
|
@@ -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 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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"}
|
|
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';\n\nimport { styles as menuStyles } from '@/base-ui/DropdownMenu/sharedStyle';\nimport { useMenuVirtualList, VirtualScrollArea } from '@/base-ui/virtual';\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 const enabled = Boolean(virtual) && !isEmpty;\n const { keepMountedIndices, viewportProps, viewportRef, virtualChildren, virtualizerRef } =\n useMenuVirtualList({\n children: listContent,\n enabled,\n keepMounted: virtualState.selectedIndices,\n });\n\n if (!enabled) {\n return (\n <BaseSelect.List className={listClassName} data-virtual={virtual || undefined}>\n {listContent}\n </BaseSelect.List>\n );\n }\n\n return (\n <VirtualScrollArea\n itemSize={listItemHeight}\n keepMounted={keepMountedIndices}\n style={virtualState.virtualListStyle}\n viewport={<BaseSelect.List className={listClassName} />}\n viewportProps={{ ref: viewportRef, ...viewportProps }}\n virtualizerRef={virtualizerRef}\n >\n {virtualChildren}\n </VirtualScrollArea>\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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"}
|
|
@@ -9,11 +9,10 @@ import { Check } from "lucide-react";
|
|
|
9
9
|
import { Select } from "@base-ui/react/select";
|
|
10
10
|
//#region src/base-ui/Select/renderOptions.tsx
|
|
11
11
|
function renderItem(option, index, params) {
|
|
12
|
-
const { classNames, isBoldIndicator, itemTextClassName, listItemHeight, optionRender
|
|
12
|
+
const { classNames, isBoldIndicator, itemTextClassName, listItemHeight, optionRender } = params;
|
|
13
13
|
return /* @__PURE__ */ jsxs(Select.Item, {
|
|
14
14
|
disabled: option.disabled,
|
|
15
15
|
label: getOptionSearchText(option),
|
|
16
|
-
render: virtual ? renderVirtualItem : void 0,
|
|
17
16
|
value: option.value,
|
|
18
17
|
className: cx(styles.item, styles$1.item, isBoldIndicator && styles$1.itemBoldSelected, classNames?.item, classNames?.option, option.className),
|
|
19
18
|
style: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderOptions.mjs","names":["BaseSelect","menuStyles","styles"],"sources":["../../../src/base-ui/Select/renderOptions.tsx"],"sourcesContent":["'use client';\n\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cx } from 'antd-style';\nimport { Check } from 'lucide-react';\
|
|
1
|
+
{"version":3,"file":"renderOptions.mjs","names":["BaseSelect","menuStyles","styles"],"sources":["../../../src/base-ui/Select/renderOptions.tsx"],"sourcesContent":["'use client';\n\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cx } from 'antd-style';\nimport { Check } from 'lucide-react';\n\nimport { styles as menuStyles } from '@/base-ui/DropdownMenu/sharedStyle';\nimport Icon from '@/Icon';\n\nimport { getOptionSearchText, isGroupOption } from './helpers';\nimport { styles } from './style';\nimport {\n type SelectClassNames,\n type SelectOption,\n type SelectOptions,\n type SelectProps,\n} from './type';\n\ninterface RenderOptionsParams {\n classNames: SelectClassNames | undefined;\n isBoldIndicator: boolean;\n items: SelectOptions<any>;\n itemTextClassName: string;\n listItemHeight: number | undefined;\n optionRender: SelectProps['optionRender'];\n}\n\nfunction renderItem(\n option: SelectOption<any>,\n index: number,\n params: Omit<RenderOptionsParams, 'items'>,\n) {\n const { classNames, isBoldIndicator, itemTextClassName, listItemHeight, optionRender } = params;\n\n return (\n <BaseSelect.Item\n disabled={option.disabled}\n key={`${String(option.value)}-${index}`}\n label={getOptionSearchText(option)}\n value={option.value}\n className={cx(\n menuStyles.item,\n styles.item,\n isBoldIndicator && styles.itemBoldSelected,\n classNames?.item,\n classNames?.option,\n option.className,\n )}\n style={{\n minHeight: listItemHeight,\n ...option.style,\n }}\n >\n <BaseSelect.ItemText className={itemTextClassName}>\n {optionRender ? optionRender(option, { index }) : option.label}\n </BaseSelect.ItemText>\n {!isBoldIndicator && (\n <BaseSelect.ItemIndicator className={cx(styles.itemIndicator, classNames?.itemIndicator)}>\n <Icon icon={Check} size={'small'} />\n </BaseSelect.ItemIndicator>\n )}\n </BaseSelect.Item>\n );\n}\n\nexport function renderOptions(params: RenderOptionsParams) {\n const { classNames, items } = params;\n let optionIndex = 0;\n\n return items.map((item, index) => {\n if (isGroupOption(item)) {\n return (\n <BaseSelect.Group className={cx(styles.group, classNames?.group)} key={`group-${index}`}>\n <BaseSelect.GroupLabel\n className={cx(menuStyles.groupLabel, styles.groupLabel, classNames?.groupLabel)}\n >\n {item.label}\n </BaseSelect.GroupLabel>\n {item.options.map((option) => renderItem(option, optionIndex++, params))}\n </BaseSelect.Group>\n );\n }\n\n return renderItem(item, optionIndex++, params);\n });\n}\n"],"mappings":";;;;;;;;;;AA2BA,SAAS,WACP,QACA,OACA,QACA;CACA,MAAM,EAAE,YAAY,iBAAiB,mBAAmB,gBAAgB,iBAAiB;CAEzF,OACE,qBAACA,OAAW,MAAZ;EACE,UAAU,OAAO;EAEjB,OAAO,oBAAoB,MAAM;EACjC,OAAO,OAAO;EACd,WAAW,GACTC,OAAW,MACXC,SAAO,MACP,mBAAmBA,SAAO,kBAC1B,YAAY,MACZ,YAAY,QACZ,OAAO,SACT;EACA,OAAO;GACL,WAAW;GACX,GAAG,OAAO;EACZ;EAhBF,UAAA,CAkBE,oBAACF,OAAW,UAAZ;GAAqB,WAAW;GAC7B,UAAA,eAAe,aAAa,QAAQ,EAAE,MAAM,CAAC,IAAI,OAAO;EACtC,CAAA,GACpB,CAAC,mBACA,oBAACA,OAAW,eAAZ;GAA0B,WAAW,GAAGE,SAAO,eAAe,YAAY,aAAa;GACrF,UAAA,oBAAC,MAAD;IAAM,MAAM;IAAO,MAAM;GAAU,CAAA;EACX,CAAA,CAEb;CAxBV,GAAA,GAAG,OAAO,OAAO,KAAK,EAAE,GAAG,OAwBjB;AAErB;AAEA,SAAgB,cAAc,QAA6B;CACzD,MAAM,EAAE,YAAY,UAAU;CAC9B,IAAI,cAAc;CAElB,OAAO,MAAM,KAAK,MAAM,UAAU;EAChC,IAAI,cAAc,IAAI,GACpB,OACE,qBAACF,OAAW,OAAZ;GAAkB,WAAW,GAAGE,SAAO,OAAO,YAAY,KAAK;GAA/D,UAAA,CACE,oBAACF,OAAW,YAAZ;IACE,WAAW,GAAGC,OAAW,YAAYC,SAAO,YAAY,YAAY,UAAU;IAE7E,UAAA,KAAK;GACe,CAAA,GACtB,KAAK,QAAQ,KAAK,WAAW,WAAW,QAAQ,eAAe,MAAM,CAAC,CACvD;EAPqD,GAAA,SAAS,OAO9D;EAItB,OAAO,WAAW,MAAM,eAAe,MAAM;CAC/C,CAAC;AACH"}
|
|
@@ -71,7 +71,6 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
71
71
|
list: css`
|
|
72
72
|
overflow-y: auto;
|
|
73
73
|
flex: 1;
|
|
74
|
-
|
|
75
74
|
min-height: 0;
|
|
76
75
|
padding-block: 0;
|
|
77
76
|
`,
|
|
@@ -89,14 +88,13 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
89
88
|
var(--lobe-select-popup-max-height, var(--available-height))
|
|
90
89
|
);
|
|
91
90
|
|
|
92
|
-
max-height: var(--lobe-select-available-height);
|
|
93
|
-
|
|
94
91
|
transform-origin: var(--transform-origin);
|
|
95
92
|
|
|
96
93
|
display: flex;
|
|
97
94
|
flex-direction: column;
|
|
98
95
|
|
|
99
96
|
box-sizing: border-box;
|
|
97
|
+
max-height: var(--lobe-select-available-height);
|
|
100
98
|
|
|
101
99
|
transition:
|
|
102
100
|
opacity 150ms ${cssVar.motionEaseOut},
|
|
@@ -137,7 +135,7 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
137
135
|
align-items: center;
|
|
138
136
|
|
|
139
137
|
min-height: 36px;
|
|
140
|
-
margin-inline: -
|
|
138
|
+
margin-inline: calc(-1 * var(--lobe-menu-popup-padding));
|
|
141
139
|
padding-block: 8px;
|
|
142
140
|
padding-inline: 12px;
|
|
143
141
|
border-block-end: 1px solid ${cssVar.colorFillSecondary};
|