@j2-health/design-system 0.6.8 → 0.6.9
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/dist/src/components/select/SummarizedSelect.cjs +97 -64
- package/dist/src/components/select/SummarizedSelect.cjs.map +1 -1
- package/dist/src/components/select/SummarizedSelect.d.ts +11 -2
- package/dist/src/components/select/SummarizedSelect.js +98 -65
- package/dist/src/components/select/SummarizedSelect.js.map +1 -1
- package/dist/src/components/select/SummarizedSelect.module.css.cjs +15 -12
- package/dist/src/components/select/SummarizedSelect.module.css.cjs.map +1 -1
- package/dist/src/components/select/SummarizedSelect.module.css.js +15 -13
- package/dist/src/components/select/SummarizedSelect.module.css.js.map +1 -1
- package/dist/style.css +35 -29
- package/package.json +1 -1
|
@@ -82,7 +82,7 @@ var OpenAtTop = ({ openCount, selectRef, children }) => {
|
|
|
82
82
|
}, [openCount, selectRef]);
|
|
83
83
|
return children;
|
|
84
84
|
};
|
|
85
|
-
function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading, multiple, value, onChange, options, renderLabel, rootClassName, popupClassName, variant, trigger = "select", triggerWeight, defaultOpen = false, flattenOnSearch = false, scrollToSelectedOnOpen = true, groupDividers = false, ...props }) {
|
|
85
|
+
function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading, multiple, value, onChange, options, renderLabel, rootClassName, popupClassName, variant, trigger = "select", triggerWeight, defaultOpen = false, flattenOnSearch = false, scrollToSelectedOnOpen = true, groupDividers = false, searchSuffix, ...props }) {
|
|
86
86
|
const isHeadline = variant === "headlined";
|
|
87
87
|
const isField = variant === "field";
|
|
88
88
|
const antVariant = isHeadline ? "borderless" : isField ? "outlined" : variant;
|
|
@@ -91,6 +91,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
91
91
|
const [focusTrigger, setFocusTrigger] = (0, react.useState)(defaultOpen ? 1 : 0);
|
|
92
92
|
const [isOpen, setIsOpen] = (0, react.useState)(defaultOpen);
|
|
93
93
|
const inputRef = (0, react.useRef)(null);
|
|
94
|
+
const popupRef = (0, react.useRef)(null);
|
|
94
95
|
const selectRef = (0, react.useRef)(null);
|
|
95
96
|
const measureSpanRef = (0, react.useRef)(null);
|
|
96
97
|
const [measuredWidth, setMeasuredWidth] = (0, react.useState)();
|
|
@@ -137,6 +138,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
137
138
|
const flatFilteredOptions = (0, react.useMemo)(() => {
|
|
138
139
|
return getAllOptions(filteredOptions);
|
|
139
140
|
}, [filteredOptions]);
|
|
141
|
+
const shownValues = (0, react.useMemo)(() => flatFilteredOptions.map((o) => String(o.value)).join("\0"), [flatFilteredOptions]);
|
|
140
142
|
const allFlatOptions = (0, react.useMemo)(() => {
|
|
141
143
|
return getAllOptions(options);
|
|
142
144
|
}, [options]);
|
|
@@ -204,77 +206,101 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
204
206
|
});
|
|
205
207
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: option.label });
|
|
206
208
|
};
|
|
209
|
+
const focusSearch = () => setTimeout(() => inputRef.current?.focus({ preventScroll: true }));
|
|
210
|
+
const renderSearchSuffix = () => searchSuffix ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
211
|
+
className: "flex items-center gap-2",
|
|
212
|
+
onClick: (e) => {
|
|
213
|
+
e.stopPropagation();
|
|
214
|
+
if (e.target.closest(".ant-select-item-option, [role=\"option\"]")) focusSearch();
|
|
215
|
+
},
|
|
216
|
+
onKeyDownCapture: (e) => {
|
|
217
|
+
if (e.key === "Escape" || e.key === "Enter") focusSearch();
|
|
218
|
+
},
|
|
219
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
220
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
221
|
+
"aria-hidden": true,
|
|
222
|
+
className: "h-4 w-px bg-j2-border-secondary"
|
|
223
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.ConfigProvider, {
|
|
224
|
+
getPopupContainer: () => popupRef.current ?? document.body,
|
|
225
|
+
children: searchSuffix
|
|
226
|
+
})]
|
|
227
|
+
}) : void 0;
|
|
207
228
|
const popupRender = (menu) => {
|
|
208
229
|
const valueToLabel = (val) => {
|
|
209
230
|
const option = allFlatOptions.find((opt) => opt.value === val);
|
|
210
231
|
return option ? option.label : val;
|
|
211
232
|
};
|
|
212
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
e
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
className: "flex flex-wrap gap-y-1",
|
|
237
|
-
children: value.map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Tag.Tag, {
|
|
238
|
-
className: "opacity-100 z-10 flex max-w-full",
|
|
239
|
-
status: "default",
|
|
240
|
-
closable: true,
|
|
241
|
-
onClose: () => handleTagClose(value),
|
|
242
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
243
|
-
className: "overflow-ellipsis overflow-hidden",
|
|
244
|
-
title: valueToLabel(value),
|
|
245
|
-
children: valueToLabel(value)
|
|
246
|
-
})
|
|
247
|
-
}, value))
|
|
248
|
-
})
|
|
249
|
-
}) : null,
|
|
250
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
251
|
-
className: (0, classnames.default)(require_SummarizedSelect_module.default.menuContainer, "rounded-lg", {
|
|
252
|
-
[require_SummarizedSelect_module.default.headlinedMenuContainer]: isHeadline,
|
|
253
|
-
[require_SummarizedSelect_module.default.menuContainerMultiple]: multiple
|
|
233
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
234
|
+
ref: popupRef,
|
|
235
|
+
className: (0, classnames.default)({ relative: searchSuffix != null }),
|
|
236
|
+
children: [
|
|
237
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
238
|
+
className: "mb-2 px-2 pb-2 border-b -mx-1 mt-1",
|
|
239
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input, {
|
|
240
|
+
ref: inputRef,
|
|
241
|
+
placeholder: searchPlaceholder || "Search...",
|
|
242
|
+
value: searchValue,
|
|
243
|
+
onChange: (e) => {
|
|
244
|
+
setSearchValue(e.target.value);
|
|
245
|
+
e.stopPropagation();
|
|
246
|
+
e.preventDefault();
|
|
247
|
+
},
|
|
248
|
+
onKeyDown: handleKeyDown,
|
|
249
|
+
onClick: (e) => e.stopPropagation(),
|
|
250
|
+
prefix: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_phosphor_icons_react.MagnifyingGlassIcon, {
|
|
251
|
+
size: 16,
|
|
252
|
+
className: "text-j2-text-placeholder"
|
|
253
|
+
}),
|
|
254
|
+
suffix: renderSearchSuffix(),
|
|
255
|
+
allowClear: true
|
|
256
|
+
}, focusTrigger)
|
|
254
257
|
}),
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
selectRef,
|
|
258
|
-
children: menu
|
|
259
|
-
}) }, searchValue)
|
|
260
|
-
}),
|
|
261
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
262
|
-
className: "flex justify-between items-center",
|
|
263
|
-
children: multiple && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
264
|
-
className: "w-full mt-1 pt-1 border-t border-j2-border-secondary",
|
|
258
|
+
multiple && value.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
259
|
+
className: "px-2 pb-2",
|
|
265
260
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
266
|
-
"
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
261
|
+
className: "flex flex-wrap gap-y-1",
|
|
262
|
+
children: value.map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Tag.Tag, {
|
|
263
|
+
className: "opacity-100 z-10 flex max-w-full",
|
|
264
|
+
status: "default",
|
|
265
|
+
closable: true,
|
|
266
|
+
onClose: () => handleTagClose(value),
|
|
267
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
268
|
+
className: "overflow-ellipsis overflow-hidden",
|
|
269
|
+
title: valueToLabel(value),
|
|
270
|
+
children: valueToLabel(value)
|
|
271
|
+
})
|
|
272
|
+
}, value))
|
|
273
|
+
})
|
|
274
|
+
}) : null,
|
|
275
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
276
|
+
className: (0, classnames.default)(require_SummarizedSelect_module.default.menuContainer, "rounded-lg", {
|
|
277
|
+
[require_SummarizedSelect_module.default.headlinedMenuContainer]: isHeadline,
|
|
278
|
+
[require_SummarizedSelect_module.default.menuContainerMultiple]: multiple
|
|
279
|
+
}),
|
|
280
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: scrollToSelectedOnOpen ? menu : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OpenAtTop, {
|
|
281
|
+
openCount: focusTrigger,
|
|
282
|
+
selectRef,
|
|
283
|
+
children: menu
|
|
284
|
+
}) }, `${searchValue}\u0000${shownValues}`)
|
|
285
|
+
}),
|
|
286
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
287
|
+
className: "flex justify-between items-center",
|
|
288
|
+
children: multiple && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
289
|
+
className: "w-full mt-1 pt-1 border-t border-j2-border-secondary",
|
|
270
290
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
271
|
-
|
|
272
|
-
|
|
291
|
+
"aria-selected": "false",
|
|
292
|
+
className: (0, classnames.default)("ant-select-item ant-select-item-option w-full", require_SummarizedSelect_module.default.clearAllButton),
|
|
293
|
+
title: "Clear all",
|
|
294
|
+
onClick: handleToggleAll,
|
|
295
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
296
|
+
className: "ant-select-item-option-content text-center font-semibold",
|
|
297
|
+
children: "Clear all"
|
|
298
|
+
})
|
|
273
299
|
})
|
|
274
300
|
})
|
|
275
301
|
})
|
|
276
|
-
|
|
277
|
-
|
|
302
|
+
]
|
|
303
|
+
});
|
|
278
304
|
};
|
|
279
305
|
const handleOpenChange = (open) => {
|
|
280
306
|
setIsOpen(open);
|
|
@@ -290,7 +316,11 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
290
316
|
"aria-selected": isSelected,
|
|
291
317
|
onClick: () => handleOptionClick(optionValue),
|
|
292
318
|
className: (0, classnames.default)("px-3 py-1.5 rounded cursor-pointer text-sm", isSelected ? "bg-[var(--j2-color-primary-bg-hover)] font-semibold text-[var(--j2-color-primary)] hover:bg-[var(--j2-color-primary-bg-hover)]" : "hover:bg-[var(--j2-color-bg-hover)]"),
|
|
293
|
-
children:
|
|
319
|
+
children: props.optionRender ? props.optionRender({
|
|
320
|
+
...option,
|
|
321
|
+
key: optionValue,
|
|
322
|
+
data: option
|
|
323
|
+
}, { index: flatFilteredOptions.indexOf(option) }) : hasLogo ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
294
324
|
className: "flex items-center gap-2",
|
|
295
325
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
296
326
|
className: "h-4 shrink-0",
|
|
@@ -308,7 +338,8 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
308
338
|
return option ? option.label : val;
|
|
309
339
|
};
|
|
310
340
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
311
|
-
|
|
341
|
+
ref: popupRef,
|
|
342
|
+
className: "relative bg-white rounded-lg shadow-md p-2 min-w-[240px]",
|
|
312
343
|
children: [
|
|
313
344
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
314
345
|
className: "pb-2 border-b border-j2-border-secondary",
|
|
@@ -326,6 +357,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
326
357
|
size: 16,
|
|
327
358
|
className: "text-j2-text-placeholder"
|
|
328
359
|
}),
|
|
360
|
+
suffix: renderSearchSuffix(),
|
|
329
361
|
allowClear: true
|
|
330
362
|
}, focusTrigger)
|
|
331
363
|
}),
|
|
@@ -396,6 +428,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
396
428
|
onOpenChange: handleOpenChange,
|
|
397
429
|
trigger: ["click"],
|
|
398
430
|
disabled: props.disabled,
|
|
431
|
+
getPopupContainer: props.getPopupContainer,
|
|
399
432
|
popupRender: dropdownPopupRender,
|
|
400
433
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Typography.Link, {
|
|
401
434
|
disabled: props.disabled,
|
|
@@ -451,7 +484,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
451
484
|
[require_SummarizedSelect_module.default.headlinedSelect]: isHeadline,
|
|
452
485
|
[require_SummarizedSelect_module.default.fieldSelect]: isField
|
|
453
486
|
}),
|
|
454
|
-
popup: { root: popupClassName }
|
|
487
|
+
popup: { root: (0, classnames.default)(popupClassName, { [require_SummarizedSelect_module.default.hasSearchSuffix]: searchSuffix != null }) }
|
|
455
488
|
},
|
|
456
489
|
variant: antVariant,
|
|
457
490
|
...props
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummarizedSelect.cjs","names":["cx","styles","useState","useRef","useMemo","Input","MagnifyingGlassIcon","Tag","Fragment","Spin","LoadingOutlined","CaretDownIcon","AntdDropdown","Typography","_Fragment","Select"],"sources":["../../../../src/components/select/SummarizedSelect.tsx"],"sourcesContent":["import {\n Dropdown as AntdDropdown,\n Select,\n Spin,\n Input,\n SelectProps,\n InputRef,\n Typography,\n} from 'antd'\nimport { DefaultOptionType, type RefSelectProps } from 'antd/es/select'\nimport { Fragment, useState, useMemo, useRef, useEffect } from 'react'\nimport { LoadingOutlined } from '@ant-design/icons'\nimport { CaretDownIcon, MagnifyingGlassIcon } from '@phosphor-icons/react'\nimport { Tag } from '../tag'\nimport cx from 'classnames'\n\nimport styles from './SummarizedSelect.module.css'\n\ntype Option = DefaultOptionType\ntype OptionWithLogo = Option & {\n logo: React.ReactNode\n}\n\ntype GroupOption = {\n label: string\n options: Option[]\n className?: string\n}\n\nexport type SelectOption = Option | GroupOption | OptionWithLogo\n\nexport type SummarizedSelectVariant =\n SelectProps['variant'] | 'headlined' | 'field'\n\nexport type SummarizedSelectTrigger = 'select' | 'dropdown'\n\ntype BaseProps = Omit<\n SelectProps<string | string[], SelectOption>,\n 'mode' | 'value' | 'onChange' | 'variant'\n> & {\n searchPlaceholder?: string\n formControlPlaceholder?: string\n rootClassName?: string\n popupClassName?: string\n /**\n * Look of the `'select'` trigger.\n * - antd's own variants (`'outlined'`, `'borderless'`, ...): the filter-chip\n * look. It sizes to its label and turns into a filled pill once a\n * multiple select has values.\n * - `'headlined'`: a page-title select.\n * - `'field'`: a plain form field. It fills its container and keeps the\n * same look whatever is selected, so it lines up with the inputs and\n * selects around it in a form row.\n */\n variant?: SummarizedSelectVariant\n /**\n * Shape of the control that opens the popup.\n * - `'select'` (default): antd Select, styled by `variant`.\n * - `'dropdown'`: antd Dropdown with a text target (label + caret), for\n * breadcrumbs and inline switchers. Semibold primary text with a duotone\n * caret. A Tailwind weight utility on `rootClassName` (`font-normal`,\n * `font-[450]`) replaces the default; for any other weight, use\n * `triggerWeight`. Ignores `variant`.\n */\n trigger?: SummarizedSelectTrigger\n /**\n * The `'dropdown'` trigger's font weight, e.g. `400` or `'normal'`.\n * Replaces the semibold default and wins over any class. Use it for a\n * weight `rootClassName` can't express as a Tailwind weight utility.\n */\n triggerWeight?: React.CSSProperties['fontWeight']\n defaultOpen?: boolean\n /**\n * While searching, list the matches as one list sorted by label: groups are\n * dropped, and a value that appears in more than one group shows once. Lets\n * a list that repeats options in a shortcut group (Recent, say) above the\n * full list search as a single list. Groups come back when the search is\n * cleared.\n */\n flattenOnSearch?: boolean\n /**\n * `false` opens the `'select'` trigger's list at the top every time instead\n * of scrolled to the selected option, for a list whose first rows matter\n * more than where the selection is. The `'dropdown'` trigger always opens\n * at the top.\n */\n scrollToSelectedOnOpen?: boolean\n /** A line between option groups, above the title of every group after the first. */\n groupDividers?: boolean\n\n loading?: boolean\n}\n\ntype SingleProps = {\n multiple?: false\n renderLabel?: undefined\n value: string | undefined\n onChange: (newValue: string) => void\n}\n\ntype MultiProps = {\n multiple: true\n renderLabel: (count: number) => string\n value: string[]\n onChange: (newValue: string[]) => void\n}\n\nexport type Props = BaseProps & (SingleProps | MultiProps)\n\nconst isGroupOption = (option: SelectOption): option is GroupOption => {\n return 'options' in option\n}\n\nconst getAllOptions = (options: SelectOption[] | undefined): Option[] => {\n if (!options) return []\n\n return options.flatMap((option) =>\n isGroupOption(option) ? option.options : [option]\n )\n}\n\nconst byLabel = (a: Option, b: Option) =>\n String(a.label ?? '').localeCompare(String(b.label ?? ''), undefined, {\n numeric: true,\n sensitivity: 'base',\n })\n\n/** One entry per value, the first one seen, sorted by label. */\nconst flattenAndSort = (options: SelectOption[]): Option[] => {\n const seen = new Set<unknown>()\n return getAllOptions(options)\n .filter((option) => {\n if (seen.has(option.value)) return false\n seen.add(option.value)\n return true\n })\n .sort(byLabel)\n}\n\nconst withGroupDividers = (options: SelectOption[]): SelectOption[] => {\n let groupsSeen = 0\n return options.map((option) => {\n if (!isGroupOption(option)) return option\n groupsSeen += 1\n return groupsSeen === 1\n ? option\n : {\n ...option,\n className: cx(option.className, styles.groupDivider),\n }\n })\n}\n\nconst filterOptions = (\n options: SelectOption[] | undefined,\n searchValue: string\n): SelectOption[] => {\n if (!options) return []\n if (!searchValue) return options\n\n return options\n .map((option) => {\n if (isGroupOption(option)) {\n const filteredSubOptions = option.options.filter((subOption) =>\n subOption.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n return filteredSubOptions.length > 0\n ? { ...option, options: filteredSubOptions }\n : null\n } else {\n return option.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n ? option\n : null\n }\n })\n .filter((option): option is SelectOption => option !== null)\n}\n\n/**\n * An unprefixed Tailwind font-weight utility: a named weight (`font-normal`,\n * `font-bold`) or an arbitrary numeric one (`font-[450]`). Arbitrary values\n * must be numeric, since `font-['Inter']` sets the family. Custom weight names\n * can't be told apart from family names, so they need `triggerWeight`.\n */\nconst WEIGHT_CLASS =\n /(^|\\s)font-(thin|extralight|light|normal|medium|semibold|bold|extrabold|black|\\[\\d+\\])(\\s|$)/\n\nconst hasWeightClass = (className?: string) =>\n Boolean(className && WEIGHT_CLASS.test(className))\n\n/**\n * Puts the option list back at the top each time it opens and each time it is\n * rebuilt for a search. antd scrolls to the selected option from a timeout\n * started in the list's own effect. This wraps the list, so its effect runs\n * after that one and its timeout lands last. It keys off a count of opens, not\n * the open flag: antd does not re-render a closed popup, so the flag it sees\n * can stay `true` from one open to the next.\n */\nconst OpenAtTop = ({\n openCount,\n selectRef,\n children,\n}: {\n openCount: number\n selectRef: React.RefObject<RefSelectProps | null>\n children: React.ReactElement\n}) => {\n useEffect(() => {\n const timeoutId = setTimeout(() => {\n selectRef.current?.scrollTo({ index: 0, align: 'top' })\n })\n return () => clearTimeout(timeoutId)\n }, [openCount, selectRef])\n return children\n}\n\nexport function SummarizedSelect({\n searchPlaceholder,\n formControlPlaceholder,\n loading,\n multiple,\n value,\n onChange,\n options,\n renderLabel,\n rootClassName,\n popupClassName,\n variant,\n trigger = 'select',\n triggerWeight,\n defaultOpen = false,\n flattenOnSearch = false,\n scrollToSelectedOnOpen = true,\n groupDividers = false,\n ...props\n}: Props) {\n const isHeadline = variant === 'headlined'\n const isField = variant === 'field'\n const antVariant = isHeadline ? 'borderless' : isField ? 'outlined' : variant\n const isChip = !isField && variant !== 'underlined' && !isHeadline\n const [searchValue, setSearchValue] = useState('')\n const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0)\n const [isOpen, setIsOpen] = useState(defaultOpen)\n const inputRef = useRef<InputRef>(null)\n const selectRef = useRef<RefSelectProps>(null)\n const measureSpanRef = useRef<HTMLSpanElement>(null)\n const [measuredWidth, setMeasuredWidth] = useState<number>()\n\n const displayText = useMemo(() => {\n if (multiple && value.length > 0) {\n return renderLabel(value.length)\n }\n if (!multiple && value) {\n const option = getAllOptions(options).find((opt) => opt.value === value)\n return option ? String(option.label) : String(value)\n }\n return formControlPlaceholder ?? ''\n }, [multiple, value, options, renderLabel, formControlPlaceholder])\n\n useEffect(() => {\n if (!measureSpanRef.current) return\n // padding (22px = 11px each side) + arrow (18px) + border (6px)\n setMeasuredWidth(Math.ceil(measureSpanRef.current.offsetWidth) + 46)\n }, [displayText])\n\n useEffect(() => {\n if (focusTrigger > 0) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setTimeout(() => {\n // `preventScroll`: on first open the popup is still at its initial\n // spot when this runs, and a plain focus scrolls the page to it.\n inputRef.current?.focus({ cursor: 'end', preventScroll: true })\n }, 100)\n })\n })\n }\n }, [focusTrigger])\n\n const filteredOptions = useMemo(() => {\n const filtered = filterOptions(options, searchValue)\n if (flattenOnSearch && searchValue) return flattenAndSort(filtered)\n return groupDividers ? withGroupDividers(filtered) : filtered\n }, [searchValue, options, flattenOnSearch, groupDividers])\n\n const flatFilteredOptions = useMemo(() => {\n return getAllOptions(filteredOptions)\n }, [filteredOptions])\n\n const allFlatOptions = useMemo(() => {\n return getAllOptions(options)\n }, [options])\n\n const handleTagClose = (removedValue: string) => {\n if (!multiple) return\n\n onChange(value.filter((x) => x !== removedValue))\n }\n\n const handleToggleAll = () => {\n if (!multiple) return\n\n const allFilteredValues = getAllOptions(filteredOptions).map(\n (opt) => opt.value as string\n )\n const someSelected = allFilteredValues.some((val) => value.includes(val))\n\n if (someSelected) {\n onChange(value.filter((val) => !allFilteredValues.includes(val)))\n }\n }\n\n const handleSelectFirstOption = () => {\n if (flatFilteredOptions.length === 0) return\n\n const firstOption = flatFilteredOptions[0]\n if (!firstOption) return\n\n const optionValue = firstOption.value as string\n\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleOptionClick = (optionValue: string) => {\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n // Allow these navigation keys to bubble up to Select's native keyboard handler\n const navigationKeys = ['ArrowUp', 'ArrowDown']\n\n // Handle Enter - select first filtered option (custom behavior)\n if (e.key === 'Enter') {\n e.preventDefault()\n e.stopPropagation()\n handleSelectFirstOption()\n return\n }\n\n // Handle Escape - close dropdown (custom behavior)\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n handleOpenChange(false)\n return\n }\n\n // For arrow keys, prevent cursor movement but allow propagation to Select\n if (navigationKeys.includes(e.key)) {\n e.preventDefault() // Prevents cursor from moving to start/end of input text\n // Do NOT call stopPropagation() - let event bubble to Select component\n return\n }\n\n // For all other keys (including Backspace), stop propagation\n // This prevents backspace from removing tags in multiple mode\n e.stopPropagation()\n }\n\n const optionRender: NonNullable<\n SelectProps<string | string[], SelectOption>['optionRender']\n > = (option) => {\n if ('logo' in option.data && option.data.logo) {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">{option.data.logo}</div>\n <span className=\"overflow-ellipsis overflow-hidden\">\n {option.label}\n </span>\n </div>\n )\n }\n return <div>{option.label}</div>\n }\n\n const popupRender = (menu: React.ReactElement) => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div>\n <div className=\"mb-2 px-2 pb-2 border-b -mx-1 mt-1\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n e.preventDefault()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 ? (\n <div className=\"px-2 pb-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((value) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={value}\n status=\"default\"\n closable\n onClose={() => handleTagClose(value)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(value)}\n >\n {valueToLabel(value)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n ) : null}\n <div\n className={cx(styles.menuContainer, 'rounded-lg', {\n [styles.headlinedMenuContainer]: isHeadline,\n [styles.menuContainerMultiple]: multiple,\n })}\n >\n {/* Keyed on the search so antd rebuilds its option list per\n keystroke. Focusing the search input blurs the Select, antd\n starts a close, cancels it because focus stayed in the popup,\n and never clears its `lockOptions` flag -- a locked list keeps\n showing the options it had when the popup opened. */}\n <Fragment key={searchValue}>\n {scrollToSelectedOnOpen ? (\n menu\n ) : (\n <OpenAtTop openCount={focusTrigger} selectRef={selectRef}>\n {menu}\n </OpenAtTop>\n )}\n </Fragment>\n </div>\n <div className=\"flex justify-between items-center\">\n {multiple && (\n <div className=\"w-full mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n aria-selected=\"false\"\n className={cx(\n 'ant-select-item ant-select-item-option w-full',\n styles.clearAllButton\n )}\n title=\"Clear all\"\n onClick={handleToggleAll}\n >\n <div className=\"ant-select-item-option-content text-center font-semibold\">\n Clear all\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open)\n if (open) {\n // Trigger focus by updating the counter\n setFocusTrigger((prev) => prev + 1)\n } else {\n setSearchValue('')\n }\n }\n\n const renderDropdownOptionRow = (option: Option) => {\n const optionValue = option.value as string\n const isSelected = multiple\n ? value.includes(optionValue)\n : value === optionValue\n const hasLogo = 'logo' in option && (option as OptionWithLogo).logo\n return (\n <div\n key={optionValue}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => handleOptionClick(optionValue)}\n className={cx(\n 'px-3 py-1.5 rounded cursor-pointer text-sm',\n isSelected\n ? 'bg-[var(--j2-color-primary-bg-hover)] font-semibold text-[var(--j2-color-primary)] hover:bg-[var(--j2-color-primary-bg-hover)]'\n : 'hover:bg-[var(--j2-color-bg-hover)]'\n )}\n >\n {hasLogo ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">\n {(option as OptionWithLogo).logo}\n </div>\n <span className=\"overflow-hidden overflow-ellipsis\">\n {option.label}\n </span>\n </div>\n ) : (\n option.label\n )}\n </div>\n )\n }\n\n const dropdownPopupRender = () => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div className=\"bg-white rounded-lg shadow-md p-2 min-w-[240px]\">\n <div className=\"pb-2 border-b border-j2-border-secondary\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 && (\n <div className=\"px-1 pt-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((v) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={v}\n status=\"default\"\n closable\n onClose={() => handleTagClose(v)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(v)}\n >\n {valueToLabel(v)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n )}\n <div\n className=\"max-h-72 overflow-y-auto py-1\"\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n >\n {filteredOptions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-[var(--j2-color-text-secondary)]\">\n No options found\n </div>\n ) : (\n filteredOptions.map((opt) => {\n if (isGroupOption(opt)) {\n return (\n <div key={`group-${opt.label}`} className={opt.className}>\n <div className=\"px-3 pt-2 pb-1 text-xs font-semibold uppercase tracking-wide text-[var(--j2-color-text-tertiary)]\">\n {opt.label}\n </div>\n {opt.options.map(renderDropdownOptionRow)}\n </div>\n )\n }\n return renderDropdownOptionRow(opt)\n })\n )}\n </div>\n {multiple && value.length > 0 && (\n <div className=\"mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n role=\"button\"\n aria-label=\"Clear all\"\n title=\"Clear all\"\n onClick={handleToggleAll}\n className={cx(\n 'text-center font-semibold text-sm py-1.5 rounded cursor-pointer',\n styles.clearAllButton\n )}\n >\n Clear all\n </div>\n </div>\n )}\n </div>\n )\n }\n\n if (trigger === 'dropdown') {\n const hasSelection = multiple ? value.length > 0 : Boolean(value)\n const triggerContent = (\n <span className=\"inline-flex items-center gap-1.5\">\n {hasSelection ? displayText : (formControlPlaceholder ?? 'Select')}\n {loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon weight=\"duotone\" data-testid=\"caret-down\" />\n )}\n </span>\n )\n\n return (\n <AntdDropdown\n open={isOpen}\n onOpenChange={handleOpenChange}\n trigger={['click']}\n disabled={props.disabled}\n popupRender={dropdownPopupRender}\n >\n <Typography.Link\n disabled={props.disabled}\n className={cx(\n 'inline-flex',\n styles.dropdownTrigger,\n triggerWeight === undefined &&\n !hasWeightClass(rootClassName) &&\n 'font-semibold',\n rootClassName\n )}\n style={\n triggerWeight === undefined\n ? undefined\n : { fontWeight: triggerWeight }\n }\n >\n {triggerContent}\n </Typography.Link>\n </AntdDropdown>\n )\n }\n\n return (\n <>\n <span\n ref={measureSpanRef}\n aria-hidden\n style={{\n position: 'absolute',\n visibility: 'hidden',\n whiteSpace: 'nowrap',\n fontSize: 'inherit',\n }}\n >\n {displayText}\n </span>\n <Select<string | string[], SelectOption>\n ref={selectRef}\n open={isOpen}\n showSearch={false}\n style={{ width: isField ? '100%' : measuredWidth }}\n suffixIcon={\n loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon size={14} data-testid=\"caret-down\" />\n )\n }\n placeholder={formControlPlaceholder}\n mode={multiple ? 'multiple' : undefined}\n value={value}\n maxTagCount={0}\n maxTagPlaceholder={multiple ? () => renderLabel(value.length) : value}\n options={filteredOptions}\n onChange={(val) => {\n if (multiple) {\n if (Array.isArray(val)) {\n onChange(val)\n } else {\n throw new Error('Value should be an array in multiple mode')\n }\n } else {\n if (typeof val === 'string') {\n onChange(val)\n } else {\n throw new Error(\n 'Value should be a string in single selection mode'\n )\n }\n }\n }}\n popupRender={popupRender}\n optionRender={optionRender}\n onOpenChange={handleOpenChange}\n classNames={{\n root: cx(rootClassName, styles.summarizedSelect, {\n [styles.hemisphericSelect]: isChip,\n [styles.isActive]: isChip && multiple && value.length > 0,\n [styles.headlinedSelect]: isHeadline,\n [styles.fieldSelect]: isField,\n }),\n popup: { root: popupClassName },\n }}\n variant={antVariant}\n {...props}\n />\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SummarizedSelect.cjs","names":["cx","styles","useState","useRef","useMemo","ConfigProvider","Input","MagnifyingGlassIcon","Tag","Fragment","Spin","LoadingOutlined","CaretDownIcon","AntdDropdown","Typography","_Fragment","Select"],"sources":["../../../../src/components/select/SummarizedSelect.tsx"],"sourcesContent":["import {\n ConfigProvider,\n Dropdown as AntdDropdown,\n Select,\n Spin,\n Input,\n SelectProps,\n InputRef,\n Typography,\n} from 'antd'\nimport { DefaultOptionType, type RefSelectProps } from 'antd/es/select'\nimport { Fragment, useState, useMemo, useRef, useEffect } from 'react'\nimport { LoadingOutlined } from '@ant-design/icons'\nimport { CaretDownIcon, MagnifyingGlassIcon } from '@phosphor-icons/react'\nimport { Tag } from '../tag'\nimport cx from 'classnames'\n\nimport styles from './SummarizedSelect.module.css'\n\ntype Option = DefaultOptionType\ntype OptionWithLogo = Option & {\n logo: React.ReactNode\n}\n\ntype GroupOption = {\n label: string\n options: Option[]\n className?: string\n}\n\nexport type SelectOption = Option | GroupOption | OptionWithLogo\n\nexport type SummarizedSelectVariant =\n SelectProps['variant'] | 'headlined' | 'field'\n\nexport type SummarizedSelectTrigger = 'select' | 'dropdown'\n\ntype BaseProps = Omit<\n SelectProps<string | string[], SelectOption>,\n 'mode' | 'value' | 'onChange' | 'variant'\n> & {\n searchPlaceholder?: string\n formControlPlaceholder?: string\n rootClassName?: string\n popupClassName?: string\n /**\n * Look of the `'select'` trigger.\n * - antd's own variants (`'outlined'`, `'borderless'`, ...): the filter-chip\n * look. It sizes to its label and turns into a filled pill once a\n * multiple select has values.\n * - `'headlined'`: a page-title select.\n * - `'field'`: a plain form field. It fills its container and keeps the\n * same look whatever is selected, so it lines up with the inputs and\n * selects around it in a form row.\n */\n variant?: SummarizedSelectVariant\n /**\n * Shape of the control that opens the popup.\n * - `'select'` (default): antd Select, styled by `variant`.\n * - `'dropdown'`: antd Dropdown with a text target (label + caret), for\n * breadcrumbs and inline switchers. Semibold primary text with a duotone\n * caret. A Tailwind weight utility on `rootClassName` (`font-normal`,\n * `font-[450]`) replaces the default; for any other weight, use\n * `triggerWeight`. Ignores `variant`. Of antd's Select props it takes\n * `optionRender` (for its rows) and `getPopupContainer`.\n */\n trigger?: SummarizedSelectTrigger\n /**\n * The `'dropdown'` trigger's font weight, e.g. `400` or `'normal'`.\n * Replaces the semibold default and wins over any class. Use it for a\n * weight `rootClassName` can't express as a Tailwind weight utility.\n */\n triggerWeight?: React.CSSProperties['fontWeight']\n defaultOpen?: boolean\n /**\n * While searching, list the matches as one list sorted by label: groups are\n * dropped, and a value that appears in more than one group shows once. Lets\n * a list that repeats options in a shortcut group (Recent, say) above the\n * full list search as a single list. Groups come back when the search is\n * cleared.\n */\n flattenOnSearch?: boolean\n /**\n * `false` opens the `'select'` trigger's list at the top every time instead\n * of scrolled to the selected option, for a list whose first rows matter\n * more than where the selection is. The `'dropdown'` trigger always opens\n * at the top.\n */\n scrollToSelectedOnOpen?: boolean\n /** A line between option groups, above the title of every group after the first. */\n groupDividers?: boolean\n /**\n * A control at the right end of the popup's search box, after a short\n * divider, in both triggers. For a control that sets the scope of the search,\n * such as a second select that filters the options. Its own popups open\n * inside this popup, and picking from them or pressing Escape there leaves\n * this popup open with focus back in the search box.\n */\n searchSuffix?: React.ReactNode\n\n loading?: boolean\n}\n\ntype SingleProps = {\n multiple?: false\n renderLabel?: undefined\n value: string | undefined\n onChange: (newValue: string) => void\n}\n\ntype MultiProps = {\n multiple: true\n renderLabel: (count: number) => string\n value: string[]\n onChange: (newValue: string[]) => void\n}\n\nexport type Props = BaseProps & (SingleProps | MultiProps)\n\nconst isGroupOption = (option: SelectOption): option is GroupOption => {\n return 'options' in option\n}\n\nconst getAllOptions = (options: SelectOption[] | undefined): Option[] => {\n if (!options) return []\n\n return options.flatMap((option) =>\n isGroupOption(option) ? option.options : [option]\n )\n}\n\nconst byLabel = (a: Option, b: Option) =>\n String(a.label ?? '').localeCompare(String(b.label ?? ''), undefined, {\n numeric: true,\n sensitivity: 'base',\n })\n\n/** One entry per value, the first one seen, sorted by label. */\nconst flattenAndSort = (options: SelectOption[]): Option[] => {\n const seen = new Set<unknown>()\n return getAllOptions(options)\n .filter((option) => {\n if (seen.has(option.value)) return false\n seen.add(option.value)\n return true\n })\n .sort(byLabel)\n}\n\nconst withGroupDividers = (options: SelectOption[]): SelectOption[] => {\n let groupsSeen = 0\n return options.map((option) => {\n if (!isGroupOption(option)) return option\n groupsSeen += 1\n return groupsSeen === 1\n ? option\n : {\n ...option,\n className: cx(option.className, styles.groupDivider),\n }\n })\n}\n\nconst filterOptions = (\n options: SelectOption[] | undefined,\n searchValue: string\n): SelectOption[] => {\n if (!options) return []\n if (!searchValue) return options\n\n return options\n .map((option) => {\n if (isGroupOption(option)) {\n const filteredSubOptions = option.options.filter((subOption) =>\n subOption.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n return filteredSubOptions.length > 0\n ? { ...option, options: filteredSubOptions }\n : null\n } else {\n return option.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n ? option\n : null\n }\n })\n .filter((option): option is SelectOption => option !== null)\n}\n\n/**\n * An unprefixed Tailwind font-weight utility: a named weight (`font-normal`,\n * `font-bold`) or an arbitrary numeric one (`font-[450]`). Arbitrary values\n * must be numeric, since `font-['Inter']` sets the family. Custom weight names\n * can't be told apart from family names, so they need `triggerWeight`.\n */\nconst WEIGHT_CLASS =\n /(^|\\s)font-(thin|extralight|light|normal|medium|semibold|bold|extrabold|black|\\[\\d+\\])(\\s|$)/\n\nconst hasWeightClass = (className?: string) =>\n Boolean(className && WEIGHT_CLASS.test(className))\n\n/**\n * Puts the option list back at the top each time it opens and each time it is\n * rebuilt for a search. antd scrolls to the selected option from a timeout\n * started in the list's own effect. This wraps the list, so its effect runs\n * after that one and its timeout lands last. It keys off a count of opens, not\n * the open flag: antd does not re-render a closed popup, so the flag it sees\n * can stay `true` from one open to the next.\n */\nconst OpenAtTop = ({\n openCount,\n selectRef,\n children,\n}: {\n openCount: number\n selectRef: React.RefObject<RefSelectProps | null>\n children: React.ReactElement\n}) => {\n useEffect(() => {\n const timeoutId = setTimeout(() => {\n selectRef.current?.scrollTo({ index: 0, align: 'top' })\n })\n return () => clearTimeout(timeoutId)\n }, [openCount, selectRef])\n return children\n}\n\nexport function SummarizedSelect({\n searchPlaceholder,\n formControlPlaceholder,\n loading,\n multiple,\n value,\n onChange,\n options,\n renderLabel,\n rootClassName,\n popupClassName,\n variant,\n trigger = 'select',\n triggerWeight,\n defaultOpen = false,\n flattenOnSearch = false,\n scrollToSelectedOnOpen = true,\n groupDividers = false,\n searchSuffix,\n ...props\n}: Props) {\n const isHeadline = variant === 'headlined'\n const isField = variant === 'field'\n const antVariant = isHeadline ? 'borderless' : isField ? 'outlined' : variant\n const isChip = !isField && variant !== 'underlined' && !isHeadline\n const [searchValue, setSearchValue] = useState('')\n const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0)\n const [isOpen, setIsOpen] = useState(defaultOpen)\n const inputRef = useRef<InputRef>(null)\n const popupRef = useRef<HTMLDivElement>(null)\n const selectRef = useRef<RefSelectProps>(null)\n const measureSpanRef = useRef<HTMLSpanElement>(null)\n const [measuredWidth, setMeasuredWidth] = useState<number>()\n\n const displayText = useMemo(() => {\n if (multiple && value.length > 0) {\n return renderLabel(value.length)\n }\n if (!multiple && value) {\n const option = getAllOptions(options).find((opt) => opt.value === value)\n return option ? String(option.label) : String(value)\n }\n return formControlPlaceholder ?? ''\n }, [multiple, value, options, renderLabel, formControlPlaceholder])\n\n useEffect(() => {\n if (!measureSpanRef.current) return\n // padding (22px = 11px each side) + arrow (18px) + border (6px)\n setMeasuredWidth(Math.ceil(measureSpanRef.current.offsetWidth) + 46)\n }, [displayText])\n\n useEffect(() => {\n if (focusTrigger > 0) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setTimeout(() => {\n // `preventScroll`: on first open the popup is still at its initial\n // spot when this runs, and a plain focus scrolls the page to it.\n inputRef.current?.focus({ cursor: 'end', preventScroll: true })\n }, 100)\n })\n })\n }\n }, [focusTrigger])\n\n const filteredOptions = useMemo(() => {\n const filtered = filterOptions(options, searchValue)\n if (flattenOnSearch && searchValue) return flattenAndSort(filtered)\n return groupDividers ? withGroupDividers(filtered) : filtered\n }, [searchValue, options, flattenOnSearch, groupDividers])\n\n const flatFilteredOptions = useMemo(() => {\n return getAllOptions(filteredOptions)\n }, [filteredOptions])\n\n // The values on show, so the list can be rebuilt when they change while\n // the popup is open (a filter in `searchSuffix`, say). Keyed on content, not\n // on the array, since callers often build `options` afresh each render.\n const shownValues = useMemo(\n () => flatFilteredOptions.map((o) => String(o.value)).join('\\u0000'),\n [flatFilteredOptions]\n )\n\n const allFlatOptions = useMemo(() => {\n return getAllOptions(options)\n }, [options])\n\n const handleTagClose = (removedValue: string) => {\n if (!multiple) return\n\n onChange(value.filter((x) => x !== removedValue))\n }\n\n const handleToggleAll = () => {\n if (!multiple) return\n\n const allFilteredValues = getAllOptions(filteredOptions).map(\n (opt) => opt.value as string\n )\n const someSelected = allFilteredValues.some((val) => value.includes(val))\n\n if (someSelected) {\n onChange(value.filter((val) => !allFilteredValues.includes(val)))\n }\n }\n\n const handleSelectFirstOption = () => {\n if (flatFilteredOptions.length === 0) return\n\n const firstOption = flatFilteredOptions[0]\n if (!firstOption) return\n\n const optionValue = firstOption.value as string\n\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleOptionClick = (optionValue: string) => {\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n // Allow these navigation keys to bubble up to Select's native keyboard handler\n const navigationKeys = ['ArrowUp', 'ArrowDown']\n\n // Handle Enter - select first filtered option (custom behavior)\n if (e.key === 'Enter') {\n e.preventDefault()\n e.stopPropagation()\n handleSelectFirstOption()\n return\n }\n\n // Handle Escape - close dropdown (custom behavior)\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n handleOpenChange(false)\n return\n }\n\n // For arrow keys, prevent cursor movement but allow propagation to Select\n if (navigationKeys.includes(e.key)) {\n e.preventDefault() // Prevents cursor from moving to start/end of input text\n // Do NOT call stopPropagation() - let event bubble to Select component\n return\n }\n\n // For all other keys (including Backspace), stop propagation\n // This prevents backspace from removing tags in multiple mode\n e.stopPropagation()\n }\n\n const optionRender: NonNullable<\n SelectProps<string | string[], SelectOption>['optionRender']\n > = (option) => {\n if ('logo' in option.data && option.data.logo) {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">{option.data.logo}</div>\n <span className=\"overflow-ellipsis overflow-hidden\">\n {option.label}\n </span>\n </div>\n )\n }\n return <div>{option.label}</div>\n }\n\n // A pick or a key in the suffix leaves focus nowhere, which would close this\n // popup, so focus goes back to the search box.\n const focusSearch = () =>\n setTimeout(() => inputRef.current?.focus({ preventScroll: true }))\n\n // Events from the suffix's own popups reach this span through React's tree,\n // although those popups render elsewhere in the DOM.\n const renderSearchSuffix = () =>\n searchSuffix ? (\n <span\n className=\"flex items-center gap-2\"\n // The search box focuses itself on any click inside it, which would\n // pull focus out of the suffix and close its popup as it opens.\n onClick={(e) => {\n e.stopPropagation()\n const target = e.target as HTMLElement\n // A pick closes the suffix's list and focus goes nowhere, which\n // would close this popup too.\n if (target.closest('.ant-select-item-option, [role=\"option\"]')) {\n focusSearch()\n }\n }}\n // Escape closes only the suffix's list, and Enter picks in it. Both\n // are caught on the way down, since a select in the suffix stops them\n // before they would bubble here.\n onKeyDownCapture={(e) => {\n if (e.key === 'Escape' || e.key === 'Enter') focusSearch()\n }}\n // Enter and typing never reach this select.\n onKeyDown={(e) => e.stopPropagation()}\n >\n <span aria-hidden className=\"h-4 w-px bg-j2-border-secondary\" />\n <ConfigProvider\n getPopupContainer={() => popupRef.current ?? document.body}\n >\n {searchSuffix}\n </ConfigProvider>\n </span>\n ) : undefined\n\n const popupRender = (menu: React.ReactElement) => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div ref={popupRef} className={cx({ relative: searchSuffix != null })}>\n <div className=\"mb-2 px-2 pb-2 border-b -mx-1 mt-1\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n e.preventDefault()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n suffix={renderSearchSuffix()}\n allowClear\n />\n </div>\n {multiple && value.length > 0 ? (\n <div className=\"px-2 pb-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((value) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={value}\n status=\"default\"\n closable\n onClose={() => handleTagClose(value)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(value)}\n >\n {valueToLabel(value)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n ) : null}\n <div\n className={cx(styles.menuContainer, 'rounded-lg', {\n [styles.headlinedMenuContainer]: isHeadline,\n [styles.menuContainerMultiple]: multiple,\n })}\n >\n {/* Keyed on the search and the values on show so antd rebuilds its\n option list per keystroke and when the options change. Focusing\n the search input blurs the Select, antd starts a close, cancels\n it because focus stayed in the popup, and never clears its\n `lockOptions` flag -- a locked list keeps showing the options it\n had when the popup opened. */}\n <Fragment key={`${searchValue}\\u0000${shownValues}`}>\n {scrollToSelectedOnOpen ? (\n menu\n ) : (\n <OpenAtTop openCount={focusTrigger} selectRef={selectRef}>\n {menu}\n </OpenAtTop>\n )}\n </Fragment>\n </div>\n <div className=\"flex justify-between items-center\">\n {multiple && (\n <div className=\"w-full mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n aria-selected=\"false\"\n className={cx(\n 'ant-select-item ant-select-item-option w-full',\n styles.clearAllButton\n )}\n title=\"Clear all\"\n onClick={handleToggleAll}\n >\n <div className=\"ant-select-item-option-content text-center font-semibold\">\n Clear all\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open)\n if (open) {\n // Trigger focus by updating the counter\n setFocusTrigger((prev) => prev + 1)\n } else {\n setSearchValue('')\n }\n }\n\n const renderDropdownOptionRow = (option: Option) => {\n const optionValue = option.value as string\n const isSelected = multiple\n ? value.includes(optionValue)\n : value === optionValue\n const hasLogo = 'logo' in option && (option as OptionWithLogo).logo\n return (\n <div\n key={optionValue}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => handleOptionClick(optionValue)}\n className={cx(\n 'px-3 py-1.5 rounded cursor-pointer text-sm',\n isSelected\n ? 'bg-[var(--j2-color-primary-bg-hover)] font-semibold text-[var(--j2-color-primary)] hover:bg-[var(--j2-color-primary-bg-hover)]'\n : 'hover:bg-[var(--j2-color-bg-hover)]'\n )}\n >\n {props.optionRender ? (\n // The same shape antd hands the select trigger's optionRender.\n props.optionRender(\n { ...option, key: optionValue, data: option } as Parameters<\n NonNullable<typeof props.optionRender>\n >[0],\n // Its place in the whole list, as antd counts it.\n { index: flatFilteredOptions.indexOf(option) }\n )\n ) : hasLogo ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">\n {(option as OptionWithLogo).logo}\n </div>\n <span className=\"overflow-hidden overflow-ellipsis\">\n {option.label}\n </span>\n </div>\n ) : (\n option.label\n )}\n </div>\n )\n }\n\n const dropdownPopupRender = () => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div\n ref={popupRef}\n className=\"relative bg-white rounded-lg shadow-md p-2 min-w-[240px]\"\n >\n <div className=\"pb-2 border-b border-j2-border-secondary\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n suffix={renderSearchSuffix()}\n allowClear\n />\n </div>\n {multiple && value.length > 0 && (\n <div className=\"px-1 pt-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((v) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={v}\n status=\"default\"\n closable\n onClose={() => handleTagClose(v)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(v)}\n >\n {valueToLabel(v)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n )}\n <div\n className=\"max-h-72 overflow-y-auto py-1\"\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n >\n {filteredOptions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-[var(--j2-color-text-secondary)]\">\n No options found\n </div>\n ) : (\n filteredOptions.map((opt) => {\n if (isGroupOption(opt)) {\n return (\n <div key={`group-${opt.label}`} className={opt.className}>\n <div className=\"px-3 pt-2 pb-1 text-xs font-semibold uppercase tracking-wide text-[var(--j2-color-text-tertiary)]\">\n {opt.label}\n </div>\n {opt.options.map(renderDropdownOptionRow)}\n </div>\n )\n }\n return renderDropdownOptionRow(opt)\n })\n )}\n </div>\n {multiple && value.length > 0 && (\n <div className=\"mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n role=\"button\"\n aria-label=\"Clear all\"\n title=\"Clear all\"\n onClick={handleToggleAll}\n className={cx(\n 'text-center font-semibold text-sm py-1.5 rounded cursor-pointer',\n styles.clearAllButton\n )}\n >\n Clear all\n </div>\n </div>\n )}\n </div>\n )\n }\n\n if (trigger === 'dropdown') {\n const hasSelection = multiple ? value.length > 0 : Boolean(value)\n const triggerContent = (\n <span className=\"inline-flex items-center gap-1.5\">\n {hasSelection ? displayText : (formControlPlaceholder ?? 'Select')}\n {loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon weight=\"duotone\" data-testid=\"caret-down\" />\n )}\n </span>\n )\n\n return (\n <AntdDropdown\n open={isOpen}\n onOpenChange={handleOpenChange}\n trigger={['click']}\n disabled={props.disabled}\n getPopupContainer={props.getPopupContainer}\n popupRender={dropdownPopupRender}\n >\n <Typography.Link\n disabled={props.disabled}\n className={cx(\n 'inline-flex',\n styles.dropdownTrigger,\n triggerWeight === undefined &&\n !hasWeightClass(rootClassName) &&\n 'font-semibold',\n rootClassName\n )}\n style={\n triggerWeight === undefined\n ? undefined\n : { fontWeight: triggerWeight }\n }\n >\n {triggerContent}\n </Typography.Link>\n </AntdDropdown>\n )\n }\n\n return (\n <>\n <span\n ref={measureSpanRef}\n aria-hidden\n style={{\n position: 'absolute',\n visibility: 'hidden',\n whiteSpace: 'nowrap',\n fontSize: 'inherit',\n }}\n >\n {displayText}\n </span>\n <Select<string | string[], SelectOption>\n ref={selectRef}\n open={isOpen}\n showSearch={false}\n style={{ width: isField ? '100%' : measuredWidth }}\n suffixIcon={\n loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon size={14} data-testid=\"caret-down\" />\n )\n }\n placeholder={formControlPlaceholder}\n mode={multiple ? 'multiple' : undefined}\n value={value}\n maxTagCount={0}\n maxTagPlaceholder={multiple ? () => renderLabel(value.length) : value}\n options={filteredOptions}\n onChange={(val) => {\n if (multiple) {\n if (Array.isArray(val)) {\n onChange(val)\n } else {\n throw new Error('Value should be an array in multiple mode')\n }\n } else {\n if (typeof val === 'string') {\n onChange(val)\n } else {\n throw new Error(\n 'Value should be a string in single selection mode'\n )\n }\n }\n }}\n popupRender={popupRender}\n optionRender={optionRender}\n onOpenChange={handleOpenChange}\n classNames={{\n root: cx(rootClassName, styles.summarizedSelect, {\n [styles.hemisphericSelect]: isChip,\n [styles.isActive]: isChip && multiple && value.length > 0,\n [styles.headlinedSelect]: isHeadline,\n [styles.fieldSelect]: isField,\n }),\n popup: {\n root: cx(popupClassName, {\n [styles.hasSearchSuffix]: searchSuffix != null,\n }),\n },\n }}\n variant={antVariant}\n {...props}\n />\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAuHA,IAAM,iBAAiB,WAAgD;CACrE,OAAO,aAAa;AACtB;AAEA,IAAM,iBAAiB,YAAkD;CACvE,IAAI,CAAC,SAAS,OAAO,CAAC;CAEtB,OAAO,QAAQ,SAAS,WACtB,cAAc,MAAM,IAAI,OAAO,UAAU,CAAC,MAAM,CAClD;AACF;AAEA,IAAM,WAAW,GAAW,MAC1B,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,cAAc,OAAO,EAAE,SAAS,EAAE,GAAG,KAAA,GAAW;CACpE,SAAS;CACT,aAAa;AACf,CAAC;;AAGH,IAAM,kBAAkB,YAAsC;CAC5D,MAAM,uBAAO,IAAI,IAAa;CAC9B,OAAO,cAAc,OAAO,CAAC,CAC1B,QAAQ,WAAW;EAClB,IAAI,KAAK,IAAI,OAAO,KAAK,GAAG,OAAO;EACnC,KAAK,IAAI,OAAO,KAAK;EACrB,OAAO;CACT,CAAC,CAAC,CACD,KAAK,OAAO;AACjB;AAEA,IAAM,qBAAqB,YAA4C;CACrE,IAAI,aAAa;CACjB,OAAO,QAAQ,KAAK,WAAW;EAC7B,IAAI,CAAC,cAAc,MAAM,GAAG,OAAO;EACnC,cAAc;EACd,OAAO,eAAe,IAClB,SACA;GACE,GAAG;GACH,YAAA,GAAWA,WAAAA,QAAAA,CAAG,OAAO,WAAWC,gCAAAA,QAAO,YAAY;EACrD;CACN,CAAC;AACH;AAEA,IAAM,iBACJ,SACA,gBACmB;CACnB,IAAI,CAAC,SAAS,OAAO,CAAC;CACtB,IAAI,CAAC,aAAa,OAAO;CAEzB,OAAO,QACJ,KAAK,WAAW;EACf,IAAI,cAAc,MAAM,GAAG;GACzB,MAAM,qBAAqB,OAAO,QAAQ,QAAQ,cAChD,UAAU,OACN,SAAS,CAAC,CACX,YAAY,CAAC,CACb,SAAS,YAAY,YAAY,CAAC,CACvC;GACA,OAAO,mBAAmB,SAAS,IAC/B;IAAE,GAAG;IAAQ,SAAS;GAAmB,IACzC;EACN,OACE,OAAO,OAAO,OACV,SAAS,CAAC,CACX,YAAY,CAAC,CACb,SAAS,YAAY,YAAY,CAAC,IACjC,SACA;CAER,CAAC,CAAC,CACD,QAAQ,WAAmC,WAAW,IAAI;AAC/D;;;;;;;AAQA,IAAM,eACJ;AAEF,IAAM,kBAAkB,cACtB,QAAQ,aAAa,aAAa,KAAK,SAAS,CAAC;;;;;;;;;AAUnD,IAAM,aAAa,EACjB,WACA,WACA,eAKI;CACJ,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,YAAY,iBAAiB;GACjC,UAAU,SAAS,SAAS;IAAE,OAAO;IAAG,OAAO;GAAM,CAAC;EACxD,CAAC;EACD,aAAa,aAAa,SAAS;CACrC,GAAG,CAAC,WAAW,SAAS,CAAC;CACzB,OAAO;AACT;AAEA,SAAgB,iBAAiB,EAC/B,mBACA,wBACA,SACA,UACA,OACA,UACA,SACA,aACA,eACA,gBACA,SACA,UAAU,UACV,eACA,cAAc,OACd,kBAAkB,OAClB,yBAAyB,MACzB,gBAAgB,OAChB,cACA,GAAG,SACK;CACR,MAAM,aAAa,YAAY;CAC/B,MAAM,UAAU,YAAY;CAC5B,MAAM,aAAa,aAAa,eAAe,UAAU,aAAa;CACtE,MAAM,SAAS,CAAC,WAAW,YAAY,gBAAgB,CAAC;CACxD,MAAM,CAAC,aAAa,mBAAA,GAAkBC,MAAAA,SAAAA,CAAS,EAAE;CACjD,MAAM,CAAC,cAAc,oBAAA,GAAmBA,MAAAA,SAAAA,CAAS,cAAc,IAAI,CAAC;CACpE,MAAM,CAAC,QAAQ,cAAA,GAAaA,MAAAA,SAAAA,CAAS,WAAW;CAChD,MAAM,YAAA,GAAWC,MAAAA,OAAAA,CAAiB,IAAI;CACtC,MAAM,YAAA,GAAWA,MAAAA,OAAAA,CAAuB,IAAI;CAC5C,MAAM,aAAA,GAAYA,MAAAA,OAAAA,CAAuB,IAAI;CAC7C,MAAM,kBAAA,GAAiBA,MAAAA,OAAAA,CAAwB,IAAI;CACnD,MAAM,CAAC,eAAe,qBAAA,GAAoBD,MAAAA,SAAAA,CAAiB;CAE3D,MAAM,eAAA,GAAcE,MAAAA,QAAAA,OAAc;EAChC,IAAI,YAAY,MAAM,SAAS,GAC7B,OAAO,YAAY,MAAM,MAAM;EAEjC,IAAI,CAAC,YAAY,OAAO;GACtB,MAAM,SAAS,cAAc,OAAO,CAAC,CAAC,MAAM,QAAQ,IAAI,UAAU,KAAK;GACvE,OAAO,SAAS,OAAO,OAAO,KAAK,IAAI,OAAO,KAAK;EACrD;EACA,OAAO,0BAA0B;CACnC,GAAG;EAAC;EAAU;EAAO;EAAS;EAAa;CAAsB,CAAC;CAElE,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,eAAe,SAAS;EAE7B,iBAAiB,KAAK,KAAK,eAAe,QAAQ,WAAW,IAAI,EAAE;CACrE,GAAG,CAAC,WAAW,CAAC;CAEhB,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,eAAe,GACjB,4BAA4B;GAC1B,4BAA4B;IAC1B,iBAAiB;KAGf,SAAS,SAAS,MAAM;MAAE,QAAQ;MAAO,eAAe;KAAK,CAAC;IAChE,GAAG,GAAG;GACR,CAAC;EACH,CAAC;CAEL,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,mBAAA,GAAkBA,MAAAA,QAAAA,OAAc;EACpC,MAAM,WAAW,cAAc,SAAS,WAAW;EACnD,IAAI,mBAAmB,aAAa,OAAO,eAAe,QAAQ;EAClE,OAAO,gBAAgB,kBAAkB,QAAQ,IAAI;CACvD,GAAG;EAAC;EAAa;EAAS;EAAiB;CAAa,CAAC;CAEzD,MAAM,uBAAA,GAAsBA,MAAAA,QAAAA,OAAc;EACxC,OAAO,cAAc,eAAe;CACtC,GAAG,CAAC,eAAe,CAAC;CAKpB,MAAM,eAAA,GAAcA,MAAAA,QAAAA,OACZ,oBAAoB,KAAK,MAAM,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,IAAQ,GACnE,CAAC,mBAAmB,CACtB;CAEA,MAAM,kBAAA,GAAiBA,MAAAA,QAAAA,OAAc;EACnC,OAAO,cAAc,OAAO;CAC9B,GAAG,CAAC,OAAO,CAAC;CAEZ,MAAM,kBAAkB,iBAAyB;EAC/C,IAAI,CAAC,UAAU;EAEf,SAAS,MAAM,QAAQ,MAAM,MAAM,YAAY,CAAC;CAClD;CAEA,MAAM,wBAAwB;EAC5B,IAAI,CAAC,UAAU;EAEf,MAAM,oBAAoB,cAAc,eAAe,CAAC,CAAC,KACtD,QAAQ,IAAI,KACf;EAGA,IAFqB,kBAAkB,MAAM,QAAQ,MAAM,SAAS,GAAG,CAEnE,GACF,SAAS,MAAM,QAAQ,QAAQ,CAAC,kBAAkB,SAAS,GAAG,CAAC,CAAC;CAEpE;CAEA,MAAM,gCAAgC;EACpC,IAAI,oBAAoB,WAAW,GAAG;EAEtC,MAAM,cAAc,oBAAoB;EACxC,IAAI,CAAC,aAAa;EAElB,MAAM,cAAc,YAAY;EAEhC,IAAI,UAAU;GACZ,IAAI,MAAM,SAAS,WAAW,GAC5B,SAAS,MAAM,QAAQ,MAAM,MAAM,WAAW,CAAC;QAE/C,SAAS,CAAC,GAAG,OAAO,WAAW,CAAC;EAEpC,OAAO;GACL,SAAS,WAAW;GACpB,iBAAiB,KAAK;EACxB;CACF;CAEA,MAAM,qBAAqB,gBAAwB;EACjD,IAAI,UAAU;GACZ,IAAI,MAAM,SAAS,WAAW,GAC5B,SAAS,MAAM,QAAQ,MAAM,MAAM,WAAW,CAAC;QAE/C,SAAS,CAAC,GAAG,OAAO,WAAW,CAAC;EAEpC,OAAO;GACL,SAAS,WAAW;GACpB,iBAAiB,KAAK;EACxB;CACF;CAEA,MAAM,iBAAiB,MAA6C;EAElE,MAAM,iBAAiB,CAAC,WAAW,WAAW;EAG9C,IAAI,EAAE,QAAQ,SAAS;GACrB,EAAE,eAAe;GACjB,EAAE,gBAAgB;GAClB,wBAAwB;GACxB;EACF;EAGA,IAAI,EAAE,QAAQ,UAAU;GACtB,EAAE,eAAe;GACjB,EAAE,gBAAgB;GAClB,iBAAiB,KAAK;GACtB;EACF;EAGA,IAAI,eAAe,SAAS,EAAE,GAAG,GAAG;GAClC,EAAE,eAAe;GAEjB;EACF;EAIA,EAAE,gBAAgB;CACpB;CAEA,MAAM,gBAED,WAAW;EACd,IAAI,UAAU,OAAO,QAAQ,OAAO,KAAK,MACvC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAU;IAAgB,UAAA,OAAO,KAAK;GAAU,CAAA,GACrD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IAAM,WAAU;IACb,UAAA,OAAO;GACJ,CAAA,CACH;;EAGT,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAA,UAAM,OAAO,MAAW,CAAA;CACjC;CAIA,MAAM,oBACJ,iBAAiB,SAAS,SAAS,MAAM,EAAE,eAAe,KAAK,CAAC,CAAC;CAInE,MAAM,2BACJ,eACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;EACE,WAAU;EAGV,UAAU,MAAM;GACd,EAAE,gBAAgB;GAIlB,IAHe,EAAE,OAGN,QAAQ,4CAA0C,GAC3D,YAAY;EAEhB;EAIA,mBAAmB,MAAM;GACvB,IAAI,EAAE,QAAQ,YAAY,EAAE,QAAQ,SAAS,YAAY;EAC3D;EAEA,YAAY,MAAM,EAAE,gBAAgB;EApBtC,UAAA,CAsBE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,eAAA;GAAY,WAAU;EAAmC,CAAA,GAC/D,iBAAA,GAAA,kBAAA,IAAA,CAACC,KAAAA,gBAAD;GACE,yBAAyB,SAAS,WAAW,SAAS;GAErD,UAAA;EACa,CAAA,CACZ;CACJ,CAAA,IAAA,KAAA;CAEN,MAAM,eAAe,SAA6B;EAChD,MAAM,gBAAgB,QAAgB;GACpC,MAAM,SAAS,eAAe,MAAM,QAAQ,IAAI,UAAU,GAAG;GAC7D,OAAO,SAAU,OAAO,QAAmB;EAC7C;EAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,KAAK;GAAU,YAAA,GAAWL,WAAAA,QAAAA,CAAG,EAAE,UAAU,gBAAgB,KAAK,CAAC;GAApE,UAAA;IACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;KACb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACM,KAAAA,OAAD;MACE,KAAK;MAEL,aAAa,qBAAqB;MAClC,OAAO;MACP,WAAW,MAAM;OACf,eAAe,EAAE,OAAO,KAAK;OAC7B,EAAE,gBAAgB;OAClB,EAAE,eAAe;MACnB;MACA,WAAW;MACX,UAAU,MAAM,EAAE,gBAAgB;MAClC,QACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,sBAAAA,qBAAD;OACE,MAAM;OACN,WAAU;MACX,CAAA;MAEH,QAAQ,mBAAmB;MAC3B,YAAA;KACD,GAlBM,YAkBN;IACE,CAAA;IACJ,YAAY,MAAM,SAAS,IAC1B,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;KACb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAU;MACX,UAAA,MAAmB,KAAK,UACxB,iBAAA,GAAA,kBAAA,IAAA,CAACC,YAAAA,KAAD;OACE,WAAU;OAEV,QAAO;OACP,UAAA;OACA,eAAe,eAAe,KAAK;OAEnC,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QACE,WAAU;QACV,OAAO,aAAa,KAAK;QAExB,UAAA,aAAa,KAAK;OACf,CAAA;MACH,GAXE,KAWF,CACN;KACE,CAAA;IACF,CAAA,IACH;IACJ,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KACE,YAAA,GAAWR,WAAAA,QAAAA,CAAGC,gCAAAA,QAAO,eAAe,cAAc;OAC/CA,gCAAAA,QAAO,yBAAyB;OAChCA,gCAAAA,QAAO,wBAAwB;KAClC,CAAC;KAQD,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACQ,MAAAA,UAAD,EAAA,UACG,yBACC,OAEA,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;MAAW,WAAW;MAAyB;MAC5C,UAAA;KACQ,CAAA,EAEL,GARK,GAAG,YAAY,QAAQ,aAQ5B;IACP,CAAA;IACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;KACZ,UAAA,YACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAU;MACb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OACE,iBAAc;OACd,YAAA,GAAWT,WAAAA,QAAAA,CACT,iDACAC,gCAAAA,QAAO,cACT;OACA,OAAM;OACN,SAAS;OAET,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAU;QAA2D,UAAA;OAErE,CAAA;MACF,CAAA;KACF,CAAA;IAEJ,CAAA;GACF;;CAET;CAEA,MAAM,oBAAoB,SAAkB;EAC1C,UAAU,IAAI;EACd,IAAI,MAEF,iBAAiB,SAAS,OAAO,CAAC;OAElC,eAAe,EAAE;CAErB;CAEA,MAAM,2BAA2B,WAAmB;EAClD,MAAM,cAAc,OAAO;EAC3B,MAAM,aAAa,WACf,MAAM,SAAS,WAAW,IAC1B,UAAU;EACd,MAAM,UAAU,UAAU,UAAW,OAA0B;EAC/D,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;GAEE,MAAK;GACL,iBAAe;GACf,eAAe,kBAAkB,WAAW;GAC5C,YAAA,GAAWD,WAAAA,QAAAA,CACT,8CACA,aACI,mIACA,qCACN;GAEC,UAAA,MAAM,eAEL,MAAM,aACJ;IAAE,GAAG;IAAQ,KAAK;IAAa,MAAM;GAAO,GAI5C,EAAE,OAAO,oBAAoB,QAAQ,MAAM,EAAE,CAC/C,IACE,UACF,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;KACX,UAAA,OAA0B;IACzB,CAAA,GACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;KACb,UAAA,OAAO;IACJ,CAAA,CACH;GAEL,CAAA,IAAA,OAAO;EAEN,GAhCE,WAgCF;CAET;CAEA,MAAM,4BAA4B;EAChC,MAAM,gBAAgB,QAAgB;GACpC,MAAM,SAAS,eAAe,MAAM,QAAQ,IAAI,UAAU,GAAG;GAC7D,OAAO,SAAU,OAAO,QAAmB;EAC7C;EAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GACE,KAAK;GACL,WAAU;GAFZ,UAAA;IAIE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;KACb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACM,KAAAA,OAAD;MACE,KAAK;MAEL,aAAa,qBAAqB;MAClC,OAAO;MACP,WAAW,MAAM;OACf,eAAe,EAAE,OAAO,KAAK;OAC7B,EAAE,gBAAgB;MACpB;MACA,WAAW;MACX,UAAU,MAAM,EAAE,gBAAgB;MAClC,QACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,sBAAAA,qBAAD;OACE,MAAM;OACN,WAAU;MACX,CAAA;MAEH,QAAQ,mBAAmB;MAC3B,YAAA;KACD,GAjBM,YAiBN;IACE,CAAA;IACJ,YAAY,MAAM,SAAS,KAC1B,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;KACb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAU;MACX,UAAA,MAAmB,KAAK,MACxB,iBAAA,GAAA,kBAAA,IAAA,CAACC,YAAAA,KAAD;OACE,WAAU;OAEV,QAAO;OACP,UAAA;OACA,eAAe,eAAe,CAAC;OAE/B,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QACE,WAAU;QACV,OAAO,aAAa,CAAC;QAEpB,UAAA,aAAa,CAAC;OACX,CAAA;MACH,GAXE,CAWF,CACN;KACE,CAAA;IACF,CAAA;IAEP,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,wBAAsB,YAAY,KAAA;KAEjC,UAAA,gBAAgB,WAAW,IAC1B,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAU;MAA0D,UAAA;KAEpE,CAAA,IAEL,gBAAgB,KAAK,QAAQ;MAC3B,IAAI,cAAc,GAAG,GACnB,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAgC,WAAW,IAAI;OAA/C,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAU;QACZ,UAAA,IAAI;OACF,CAAA,GACJ,IAAI,QAAQ,IAAI,uBAAuB,CACrC;MALK,GAAA,SAAS,IAAI,OAKlB;MAGT,OAAO,wBAAwB,GAAG;KACpC,CAAC;IAEA,CAAA;IACJ,YAAY,MAAM,SAAS,KAC1B,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;KACb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MACE,MAAK;MACL,cAAW;MACX,OAAM;MACN,SAAS;MACT,YAAA,GAAWR,WAAAA,QAAAA,CACT,mEACAC,gCAAAA,QAAO,cACT;MACD,UAAA;KAEI,CAAA;IACF,CAAA;GAEJ;;CAET;CAEA,IAAI,YAAY,YAAY;EAC1B,MAAM,eAAe,WAAW,MAAM,SAAS,IAAI,QAAQ,KAAK;EAChE,MAAM,iBACJ,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACG,eAAe,cAAe,0BAA0B,UACxD,UACC,iBAAA,GAAA,kBAAA,IAAA,CAACS,KAAAA,MAAD;IACE,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAACC,kBAAAA,iBAAD,EAAiB,MAAA,KAAM,CAAA;IAClC,MAAK;IACL,eAAY;GACb,CAAA,IAED,iBAAA,GAAA,kBAAA,IAAA,CAACC,sBAAAA,eAAD;IAAe,QAAO;IAAU,eAAY;GAAc,CAAA,CAExD;;EAGR,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,KAAAA,UAAD;GACE,MAAM;GACN,cAAc;GACd,SAAS,CAAC,OAAO;GACjB,UAAU,MAAM;GAChB,mBAAmB,MAAM;GACzB,aAAa;GAEb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,KAAAA,WAAW,MAAZ;IACE,UAAU,MAAM;IAChB,YAAA,GAAWd,WAAAA,QAAAA,CACT,eACAC,gCAAAA,QAAO,iBACP,kBAAkB,KAAA,KAChB,CAAC,eAAe,aAAa,KAC7B,iBACF,aACF;IACA,OACE,kBAAkB,KAAA,IACd,KAAA,IACA,EAAE,YAAY,cAAc;IAGjC,UAAA;GACc,CAAA;EACL,CAAA;CAElB;CAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAAc,kBAAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;EACE,KAAK;EACL,eAAA;EACA,OAAO;GACL,UAAU;GACV,YAAY;GACZ,YAAY;GACZ,UAAU;EACZ;EAEC,UAAA;CACG,CAAA,GACN,iBAAA,GAAA,kBAAA,IAAA,CAACC,KAAAA,QAAD;EACE,KAAK;EACL,MAAM;EACN,YAAY;EACZ,OAAO,EAAE,OAAO,UAAU,SAAS,cAAc;EACjD,YACE,UACE,iBAAA,GAAA,kBAAA,IAAA,CAACN,KAAAA,MAAD;GACE,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAACC,kBAAAA,iBAAD,EAAiB,MAAA,KAAM,CAAA;GAClC,MAAK;GACL,eAAY;EACb,CAAA,IAED,iBAAA,GAAA,kBAAA,IAAA,CAACC,sBAAAA,eAAD;GAAe,MAAM;GAAI,eAAY;EAAc,CAAA;EAGvD,aAAa;EACb,MAAM,WAAW,aAAa,KAAA;EACvB;EACP,aAAa;EACb,mBAAmB,iBAAiB,YAAY,MAAM,MAAM,IAAI;EAChE,SAAS;EACT,WAAW,QAAQ;GACjB,IAAI,UAAU;IACZ,IAAI,MAAM,QAAQ,GAAG,GACnB,SAAS,GAAG;SAEZ,MAAM,IAAI,MAAM,2CAA2C;GAE/D,OACE,IAAI,OAAO,QAAQ,UACjB,SAAS,GAAG;QAEZ,MAAM,IAAI,MACR,mDACF;EAGN;EACa;EACC;EACd,cAAc;EACd,YAAY;GACV,OAAA,GAAMZ,WAAAA,QAAAA,CAAG,eAAeC,gCAAAA,QAAO,kBAAkB;KAC9CA,gCAAAA,QAAO,oBAAoB;KAC3BA,gCAAAA,QAAO,WAAW,UAAU,YAAY,MAAM,SAAS;KACvDA,gCAAAA,QAAO,kBAAkB;KACzBA,gCAAAA,QAAO,cAAc;GACxB,CAAC;GACD,OAAO,EACL,OAAA,GAAMD,WAAAA,QAAAA,CAAG,gBAAgB,GACtBC,gCAAAA,QAAO,kBAAkB,gBAAgB,KAC5C,CAAC,EACH;EACF;EACA,SAAS;EACT,GAAI;CACL,CAAA,CACD,EAAA,CAAA;AAEN"}
|
|
@@ -35,7 +35,8 @@ type BaseProps = Omit<SelectProps<string | string[], SelectOption>, 'mode' | 'va
|
|
|
35
35
|
* breadcrumbs and inline switchers. Semibold primary text with a duotone
|
|
36
36
|
* caret. A Tailwind weight utility on `rootClassName` (`font-normal`,
|
|
37
37
|
* `font-[450]`) replaces the default; for any other weight, use
|
|
38
|
-
* `triggerWeight`. Ignores `variant`.
|
|
38
|
+
* `triggerWeight`. Ignores `variant`. Of antd's Select props it takes
|
|
39
|
+
* `optionRender` (for its rows) and `getPopupContainer`.
|
|
39
40
|
*/
|
|
40
41
|
trigger?: SummarizedSelectTrigger;
|
|
41
42
|
/**
|
|
@@ -62,6 +63,14 @@ type BaseProps = Omit<SelectProps<string | string[], SelectOption>, 'mode' | 'va
|
|
|
62
63
|
scrollToSelectedOnOpen?: boolean;
|
|
63
64
|
/** A line between option groups, above the title of every group after the first. */
|
|
64
65
|
groupDividers?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* A control at the right end of the popup's search box, after a short
|
|
68
|
+
* divider, in both triggers. For a control that sets the scope of the search,
|
|
69
|
+
* such as a second select that filters the options. Its own popups open
|
|
70
|
+
* inside this popup, and picking from them or pressing Escape there leaves
|
|
71
|
+
* this popup open with focus back in the search box.
|
|
72
|
+
*/
|
|
73
|
+
searchSuffix?: React.ReactNode;
|
|
65
74
|
loading?: boolean;
|
|
66
75
|
};
|
|
67
76
|
type SingleProps = {
|
|
@@ -77,5 +86,5 @@ type MultiProps = {
|
|
|
77
86
|
onChange: (newValue: string[]) => void;
|
|
78
87
|
};
|
|
79
88
|
export type Props = BaseProps & (SingleProps | MultiProps);
|
|
80
|
-
export declare function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading, multiple, value, onChange, options, renderLabel, rootClassName, popupClassName, variant, trigger, triggerWeight, defaultOpen, flattenOnSearch, scrollToSelectedOnOpen, groupDividers, ...props }: Props): import('react').JSX.Element;
|
|
89
|
+
export declare function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading, multiple, value, onChange, options, renderLabel, rootClassName, popupClassName, variant, trigger, triggerWeight, defaultOpen, flattenOnSearch, scrollToSelectedOnOpen, groupDividers, searchSuffix, ...props }: Props): import('react').JSX.Element;
|
|
81
90
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tag as Tag$1 } from "../tag/Tag.js";
|
|
2
2
|
import SummarizedSelect_module_default from "./SummarizedSelect.module.css.js";
|
|
3
3
|
import { Fragment, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import { Dropdown, Input, Select, Spin, Typography } from "antd";
|
|
4
|
+
import { ConfigProvider, Dropdown, Input, Select, Spin, Typography } from "antd";
|
|
5
5
|
import { CaretDownIcon, MagnifyingGlassIcon } from "@phosphor-icons/react";
|
|
6
6
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import cx from "classnames";
|
|
@@ -79,7 +79,7 @@ var OpenAtTop = ({ openCount, selectRef, children }) => {
|
|
|
79
79
|
}, [openCount, selectRef]);
|
|
80
80
|
return children;
|
|
81
81
|
};
|
|
82
|
-
function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading, multiple, value, onChange, options, renderLabel, rootClassName, popupClassName, variant, trigger = "select", triggerWeight, defaultOpen = false, flattenOnSearch = false, scrollToSelectedOnOpen = true, groupDividers = false, ...props }) {
|
|
82
|
+
function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading, multiple, value, onChange, options, renderLabel, rootClassName, popupClassName, variant, trigger = "select", triggerWeight, defaultOpen = false, flattenOnSearch = false, scrollToSelectedOnOpen = true, groupDividers = false, searchSuffix, ...props }) {
|
|
83
83
|
const isHeadline = variant === "headlined";
|
|
84
84
|
const isField = variant === "field";
|
|
85
85
|
const antVariant = isHeadline ? "borderless" : isField ? "outlined" : variant;
|
|
@@ -88,6 +88,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
88
88
|
const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0);
|
|
89
89
|
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
90
90
|
const inputRef = useRef(null);
|
|
91
|
+
const popupRef = useRef(null);
|
|
91
92
|
const selectRef = useRef(null);
|
|
92
93
|
const measureSpanRef = useRef(null);
|
|
93
94
|
const [measuredWidth, setMeasuredWidth] = useState();
|
|
@@ -134,6 +135,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
134
135
|
const flatFilteredOptions = useMemo(() => {
|
|
135
136
|
return getAllOptions(filteredOptions);
|
|
136
137
|
}, [filteredOptions]);
|
|
138
|
+
const shownValues = useMemo(() => flatFilteredOptions.map((o) => String(o.value)).join("\0"), [flatFilteredOptions]);
|
|
137
139
|
const allFlatOptions = useMemo(() => {
|
|
138
140
|
return getAllOptions(options);
|
|
139
141
|
}, [options]);
|
|
@@ -201,77 +203,101 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
201
203
|
});
|
|
202
204
|
return /* @__PURE__ */ jsx("div", { children: option.label });
|
|
203
205
|
};
|
|
206
|
+
const focusSearch = () => setTimeout(() => inputRef.current?.focus({ preventScroll: true }));
|
|
207
|
+
const renderSearchSuffix = () => searchSuffix ? /* @__PURE__ */ jsxs("span", {
|
|
208
|
+
className: "flex items-center gap-2",
|
|
209
|
+
onClick: (e) => {
|
|
210
|
+
e.stopPropagation();
|
|
211
|
+
if (e.target.closest(".ant-select-item-option, [role=\"option\"]")) focusSearch();
|
|
212
|
+
},
|
|
213
|
+
onKeyDownCapture: (e) => {
|
|
214
|
+
if (e.key === "Escape" || e.key === "Enter") focusSearch();
|
|
215
|
+
},
|
|
216
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
217
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
218
|
+
"aria-hidden": true,
|
|
219
|
+
className: "h-4 w-px bg-j2-border-secondary"
|
|
220
|
+
}), /* @__PURE__ */ jsx(ConfigProvider, {
|
|
221
|
+
getPopupContainer: () => popupRef.current ?? document.body,
|
|
222
|
+
children: searchSuffix
|
|
223
|
+
})]
|
|
224
|
+
}) : void 0;
|
|
204
225
|
const popupRender = (menu) => {
|
|
205
226
|
const valueToLabel = (val) => {
|
|
206
227
|
const option = allFlatOptions.find((opt) => opt.value === val);
|
|
207
228
|
return option ? option.label : val;
|
|
208
229
|
};
|
|
209
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
e
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
className: "flex flex-wrap gap-y-1",
|
|
234
|
-
children: value.map((value) => /* @__PURE__ */ jsx(Tag$1, {
|
|
235
|
-
className: "opacity-100 z-10 flex max-w-full",
|
|
236
|
-
status: "default",
|
|
237
|
-
closable: true,
|
|
238
|
-
onClose: () => handleTagClose(value),
|
|
239
|
-
children: /* @__PURE__ */ jsx("span", {
|
|
240
|
-
className: "overflow-ellipsis overflow-hidden",
|
|
241
|
-
title: valueToLabel(value),
|
|
242
|
-
children: valueToLabel(value)
|
|
243
|
-
})
|
|
244
|
-
}, value))
|
|
245
|
-
})
|
|
246
|
-
}) : null,
|
|
247
|
-
/* @__PURE__ */ jsx("div", {
|
|
248
|
-
className: cx(SummarizedSelect_module_default.menuContainer, "rounded-lg", {
|
|
249
|
-
[SummarizedSelect_module_default.headlinedMenuContainer]: isHeadline,
|
|
250
|
-
[SummarizedSelect_module_default.menuContainerMultiple]: multiple
|
|
230
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
231
|
+
ref: popupRef,
|
|
232
|
+
className: cx({ relative: searchSuffix != null }),
|
|
233
|
+
children: [
|
|
234
|
+
/* @__PURE__ */ jsx("div", {
|
|
235
|
+
className: "mb-2 px-2 pb-2 border-b -mx-1 mt-1",
|
|
236
|
+
children: /* @__PURE__ */ jsx(Input, {
|
|
237
|
+
ref: inputRef,
|
|
238
|
+
placeholder: searchPlaceholder || "Search...",
|
|
239
|
+
value: searchValue,
|
|
240
|
+
onChange: (e) => {
|
|
241
|
+
setSearchValue(e.target.value);
|
|
242
|
+
e.stopPropagation();
|
|
243
|
+
e.preventDefault();
|
|
244
|
+
},
|
|
245
|
+
onKeyDown: handleKeyDown,
|
|
246
|
+
onClick: (e) => e.stopPropagation(),
|
|
247
|
+
prefix: /* @__PURE__ */ jsx(MagnifyingGlassIcon, {
|
|
248
|
+
size: 16,
|
|
249
|
+
className: "text-j2-text-placeholder"
|
|
250
|
+
}),
|
|
251
|
+
suffix: renderSearchSuffix(),
|
|
252
|
+
allowClear: true
|
|
253
|
+
}, focusTrigger)
|
|
251
254
|
}),
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
selectRef,
|
|
255
|
-
children: menu
|
|
256
|
-
}) }, searchValue)
|
|
257
|
-
}),
|
|
258
|
-
/* @__PURE__ */ jsx("div", {
|
|
259
|
-
className: "flex justify-between items-center",
|
|
260
|
-
children: multiple && /* @__PURE__ */ jsx("div", {
|
|
261
|
-
className: "w-full mt-1 pt-1 border-t border-j2-border-secondary",
|
|
255
|
+
multiple && value.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
256
|
+
className: "px-2 pb-2",
|
|
262
257
|
children: /* @__PURE__ */ jsx("div", {
|
|
263
|
-
"
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
258
|
+
className: "flex flex-wrap gap-y-1",
|
|
259
|
+
children: value.map((value) => /* @__PURE__ */ jsx(Tag$1, {
|
|
260
|
+
className: "opacity-100 z-10 flex max-w-full",
|
|
261
|
+
status: "default",
|
|
262
|
+
closable: true,
|
|
263
|
+
onClose: () => handleTagClose(value),
|
|
264
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
265
|
+
className: "overflow-ellipsis overflow-hidden",
|
|
266
|
+
title: valueToLabel(value),
|
|
267
|
+
children: valueToLabel(value)
|
|
268
|
+
})
|
|
269
|
+
}, value))
|
|
270
|
+
})
|
|
271
|
+
}) : null,
|
|
272
|
+
/* @__PURE__ */ jsx("div", {
|
|
273
|
+
className: cx(SummarizedSelect_module_default.menuContainer, "rounded-lg", {
|
|
274
|
+
[SummarizedSelect_module_default.headlinedMenuContainer]: isHeadline,
|
|
275
|
+
[SummarizedSelect_module_default.menuContainerMultiple]: multiple
|
|
276
|
+
}),
|
|
277
|
+
children: /* @__PURE__ */ jsx(Fragment, { children: scrollToSelectedOnOpen ? menu : /* @__PURE__ */ jsx(OpenAtTop, {
|
|
278
|
+
openCount: focusTrigger,
|
|
279
|
+
selectRef,
|
|
280
|
+
children: menu
|
|
281
|
+
}) }, `${searchValue}\u0000${shownValues}`)
|
|
282
|
+
}),
|
|
283
|
+
/* @__PURE__ */ jsx("div", {
|
|
284
|
+
className: "flex justify-between items-center",
|
|
285
|
+
children: multiple && /* @__PURE__ */ jsx("div", {
|
|
286
|
+
className: "w-full mt-1 pt-1 border-t border-j2-border-secondary",
|
|
267
287
|
children: /* @__PURE__ */ jsx("div", {
|
|
268
|
-
|
|
269
|
-
|
|
288
|
+
"aria-selected": "false",
|
|
289
|
+
className: cx("ant-select-item ant-select-item-option w-full", SummarizedSelect_module_default.clearAllButton),
|
|
290
|
+
title: "Clear all",
|
|
291
|
+
onClick: handleToggleAll,
|
|
292
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
293
|
+
className: "ant-select-item-option-content text-center font-semibold",
|
|
294
|
+
children: "Clear all"
|
|
295
|
+
})
|
|
270
296
|
})
|
|
271
297
|
})
|
|
272
298
|
})
|
|
273
|
-
|
|
274
|
-
|
|
299
|
+
]
|
|
300
|
+
});
|
|
275
301
|
};
|
|
276
302
|
const handleOpenChange = (open) => {
|
|
277
303
|
setIsOpen(open);
|
|
@@ -287,7 +313,11 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
287
313
|
"aria-selected": isSelected,
|
|
288
314
|
onClick: () => handleOptionClick(optionValue),
|
|
289
315
|
className: cx("px-3 py-1.5 rounded cursor-pointer text-sm", isSelected ? "bg-[var(--j2-color-primary-bg-hover)] font-semibold text-[var(--j2-color-primary)] hover:bg-[var(--j2-color-primary-bg-hover)]" : "hover:bg-[var(--j2-color-bg-hover)]"),
|
|
290
|
-
children:
|
|
316
|
+
children: props.optionRender ? props.optionRender({
|
|
317
|
+
...option,
|
|
318
|
+
key: optionValue,
|
|
319
|
+
data: option
|
|
320
|
+
}, { index: flatFilteredOptions.indexOf(option) }) : hasLogo ? /* @__PURE__ */ jsxs("div", {
|
|
291
321
|
className: "flex items-center gap-2",
|
|
292
322
|
children: [/* @__PURE__ */ jsx("div", {
|
|
293
323
|
className: "h-4 shrink-0",
|
|
@@ -305,7 +335,8 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
305
335
|
return option ? option.label : val;
|
|
306
336
|
};
|
|
307
337
|
return /* @__PURE__ */ jsxs("div", {
|
|
308
|
-
|
|
338
|
+
ref: popupRef,
|
|
339
|
+
className: "relative bg-white rounded-lg shadow-md p-2 min-w-[240px]",
|
|
309
340
|
children: [
|
|
310
341
|
/* @__PURE__ */ jsx("div", {
|
|
311
342
|
className: "pb-2 border-b border-j2-border-secondary",
|
|
@@ -323,6 +354,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
323
354
|
size: 16,
|
|
324
355
|
className: "text-j2-text-placeholder"
|
|
325
356
|
}),
|
|
357
|
+
suffix: renderSearchSuffix(),
|
|
326
358
|
allowClear: true
|
|
327
359
|
}, focusTrigger)
|
|
328
360
|
}),
|
|
@@ -393,6 +425,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
393
425
|
onOpenChange: handleOpenChange,
|
|
394
426
|
trigger: ["click"],
|
|
395
427
|
disabled: props.disabled,
|
|
428
|
+
getPopupContainer: props.getPopupContainer,
|
|
396
429
|
popupRender: dropdownPopupRender,
|
|
397
430
|
children: /* @__PURE__ */ jsx(Typography.Link, {
|
|
398
431
|
disabled: props.disabled,
|
|
@@ -448,7 +481,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
448
481
|
[SummarizedSelect_module_default.headlinedSelect]: isHeadline,
|
|
449
482
|
[SummarizedSelect_module_default.fieldSelect]: isField
|
|
450
483
|
}),
|
|
451
|
-
popup: { root: popupClassName }
|
|
484
|
+
popup: { root: cx(popupClassName, { [SummarizedSelect_module_default.hasSearchSuffix]: searchSuffix != null }) }
|
|
452
485
|
},
|
|
453
486
|
variant: antVariant,
|
|
454
487
|
...props
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummarizedSelect.js","names":["styles","Tag","AntdDropdown","_Fragment"],"sources":["../../../../src/components/select/SummarizedSelect.tsx"],"sourcesContent":["import {\n Dropdown as AntdDropdown,\n Select,\n Spin,\n Input,\n SelectProps,\n InputRef,\n Typography,\n} from 'antd'\nimport { DefaultOptionType, type RefSelectProps } from 'antd/es/select'\nimport { Fragment, useState, useMemo, useRef, useEffect } from 'react'\nimport { LoadingOutlined } from '@ant-design/icons'\nimport { CaretDownIcon, MagnifyingGlassIcon } from '@phosphor-icons/react'\nimport { Tag } from '../tag'\nimport cx from 'classnames'\n\nimport styles from './SummarizedSelect.module.css'\n\ntype Option = DefaultOptionType\ntype OptionWithLogo = Option & {\n logo: React.ReactNode\n}\n\ntype GroupOption = {\n label: string\n options: Option[]\n className?: string\n}\n\nexport type SelectOption = Option | GroupOption | OptionWithLogo\n\nexport type SummarizedSelectVariant =\n SelectProps['variant'] | 'headlined' | 'field'\n\nexport type SummarizedSelectTrigger = 'select' | 'dropdown'\n\ntype BaseProps = Omit<\n SelectProps<string | string[], SelectOption>,\n 'mode' | 'value' | 'onChange' | 'variant'\n> & {\n searchPlaceholder?: string\n formControlPlaceholder?: string\n rootClassName?: string\n popupClassName?: string\n /**\n * Look of the `'select'` trigger.\n * - antd's own variants (`'outlined'`, `'borderless'`, ...): the filter-chip\n * look. It sizes to its label and turns into a filled pill once a\n * multiple select has values.\n * - `'headlined'`: a page-title select.\n * - `'field'`: a plain form field. It fills its container and keeps the\n * same look whatever is selected, so it lines up with the inputs and\n * selects around it in a form row.\n */\n variant?: SummarizedSelectVariant\n /**\n * Shape of the control that opens the popup.\n * - `'select'` (default): antd Select, styled by `variant`.\n * - `'dropdown'`: antd Dropdown with a text target (label + caret), for\n * breadcrumbs and inline switchers. Semibold primary text with a duotone\n * caret. A Tailwind weight utility on `rootClassName` (`font-normal`,\n * `font-[450]`) replaces the default; for any other weight, use\n * `triggerWeight`. Ignores `variant`.\n */\n trigger?: SummarizedSelectTrigger\n /**\n * The `'dropdown'` trigger's font weight, e.g. `400` or `'normal'`.\n * Replaces the semibold default and wins over any class. Use it for a\n * weight `rootClassName` can't express as a Tailwind weight utility.\n */\n triggerWeight?: React.CSSProperties['fontWeight']\n defaultOpen?: boolean\n /**\n * While searching, list the matches as one list sorted by label: groups are\n * dropped, and a value that appears in more than one group shows once. Lets\n * a list that repeats options in a shortcut group (Recent, say) above the\n * full list search as a single list. Groups come back when the search is\n * cleared.\n */\n flattenOnSearch?: boolean\n /**\n * `false` opens the `'select'` trigger's list at the top every time instead\n * of scrolled to the selected option, for a list whose first rows matter\n * more than where the selection is. The `'dropdown'` trigger always opens\n * at the top.\n */\n scrollToSelectedOnOpen?: boolean\n /** A line between option groups, above the title of every group after the first. */\n groupDividers?: boolean\n\n loading?: boolean\n}\n\ntype SingleProps = {\n multiple?: false\n renderLabel?: undefined\n value: string | undefined\n onChange: (newValue: string) => void\n}\n\ntype MultiProps = {\n multiple: true\n renderLabel: (count: number) => string\n value: string[]\n onChange: (newValue: string[]) => void\n}\n\nexport type Props = BaseProps & (SingleProps | MultiProps)\n\nconst isGroupOption = (option: SelectOption): option is GroupOption => {\n return 'options' in option\n}\n\nconst getAllOptions = (options: SelectOption[] | undefined): Option[] => {\n if (!options) return []\n\n return options.flatMap((option) =>\n isGroupOption(option) ? option.options : [option]\n )\n}\n\nconst byLabel = (a: Option, b: Option) =>\n String(a.label ?? '').localeCompare(String(b.label ?? ''), undefined, {\n numeric: true,\n sensitivity: 'base',\n })\n\n/** One entry per value, the first one seen, sorted by label. */\nconst flattenAndSort = (options: SelectOption[]): Option[] => {\n const seen = new Set<unknown>()\n return getAllOptions(options)\n .filter((option) => {\n if (seen.has(option.value)) return false\n seen.add(option.value)\n return true\n })\n .sort(byLabel)\n}\n\nconst withGroupDividers = (options: SelectOption[]): SelectOption[] => {\n let groupsSeen = 0\n return options.map((option) => {\n if (!isGroupOption(option)) return option\n groupsSeen += 1\n return groupsSeen === 1\n ? option\n : {\n ...option,\n className: cx(option.className, styles.groupDivider),\n }\n })\n}\n\nconst filterOptions = (\n options: SelectOption[] | undefined,\n searchValue: string\n): SelectOption[] => {\n if (!options) return []\n if (!searchValue) return options\n\n return options\n .map((option) => {\n if (isGroupOption(option)) {\n const filteredSubOptions = option.options.filter((subOption) =>\n subOption.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n return filteredSubOptions.length > 0\n ? { ...option, options: filteredSubOptions }\n : null\n } else {\n return option.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n ? option\n : null\n }\n })\n .filter((option): option is SelectOption => option !== null)\n}\n\n/**\n * An unprefixed Tailwind font-weight utility: a named weight (`font-normal`,\n * `font-bold`) or an arbitrary numeric one (`font-[450]`). Arbitrary values\n * must be numeric, since `font-['Inter']` sets the family. Custom weight names\n * can't be told apart from family names, so they need `triggerWeight`.\n */\nconst WEIGHT_CLASS =\n /(^|\\s)font-(thin|extralight|light|normal|medium|semibold|bold|extrabold|black|\\[\\d+\\])(\\s|$)/\n\nconst hasWeightClass = (className?: string) =>\n Boolean(className && WEIGHT_CLASS.test(className))\n\n/**\n * Puts the option list back at the top each time it opens and each time it is\n * rebuilt for a search. antd scrolls to the selected option from a timeout\n * started in the list's own effect. This wraps the list, so its effect runs\n * after that one and its timeout lands last. It keys off a count of opens, not\n * the open flag: antd does not re-render a closed popup, so the flag it sees\n * can stay `true` from one open to the next.\n */\nconst OpenAtTop = ({\n openCount,\n selectRef,\n children,\n}: {\n openCount: number\n selectRef: React.RefObject<RefSelectProps | null>\n children: React.ReactElement\n}) => {\n useEffect(() => {\n const timeoutId = setTimeout(() => {\n selectRef.current?.scrollTo({ index: 0, align: 'top' })\n })\n return () => clearTimeout(timeoutId)\n }, [openCount, selectRef])\n return children\n}\n\nexport function SummarizedSelect({\n searchPlaceholder,\n formControlPlaceholder,\n loading,\n multiple,\n value,\n onChange,\n options,\n renderLabel,\n rootClassName,\n popupClassName,\n variant,\n trigger = 'select',\n triggerWeight,\n defaultOpen = false,\n flattenOnSearch = false,\n scrollToSelectedOnOpen = true,\n groupDividers = false,\n ...props\n}: Props) {\n const isHeadline = variant === 'headlined'\n const isField = variant === 'field'\n const antVariant = isHeadline ? 'borderless' : isField ? 'outlined' : variant\n const isChip = !isField && variant !== 'underlined' && !isHeadline\n const [searchValue, setSearchValue] = useState('')\n const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0)\n const [isOpen, setIsOpen] = useState(defaultOpen)\n const inputRef = useRef<InputRef>(null)\n const selectRef = useRef<RefSelectProps>(null)\n const measureSpanRef = useRef<HTMLSpanElement>(null)\n const [measuredWidth, setMeasuredWidth] = useState<number>()\n\n const displayText = useMemo(() => {\n if (multiple && value.length > 0) {\n return renderLabel(value.length)\n }\n if (!multiple && value) {\n const option = getAllOptions(options).find((opt) => opt.value === value)\n return option ? String(option.label) : String(value)\n }\n return formControlPlaceholder ?? ''\n }, [multiple, value, options, renderLabel, formControlPlaceholder])\n\n useEffect(() => {\n if (!measureSpanRef.current) return\n // padding (22px = 11px each side) + arrow (18px) + border (6px)\n setMeasuredWidth(Math.ceil(measureSpanRef.current.offsetWidth) + 46)\n }, [displayText])\n\n useEffect(() => {\n if (focusTrigger > 0) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setTimeout(() => {\n // `preventScroll`: on first open the popup is still at its initial\n // spot when this runs, and a plain focus scrolls the page to it.\n inputRef.current?.focus({ cursor: 'end', preventScroll: true })\n }, 100)\n })\n })\n }\n }, [focusTrigger])\n\n const filteredOptions = useMemo(() => {\n const filtered = filterOptions(options, searchValue)\n if (flattenOnSearch && searchValue) return flattenAndSort(filtered)\n return groupDividers ? withGroupDividers(filtered) : filtered\n }, [searchValue, options, flattenOnSearch, groupDividers])\n\n const flatFilteredOptions = useMemo(() => {\n return getAllOptions(filteredOptions)\n }, [filteredOptions])\n\n const allFlatOptions = useMemo(() => {\n return getAllOptions(options)\n }, [options])\n\n const handleTagClose = (removedValue: string) => {\n if (!multiple) return\n\n onChange(value.filter((x) => x !== removedValue))\n }\n\n const handleToggleAll = () => {\n if (!multiple) return\n\n const allFilteredValues = getAllOptions(filteredOptions).map(\n (opt) => opt.value as string\n )\n const someSelected = allFilteredValues.some((val) => value.includes(val))\n\n if (someSelected) {\n onChange(value.filter((val) => !allFilteredValues.includes(val)))\n }\n }\n\n const handleSelectFirstOption = () => {\n if (flatFilteredOptions.length === 0) return\n\n const firstOption = flatFilteredOptions[0]\n if (!firstOption) return\n\n const optionValue = firstOption.value as string\n\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleOptionClick = (optionValue: string) => {\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n // Allow these navigation keys to bubble up to Select's native keyboard handler\n const navigationKeys = ['ArrowUp', 'ArrowDown']\n\n // Handle Enter - select first filtered option (custom behavior)\n if (e.key === 'Enter') {\n e.preventDefault()\n e.stopPropagation()\n handleSelectFirstOption()\n return\n }\n\n // Handle Escape - close dropdown (custom behavior)\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n handleOpenChange(false)\n return\n }\n\n // For arrow keys, prevent cursor movement but allow propagation to Select\n if (navigationKeys.includes(e.key)) {\n e.preventDefault() // Prevents cursor from moving to start/end of input text\n // Do NOT call stopPropagation() - let event bubble to Select component\n return\n }\n\n // For all other keys (including Backspace), stop propagation\n // This prevents backspace from removing tags in multiple mode\n e.stopPropagation()\n }\n\n const optionRender: NonNullable<\n SelectProps<string | string[], SelectOption>['optionRender']\n > = (option) => {\n if ('logo' in option.data && option.data.logo) {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">{option.data.logo}</div>\n <span className=\"overflow-ellipsis overflow-hidden\">\n {option.label}\n </span>\n </div>\n )\n }\n return <div>{option.label}</div>\n }\n\n const popupRender = (menu: React.ReactElement) => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div>\n <div className=\"mb-2 px-2 pb-2 border-b -mx-1 mt-1\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n e.preventDefault()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 ? (\n <div className=\"px-2 pb-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((value) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={value}\n status=\"default\"\n closable\n onClose={() => handleTagClose(value)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(value)}\n >\n {valueToLabel(value)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n ) : null}\n <div\n className={cx(styles.menuContainer, 'rounded-lg', {\n [styles.headlinedMenuContainer]: isHeadline,\n [styles.menuContainerMultiple]: multiple,\n })}\n >\n {/* Keyed on the search so antd rebuilds its option list per\n keystroke. Focusing the search input blurs the Select, antd\n starts a close, cancels it because focus stayed in the popup,\n and never clears its `lockOptions` flag -- a locked list keeps\n showing the options it had when the popup opened. */}\n <Fragment key={searchValue}>\n {scrollToSelectedOnOpen ? (\n menu\n ) : (\n <OpenAtTop openCount={focusTrigger} selectRef={selectRef}>\n {menu}\n </OpenAtTop>\n )}\n </Fragment>\n </div>\n <div className=\"flex justify-between items-center\">\n {multiple && (\n <div className=\"w-full mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n aria-selected=\"false\"\n className={cx(\n 'ant-select-item ant-select-item-option w-full',\n styles.clearAllButton\n )}\n title=\"Clear all\"\n onClick={handleToggleAll}\n >\n <div className=\"ant-select-item-option-content text-center font-semibold\">\n Clear all\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open)\n if (open) {\n // Trigger focus by updating the counter\n setFocusTrigger((prev) => prev + 1)\n } else {\n setSearchValue('')\n }\n }\n\n const renderDropdownOptionRow = (option: Option) => {\n const optionValue = option.value as string\n const isSelected = multiple\n ? value.includes(optionValue)\n : value === optionValue\n const hasLogo = 'logo' in option && (option as OptionWithLogo).logo\n return (\n <div\n key={optionValue}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => handleOptionClick(optionValue)}\n className={cx(\n 'px-3 py-1.5 rounded cursor-pointer text-sm',\n isSelected\n ? 'bg-[var(--j2-color-primary-bg-hover)] font-semibold text-[var(--j2-color-primary)] hover:bg-[var(--j2-color-primary-bg-hover)]'\n : 'hover:bg-[var(--j2-color-bg-hover)]'\n )}\n >\n {hasLogo ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">\n {(option as OptionWithLogo).logo}\n </div>\n <span className=\"overflow-hidden overflow-ellipsis\">\n {option.label}\n </span>\n </div>\n ) : (\n option.label\n )}\n </div>\n )\n }\n\n const dropdownPopupRender = () => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div className=\"bg-white rounded-lg shadow-md p-2 min-w-[240px]\">\n <div className=\"pb-2 border-b border-j2-border-secondary\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 && (\n <div className=\"px-1 pt-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((v) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={v}\n status=\"default\"\n closable\n onClose={() => handleTagClose(v)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(v)}\n >\n {valueToLabel(v)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n )}\n <div\n className=\"max-h-72 overflow-y-auto py-1\"\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n >\n {filteredOptions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-[var(--j2-color-text-secondary)]\">\n No options found\n </div>\n ) : (\n filteredOptions.map((opt) => {\n if (isGroupOption(opt)) {\n return (\n <div key={`group-${opt.label}`} className={opt.className}>\n <div className=\"px-3 pt-2 pb-1 text-xs font-semibold uppercase tracking-wide text-[var(--j2-color-text-tertiary)]\">\n {opt.label}\n </div>\n {opt.options.map(renderDropdownOptionRow)}\n </div>\n )\n }\n return renderDropdownOptionRow(opt)\n })\n )}\n </div>\n {multiple && value.length > 0 && (\n <div className=\"mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n role=\"button\"\n aria-label=\"Clear all\"\n title=\"Clear all\"\n onClick={handleToggleAll}\n className={cx(\n 'text-center font-semibold text-sm py-1.5 rounded cursor-pointer',\n styles.clearAllButton\n )}\n >\n Clear all\n </div>\n </div>\n )}\n </div>\n )\n }\n\n if (trigger === 'dropdown') {\n const hasSelection = multiple ? value.length > 0 : Boolean(value)\n const triggerContent = (\n <span className=\"inline-flex items-center gap-1.5\">\n {hasSelection ? displayText : (formControlPlaceholder ?? 'Select')}\n {loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon weight=\"duotone\" data-testid=\"caret-down\" />\n )}\n </span>\n )\n\n return (\n <AntdDropdown\n open={isOpen}\n onOpenChange={handleOpenChange}\n trigger={['click']}\n disabled={props.disabled}\n popupRender={dropdownPopupRender}\n >\n <Typography.Link\n disabled={props.disabled}\n className={cx(\n 'inline-flex',\n styles.dropdownTrigger,\n triggerWeight === undefined &&\n !hasWeightClass(rootClassName) &&\n 'font-semibold',\n rootClassName\n )}\n style={\n triggerWeight === undefined\n ? undefined\n : { fontWeight: triggerWeight }\n }\n >\n {triggerContent}\n </Typography.Link>\n </AntdDropdown>\n )\n }\n\n return (\n <>\n <span\n ref={measureSpanRef}\n aria-hidden\n style={{\n position: 'absolute',\n visibility: 'hidden',\n whiteSpace: 'nowrap',\n fontSize: 'inherit',\n }}\n >\n {displayText}\n </span>\n <Select<string | string[], SelectOption>\n ref={selectRef}\n open={isOpen}\n showSearch={false}\n style={{ width: isField ? '100%' : measuredWidth }}\n suffixIcon={\n loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon size={14} data-testid=\"caret-down\" />\n )\n }\n placeholder={formControlPlaceholder}\n mode={multiple ? 'multiple' : undefined}\n value={value}\n maxTagCount={0}\n maxTagPlaceholder={multiple ? () => renderLabel(value.length) : value}\n options={filteredOptions}\n onChange={(val) => {\n if (multiple) {\n if (Array.isArray(val)) {\n onChange(val)\n } else {\n throw new Error('Value should be an array in multiple mode')\n }\n } else {\n if (typeof val === 'string') {\n onChange(val)\n } else {\n throw new Error(\n 'Value should be a string in single selection mode'\n )\n }\n }\n }}\n popupRender={popupRender}\n optionRender={optionRender}\n onOpenChange={handleOpenChange}\n classNames={{\n root: cx(rootClassName, styles.summarizedSelect, {\n [styles.hemisphericSelect]: isChip,\n [styles.isActive]: isChip && multiple && value.length > 0,\n [styles.headlinedSelect]: isHeadline,\n [styles.fieldSelect]: isField,\n }),\n popup: { root: popupClassName },\n }}\n variant={antVariant}\n {...props}\n />\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SummarizedSelect.js","names":["styles","Tag","AntdDropdown","_Fragment"],"sources":["../../../../src/components/select/SummarizedSelect.tsx"],"sourcesContent":["import {\n ConfigProvider,\n Dropdown as AntdDropdown,\n Select,\n Spin,\n Input,\n SelectProps,\n InputRef,\n Typography,\n} from 'antd'\nimport { DefaultOptionType, type RefSelectProps } from 'antd/es/select'\nimport { Fragment, useState, useMemo, useRef, useEffect } from 'react'\nimport { LoadingOutlined } from '@ant-design/icons'\nimport { CaretDownIcon, MagnifyingGlassIcon } from '@phosphor-icons/react'\nimport { Tag } from '../tag'\nimport cx from 'classnames'\n\nimport styles from './SummarizedSelect.module.css'\n\ntype Option = DefaultOptionType\ntype OptionWithLogo = Option & {\n logo: React.ReactNode\n}\n\ntype GroupOption = {\n label: string\n options: Option[]\n className?: string\n}\n\nexport type SelectOption = Option | GroupOption | OptionWithLogo\n\nexport type SummarizedSelectVariant =\n SelectProps['variant'] | 'headlined' | 'field'\n\nexport type SummarizedSelectTrigger = 'select' | 'dropdown'\n\ntype BaseProps = Omit<\n SelectProps<string | string[], SelectOption>,\n 'mode' | 'value' | 'onChange' | 'variant'\n> & {\n searchPlaceholder?: string\n formControlPlaceholder?: string\n rootClassName?: string\n popupClassName?: string\n /**\n * Look of the `'select'` trigger.\n * - antd's own variants (`'outlined'`, `'borderless'`, ...): the filter-chip\n * look. It sizes to its label and turns into a filled pill once a\n * multiple select has values.\n * - `'headlined'`: a page-title select.\n * - `'field'`: a plain form field. It fills its container and keeps the\n * same look whatever is selected, so it lines up with the inputs and\n * selects around it in a form row.\n */\n variant?: SummarizedSelectVariant\n /**\n * Shape of the control that opens the popup.\n * - `'select'` (default): antd Select, styled by `variant`.\n * - `'dropdown'`: antd Dropdown with a text target (label + caret), for\n * breadcrumbs and inline switchers. Semibold primary text with a duotone\n * caret. A Tailwind weight utility on `rootClassName` (`font-normal`,\n * `font-[450]`) replaces the default; for any other weight, use\n * `triggerWeight`. Ignores `variant`. Of antd's Select props it takes\n * `optionRender` (for its rows) and `getPopupContainer`.\n */\n trigger?: SummarizedSelectTrigger\n /**\n * The `'dropdown'` trigger's font weight, e.g. `400` or `'normal'`.\n * Replaces the semibold default and wins over any class. Use it for a\n * weight `rootClassName` can't express as a Tailwind weight utility.\n */\n triggerWeight?: React.CSSProperties['fontWeight']\n defaultOpen?: boolean\n /**\n * While searching, list the matches as one list sorted by label: groups are\n * dropped, and a value that appears in more than one group shows once. Lets\n * a list that repeats options in a shortcut group (Recent, say) above the\n * full list search as a single list. Groups come back when the search is\n * cleared.\n */\n flattenOnSearch?: boolean\n /**\n * `false` opens the `'select'` trigger's list at the top every time instead\n * of scrolled to the selected option, for a list whose first rows matter\n * more than where the selection is. The `'dropdown'` trigger always opens\n * at the top.\n */\n scrollToSelectedOnOpen?: boolean\n /** A line between option groups, above the title of every group after the first. */\n groupDividers?: boolean\n /**\n * A control at the right end of the popup's search box, after a short\n * divider, in both triggers. For a control that sets the scope of the search,\n * such as a second select that filters the options. Its own popups open\n * inside this popup, and picking from them or pressing Escape there leaves\n * this popup open with focus back in the search box.\n */\n searchSuffix?: React.ReactNode\n\n loading?: boolean\n}\n\ntype SingleProps = {\n multiple?: false\n renderLabel?: undefined\n value: string | undefined\n onChange: (newValue: string) => void\n}\n\ntype MultiProps = {\n multiple: true\n renderLabel: (count: number) => string\n value: string[]\n onChange: (newValue: string[]) => void\n}\n\nexport type Props = BaseProps & (SingleProps | MultiProps)\n\nconst isGroupOption = (option: SelectOption): option is GroupOption => {\n return 'options' in option\n}\n\nconst getAllOptions = (options: SelectOption[] | undefined): Option[] => {\n if (!options) return []\n\n return options.flatMap((option) =>\n isGroupOption(option) ? option.options : [option]\n )\n}\n\nconst byLabel = (a: Option, b: Option) =>\n String(a.label ?? '').localeCompare(String(b.label ?? ''), undefined, {\n numeric: true,\n sensitivity: 'base',\n })\n\n/** One entry per value, the first one seen, sorted by label. */\nconst flattenAndSort = (options: SelectOption[]): Option[] => {\n const seen = new Set<unknown>()\n return getAllOptions(options)\n .filter((option) => {\n if (seen.has(option.value)) return false\n seen.add(option.value)\n return true\n })\n .sort(byLabel)\n}\n\nconst withGroupDividers = (options: SelectOption[]): SelectOption[] => {\n let groupsSeen = 0\n return options.map((option) => {\n if (!isGroupOption(option)) return option\n groupsSeen += 1\n return groupsSeen === 1\n ? option\n : {\n ...option,\n className: cx(option.className, styles.groupDivider),\n }\n })\n}\n\nconst filterOptions = (\n options: SelectOption[] | undefined,\n searchValue: string\n): SelectOption[] => {\n if (!options) return []\n if (!searchValue) return options\n\n return options\n .map((option) => {\n if (isGroupOption(option)) {\n const filteredSubOptions = option.options.filter((subOption) =>\n subOption.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n return filteredSubOptions.length > 0\n ? { ...option, options: filteredSubOptions }\n : null\n } else {\n return option.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n ? option\n : null\n }\n })\n .filter((option): option is SelectOption => option !== null)\n}\n\n/**\n * An unprefixed Tailwind font-weight utility: a named weight (`font-normal`,\n * `font-bold`) or an arbitrary numeric one (`font-[450]`). Arbitrary values\n * must be numeric, since `font-['Inter']` sets the family. Custom weight names\n * can't be told apart from family names, so they need `triggerWeight`.\n */\nconst WEIGHT_CLASS =\n /(^|\\s)font-(thin|extralight|light|normal|medium|semibold|bold|extrabold|black|\\[\\d+\\])(\\s|$)/\n\nconst hasWeightClass = (className?: string) =>\n Boolean(className && WEIGHT_CLASS.test(className))\n\n/**\n * Puts the option list back at the top each time it opens and each time it is\n * rebuilt for a search. antd scrolls to the selected option from a timeout\n * started in the list's own effect. This wraps the list, so its effect runs\n * after that one and its timeout lands last. It keys off a count of opens, not\n * the open flag: antd does not re-render a closed popup, so the flag it sees\n * can stay `true` from one open to the next.\n */\nconst OpenAtTop = ({\n openCount,\n selectRef,\n children,\n}: {\n openCount: number\n selectRef: React.RefObject<RefSelectProps | null>\n children: React.ReactElement\n}) => {\n useEffect(() => {\n const timeoutId = setTimeout(() => {\n selectRef.current?.scrollTo({ index: 0, align: 'top' })\n })\n return () => clearTimeout(timeoutId)\n }, [openCount, selectRef])\n return children\n}\n\nexport function SummarizedSelect({\n searchPlaceholder,\n formControlPlaceholder,\n loading,\n multiple,\n value,\n onChange,\n options,\n renderLabel,\n rootClassName,\n popupClassName,\n variant,\n trigger = 'select',\n triggerWeight,\n defaultOpen = false,\n flattenOnSearch = false,\n scrollToSelectedOnOpen = true,\n groupDividers = false,\n searchSuffix,\n ...props\n}: Props) {\n const isHeadline = variant === 'headlined'\n const isField = variant === 'field'\n const antVariant = isHeadline ? 'borderless' : isField ? 'outlined' : variant\n const isChip = !isField && variant !== 'underlined' && !isHeadline\n const [searchValue, setSearchValue] = useState('')\n const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0)\n const [isOpen, setIsOpen] = useState(defaultOpen)\n const inputRef = useRef<InputRef>(null)\n const popupRef = useRef<HTMLDivElement>(null)\n const selectRef = useRef<RefSelectProps>(null)\n const measureSpanRef = useRef<HTMLSpanElement>(null)\n const [measuredWidth, setMeasuredWidth] = useState<number>()\n\n const displayText = useMemo(() => {\n if (multiple && value.length > 0) {\n return renderLabel(value.length)\n }\n if (!multiple && value) {\n const option = getAllOptions(options).find((opt) => opt.value === value)\n return option ? String(option.label) : String(value)\n }\n return formControlPlaceholder ?? ''\n }, [multiple, value, options, renderLabel, formControlPlaceholder])\n\n useEffect(() => {\n if (!measureSpanRef.current) return\n // padding (22px = 11px each side) + arrow (18px) + border (6px)\n setMeasuredWidth(Math.ceil(measureSpanRef.current.offsetWidth) + 46)\n }, [displayText])\n\n useEffect(() => {\n if (focusTrigger > 0) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setTimeout(() => {\n // `preventScroll`: on first open the popup is still at its initial\n // spot when this runs, and a plain focus scrolls the page to it.\n inputRef.current?.focus({ cursor: 'end', preventScroll: true })\n }, 100)\n })\n })\n }\n }, [focusTrigger])\n\n const filteredOptions = useMemo(() => {\n const filtered = filterOptions(options, searchValue)\n if (flattenOnSearch && searchValue) return flattenAndSort(filtered)\n return groupDividers ? withGroupDividers(filtered) : filtered\n }, [searchValue, options, flattenOnSearch, groupDividers])\n\n const flatFilteredOptions = useMemo(() => {\n return getAllOptions(filteredOptions)\n }, [filteredOptions])\n\n // The values on show, so the list can be rebuilt when they change while\n // the popup is open (a filter in `searchSuffix`, say). Keyed on content, not\n // on the array, since callers often build `options` afresh each render.\n const shownValues = useMemo(\n () => flatFilteredOptions.map((o) => String(o.value)).join('\\u0000'),\n [flatFilteredOptions]\n )\n\n const allFlatOptions = useMemo(() => {\n return getAllOptions(options)\n }, [options])\n\n const handleTagClose = (removedValue: string) => {\n if (!multiple) return\n\n onChange(value.filter((x) => x !== removedValue))\n }\n\n const handleToggleAll = () => {\n if (!multiple) return\n\n const allFilteredValues = getAllOptions(filteredOptions).map(\n (opt) => opt.value as string\n )\n const someSelected = allFilteredValues.some((val) => value.includes(val))\n\n if (someSelected) {\n onChange(value.filter((val) => !allFilteredValues.includes(val)))\n }\n }\n\n const handleSelectFirstOption = () => {\n if (flatFilteredOptions.length === 0) return\n\n const firstOption = flatFilteredOptions[0]\n if (!firstOption) return\n\n const optionValue = firstOption.value as string\n\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleOptionClick = (optionValue: string) => {\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n // Allow these navigation keys to bubble up to Select's native keyboard handler\n const navigationKeys = ['ArrowUp', 'ArrowDown']\n\n // Handle Enter - select first filtered option (custom behavior)\n if (e.key === 'Enter') {\n e.preventDefault()\n e.stopPropagation()\n handleSelectFirstOption()\n return\n }\n\n // Handle Escape - close dropdown (custom behavior)\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n handleOpenChange(false)\n return\n }\n\n // For arrow keys, prevent cursor movement but allow propagation to Select\n if (navigationKeys.includes(e.key)) {\n e.preventDefault() // Prevents cursor from moving to start/end of input text\n // Do NOT call stopPropagation() - let event bubble to Select component\n return\n }\n\n // For all other keys (including Backspace), stop propagation\n // This prevents backspace from removing tags in multiple mode\n e.stopPropagation()\n }\n\n const optionRender: NonNullable<\n SelectProps<string | string[], SelectOption>['optionRender']\n > = (option) => {\n if ('logo' in option.data && option.data.logo) {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">{option.data.logo}</div>\n <span className=\"overflow-ellipsis overflow-hidden\">\n {option.label}\n </span>\n </div>\n )\n }\n return <div>{option.label}</div>\n }\n\n // A pick or a key in the suffix leaves focus nowhere, which would close this\n // popup, so focus goes back to the search box.\n const focusSearch = () =>\n setTimeout(() => inputRef.current?.focus({ preventScroll: true }))\n\n // Events from the suffix's own popups reach this span through React's tree,\n // although those popups render elsewhere in the DOM.\n const renderSearchSuffix = () =>\n searchSuffix ? (\n <span\n className=\"flex items-center gap-2\"\n // The search box focuses itself on any click inside it, which would\n // pull focus out of the suffix and close its popup as it opens.\n onClick={(e) => {\n e.stopPropagation()\n const target = e.target as HTMLElement\n // A pick closes the suffix's list and focus goes nowhere, which\n // would close this popup too.\n if (target.closest('.ant-select-item-option, [role=\"option\"]')) {\n focusSearch()\n }\n }}\n // Escape closes only the suffix's list, and Enter picks in it. Both\n // are caught on the way down, since a select in the suffix stops them\n // before they would bubble here.\n onKeyDownCapture={(e) => {\n if (e.key === 'Escape' || e.key === 'Enter') focusSearch()\n }}\n // Enter and typing never reach this select.\n onKeyDown={(e) => e.stopPropagation()}\n >\n <span aria-hidden className=\"h-4 w-px bg-j2-border-secondary\" />\n <ConfigProvider\n getPopupContainer={() => popupRef.current ?? document.body}\n >\n {searchSuffix}\n </ConfigProvider>\n </span>\n ) : undefined\n\n const popupRender = (menu: React.ReactElement) => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div ref={popupRef} className={cx({ relative: searchSuffix != null })}>\n <div className=\"mb-2 px-2 pb-2 border-b -mx-1 mt-1\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n e.preventDefault()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n suffix={renderSearchSuffix()}\n allowClear\n />\n </div>\n {multiple && value.length > 0 ? (\n <div className=\"px-2 pb-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((value) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={value}\n status=\"default\"\n closable\n onClose={() => handleTagClose(value)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(value)}\n >\n {valueToLabel(value)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n ) : null}\n <div\n className={cx(styles.menuContainer, 'rounded-lg', {\n [styles.headlinedMenuContainer]: isHeadline,\n [styles.menuContainerMultiple]: multiple,\n })}\n >\n {/* Keyed on the search and the values on show so antd rebuilds its\n option list per keystroke and when the options change. Focusing\n the search input blurs the Select, antd starts a close, cancels\n it because focus stayed in the popup, and never clears its\n `lockOptions` flag -- a locked list keeps showing the options it\n had when the popup opened. */}\n <Fragment key={`${searchValue}\\u0000${shownValues}`}>\n {scrollToSelectedOnOpen ? (\n menu\n ) : (\n <OpenAtTop openCount={focusTrigger} selectRef={selectRef}>\n {menu}\n </OpenAtTop>\n )}\n </Fragment>\n </div>\n <div className=\"flex justify-between items-center\">\n {multiple && (\n <div className=\"w-full mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n aria-selected=\"false\"\n className={cx(\n 'ant-select-item ant-select-item-option w-full',\n styles.clearAllButton\n )}\n title=\"Clear all\"\n onClick={handleToggleAll}\n >\n <div className=\"ant-select-item-option-content text-center font-semibold\">\n Clear all\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open)\n if (open) {\n // Trigger focus by updating the counter\n setFocusTrigger((prev) => prev + 1)\n } else {\n setSearchValue('')\n }\n }\n\n const renderDropdownOptionRow = (option: Option) => {\n const optionValue = option.value as string\n const isSelected = multiple\n ? value.includes(optionValue)\n : value === optionValue\n const hasLogo = 'logo' in option && (option as OptionWithLogo).logo\n return (\n <div\n key={optionValue}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => handleOptionClick(optionValue)}\n className={cx(\n 'px-3 py-1.5 rounded cursor-pointer text-sm',\n isSelected\n ? 'bg-[var(--j2-color-primary-bg-hover)] font-semibold text-[var(--j2-color-primary)] hover:bg-[var(--j2-color-primary-bg-hover)]'\n : 'hover:bg-[var(--j2-color-bg-hover)]'\n )}\n >\n {props.optionRender ? (\n // The same shape antd hands the select trigger's optionRender.\n props.optionRender(\n { ...option, key: optionValue, data: option } as Parameters<\n NonNullable<typeof props.optionRender>\n >[0],\n // Its place in the whole list, as antd counts it.\n { index: flatFilteredOptions.indexOf(option) }\n )\n ) : hasLogo ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">\n {(option as OptionWithLogo).logo}\n </div>\n <span className=\"overflow-hidden overflow-ellipsis\">\n {option.label}\n </span>\n </div>\n ) : (\n option.label\n )}\n </div>\n )\n }\n\n const dropdownPopupRender = () => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div\n ref={popupRef}\n className=\"relative bg-white rounded-lg shadow-md p-2 min-w-[240px]\"\n >\n <div className=\"pb-2 border-b border-j2-border-secondary\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n suffix={renderSearchSuffix()}\n allowClear\n />\n </div>\n {multiple && value.length > 0 && (\n <div className=\"px-1 pt-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((v) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={v}\n status=\"default\"\n closable\n onClose={() => handleTagClose(v)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(v)}\n >\n {valueToLabel(v)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n )}\n <div\n className=\"max-h-72 overflow-y-auto py-1\"\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n >\n {filteredOptions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-[var(--j2-color-text-secondary)]\">\n No options found\n </div>\n ) : (\n filteredOptions.map((opt) => {\n if (isGroupOption(opt)) {\n return (\n <div key={`group-${opt.label}`} className={opt.className}>\n <div className=\"px-3 pt-2 pb-1 text-xs font-semibold uppercase tracking-wide text-[var(--j2-color-text-tertiary)]\">\n {opt.label}\n </div>\n {opt.options.map(renderDropdownOptionRow)}\n </div>\n )\n }\n return renderDropdownOptionRow(opt)\n })\n )}\n </div>\n {multiple && value.length > 0 && (\n <div className=\"mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n role=\"button\"\n aria-label=\"Clear all\"\n title=\"Clear all\"\n onClick={handleToggleAll}\n className={cx(\n 'text-center font-semibold text-sm py-1.5 rounded cursor-pointer',\n styles.clearAllButton\n )}\n >\n Clear all\n </div>\n </div>\n )}\n </div>\n )\n }\n\n if (trigger === 'dropdown') {\n const hasSelection = multiple ? value.length > 0 : Boolean(value)\n const triggerContent = (\n <span className=\"inline-flex items-center gap-1.5\">\n {hasSelection ? displayText : (formControlPlaceholder ?? 'Select')}\n {loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon weight=\"duotone\" data-testid=\"caret-down\" />\n )}\n </span>\n )\n\n return (\n <AntdDropdown\n open={isOpen}\n onOpenChange={handleOpenChange}\n trigger={['click']}\n disabled={props.disabled}\n getPopupContainer={props.getPopupContainer}\n popupRender={dropdownPopupRender}\n >\n <Typography.Link\n disabled={props.disabled}\n className={cx(\n 'inline-flex',\n styles.dropdownTrigger,\n triggerWeight === undefined &&\n !hasWeightClass(rootClassName) &&\n 'font-semibold',\n rootClassName\n )}\n style={\n triggerWeight === undefined\n ? undefined\n : { fontWeight: triggerWeight }\n }\n >\n {triggerContent}\n </Typography.Link>\n </AntdDropdown>\n )\n }\n\n return (\n <>\n <span\n ref={measureSpanRef}\n aria-hidden\n style={{\n position: 'absolute',\n visibility: 'hidden',\n whiteSpace: 'nowrap',\n fontSize: 'inherit',\n }}\n >\n {displayText}\n </span>\n <Select<string | string[], SelectOption>\n ref={selectRef}\n open={isOpen}\n showSearch={false}\n style={{ width: isField ? '100%' : measuredWidth }}\n suffixIcon={\n loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon size={14} data-testid=\"caret-down\" />\n )\n }\n placeholder={formControlPlaceholder}\n mode={multiple ? 'multiple' : undefined}\n value={value}\n maxTagCount={0}\n maxTagPlaceholder={multiple ? () => renderLabel(value.length) : value}\n options={filteredOptions}\n onChange={(val) => {\n if (multiple) {\n if (Array.isArray(val)) {\n onChange(val)\n } else {\n throw new Error('Value should be an array in multiple mode')\n }\n } else {\n if (typeof val === 'string') {\n onChange(val)\n } else {\n throw new Error(\n 'Value should be a string in single selection mode'\n )\n }\n }\n }}\n popupRender={popupRender}\n optionRender={optionRender}\n onOpenChange={handleOpenChange}\n classNames={{\n root: cx(rootClassName, styles.summarizedSelect, {\n [styles.hemisphericSelect]: isChip,\n [styles.isActive]: isChip && multiple && value.length > 0,\n [styles.headlinedSelect]: isHeadline,\n [styles.fieldSelect]: isField,\n }),\n popup: {\n root: cx(popupClassName, {\n [styles.hasSearchSuffix]: searchSuffix != null,\n }),\n },\n }}\n variant={antVariant}\n {...props}\n />\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
// src/components/select/SummarizedSelect.module.css
|
|
2
|
-
var hemisphericSelect = "
|
|
3
|
-
var summarizedSelect = "
|
|
4
|
-
var isActive = "
|
|
5
|
-
var menuContainer = "
|
|
6
|
-
var menuContainerMultiple = "
|
|
7
|
-
var headlinedSelect = "
|
|
8
|
-
var headlinedMenuContainer = "
|
|
9
|
-
var clearAllButton = "
|
|
10
|
-
var dropdownTrigger = "
|
|
11
|
-
var fieldSelect = "
|
|
12
|
-
var groupDivider = "
|
|
2
|
+
var hemisphericSelect = "_hemisphericSelect_1pri4_1";
|
|
3
|
+
var summarizedSelect = "_summarizedSelect_1pri4_9";
|
|
4
|
+
var isActive = "_isActive_1pri4_46";
|
|
5
|
+
var menuContainer = "_menuContainer_1pri4_58";
|
|
6
|
+
var menuContainerMultiple = "_menuContainerMultiple_1pri4_68";
|
|
7
|
+
var headlinedSelect = "_headlinedSelect_1pri4_83";
|
|
8
|
+
var headlinedMenuContainer = "_headlinedMenuContainer_1pri4_135";
|
|
9
|
+
var clearAllButton = "_clearAllButton_1pri4_146";
|
|
10
|
+
var dropdownTrigger = "_dropdownTrigger_1pri4_165";
|
|
11
|
+
var fieldSelect = "_fieldSelect_1pri4_186";
|
|
12
|
+
var groupDivider = "_groupDivider_1pri4_191";
|
|
13
|
+
var hasSearchSuffix = "_hasSearchSuffix_1pri4_198";
|
|
13
14
|
var SummarizedSelect_module_default = {
|
|
14
15
|
hemisphericSelect,
|
|
15
16
|
summarizedSelect,
|
|
@@ -21,13 +22,15 @@ var SummarizedSelect_module_default = {
|
|
|
21
22
|
clearAllButton,
|
|
22
23
|
dropdownTrigger,
|
|
23
24
|
fieldSelect,
|
|
24
|
-
groupDivider
|
|
25
|
+
groupDivider,
|
|
26
|
+
hasSearchSuffix
|
|
25
27
|
};
|
|
26
28
|
exports.clearAllButton = clearAllButton;
|
|
27
29
|
exports.default = SummarizedSelect_module_default;
|
|
28
30
|
exports.dropdownTrigger = dropdownTrigger;
|
|
29
31
|
exports.fieldSelect = fieldSelect;
|
|
30
32
|
exports.groupDivider = groupDivider;
|
|
33
|
+
exports.hasSearchSuffix = hasSearchSuffix;
|
|
31
34
|
exports.headlinedMenuContainer = headlinedMenuContainer;
|
|
32
35
|
exports.headlinedSelect = headlinedSelect;
|
|
33
36
|
exports.hemisphericSelect = hemisphericSelect;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummarizedSelect.module.css.cjs","names":[],"sources":["../../../../src/components/select/SummarizedSelect.module.css"],"sourcesContent":[".hemisphericSelect {\n border-radius: 9999px !important;\n\n :global(.ant-select-placeholder) {\n color: var(--j2-color-primary) !important;\n }\n}\n\n.summarizedSelect {\n :global(.ant-select-suffix) {\n color: var(--j2-color-primary);\n }\n\n :global(.ant-select-selection-item) {\n background: none !important;\n border: none !important;\n padding-inline-end: 0 !important;\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-selection-item-content) {\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-content-item-rest) {\n max-width: 100%;\n }\n\n :global(.ant-select-content-item-suffix) {\n position: absolute;\n width: 1px;\n }\n\n /* antd 6 sizes a multiple select from its in-flow items. With the suffix\n (search input) and the placeholder both absolute, an empty select\n collapses to the font size (18px tall). Hold the row at one item's\n height, which the search input supplied before it was taken out of flow. */\n &:global(.ant-select-multiple) :global(.ant-select-content) {\n min-height: calc(\n var(--ant-select-multi-item-height, 24px) +\n var(--ant-select-internal_fixed_item_margin, 2px) * 2\n );\n }\n}\n\n.isActive {\n background: var(--j2-color-primary) !important;\n\n :global(.ant-select-selection-item-content) {\n color: white !important;\n }\n\n :global(.ant-select-suffix) {\n color: white !important;\n }\n}\n\n.menuContainer :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.menuContainerMultiple :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary-bg-hover) !important;\n}\n\n.menuContainerMultiple\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: inherit;\n}\n\n/*\n * Headlined variant styles\n * The select root owns its border and background in Ant Design 6.\n */\n\n.headlinedSelect:global(.ant-select):global(.ant-select-single) {\n font-size: var(--j2-font-size-heading-2);\n height: 40px;\n width: fit-content !important;\n}\n\n.headlinedSelect:global(.ant-select) {\n background: transparent;\n padding-left: 0;\n padding-right: 4px;\n font-size: var(--j2-font-size-heading-2);\n border-bottom: 1px solid transparent;\n border-radius: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-suffix) {\n height: 16px;\n width: 16px;\n right: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-content) {\n font-weight: 600;\n line-height: 1.3;\n}\n\n/* antd 6 outlines a focused borderless select through\n `:has(input:focus-visible)`, which a text input matches on a mouse click\n too, so every click boxed the headline. The underline below already marks\n focus. `!important` because antd's status variants of that rule reach\n (0,5,1) specificity. */\n.headlinedSelect:global(.ant-select) {\n outline: none !important;\n}\n\n/* Hover state - show underline */\n.headlinedSelect:global(.ant-select):hover {\n border-bottom-color: var(--j2-color-primary);\n}\n\n/* Open/focused state - keep underline and text color */\n.headlinedSelect:global(.ant-select-open),\n.headlinedSelect:global(.ant-select-focused) {\n border-bottom-color: var(--j2-color-primary);\n}\n\n.headlinedSelect:global(.ant-select-open) :global(.ant-select-content),\n.headlinedSelect:global(.ant-select-focused) :global(.ant-select-content) {\n color: inherit;\n}\n\n/* Headline dropdown styles - needs !important to override .menuContainer */\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.clearAllButton {\n color: var(--j2-color-primary);\n}\n\n.clearAllButton:hover {\n background-color: var(--j2-color-primary-bg-hover);\n}\n\n/*\n * Dropdown trigger (`trigger=\"dropdown\"`)\n * Reads as emphasized text with an affordance, not as a link: semibold\n * primary text, no underline, and a fade on hover instead of a color shift.\n * The semibold weight is a utility class added in the component, skipped when\n * the consumer passes its own `font-*` weight. No cascade layers here: this\n * file is compiled into dist/style.css, and Tailwind 3 refuses a stylesheet\n * that declares a components layer without its own Tailwind directives.\n * Color needs `.ant-typography` to beat antd's link color.\n */\n\n.dropdownTrigger:global(.ant-typography),\n.dropdownTrigger:global(.ant-typography):hover,\n.dropdownTrigger:global(.ant-typography):focus {\n color: var(--j2-color-primary);\n text-decoration: none;\n}\n\n.dropdownTrigger:global(.ant-typography):hover {\n opacity: 0.7;\n}\n\n.dropdownTrigger:global(.ant-typography-disabled),\n.dropdownTrigger:global(.ant-typography-disabled):hover {\n color: var(--j2-color-text-disabled);\n opacity: 1;\n}\n\n/*\n * Field variant (`variant=\"field\"`)\n * A form field: full width, the field's own text color, a muted caret.\n */\n.fieldSelect :global(.ant-select-suffix) {\n color: var(--j2-color-text-secondary);\n}\n\n/* A line between option groups, drawn on every group after the first. */\n.groupDivider {\n border-top: 1px solid var(--j2-color-border-secondary);\n border-radius: 0 !important;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"SummarizedSelect.module.css.cjs","names":[],"sources":["../../../../src/components/select/SummarizedSelect.module.css"],"sourcesContent":[".hemisphericSelect {\n border-radius: 9999px !important;\n\n :global(.ant-select-placeholder) {\n color: var(--j2-color-primary) !important;\n }\n}\n\n.summarizedSelect {\n :global(.ant-select-suffix) {\n color: var(--j2-color-primary);\n }\n\n :global(.ant-select-selection-item) {\n background: none !important;\n border: none !important;\n padding-inline-end: 0 !important;\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-selection-item-content) {\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-content-item-rest) {\n max-width: 100%;\n }\n\n :global(.ant-select-content-item-suffix) {\n position: absolute;\n width: 1px;\n }\n\n /* antd 6 sizes a multiple select from its in-flow items. With the suffix\n (search input) and the placeholder both absolute, an empty select\n collapses to the font size (18px tall). Hold the row at one item's\n height, which the search input supplied before it was taken out of flow. */\n &:global(.ant-select-multiple) :global(.ant-select-content) {\n min-height: calc(\n var(--ant-select-multi-item-height, 24px) +\n var(--ant-select-internal_fixed_item_margin, 2px) * 2\n );\n }\n}\n\n.isActive {\n background: var(--j2-color-primary) !important;\n\n :global(.ant-select-selection-item-content) {\n color: white !important;\n }\n\n :global(.ant-select-suffix) {\n color: white !important;\n }\n}\n\n.menuContainer :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.menuContainerMultiple :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary-bg-hover) !important;\n}\n\n.menuContainerMultiple\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: inherit;\n}\n\n/*\n * Headlined variant styles\n * The select root owns its border and background in Ant Design 6.\n */\n\n.headlinedSelect:global(.ant-select):global(.ant-select-single) {\n font-size: var(--j2-font-size-heading-2);\n height: 40px;\n width: fit-content !important;\n}\n\n.headlinedSelect:global(.ant-select) {\n background: transparent;\n padding-left: 0;\n padding-right: 4px;\n font-size: var(--j2-font-size-heading-2);\n border-bottom: 1px solid transparent;\n border-radius: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-suffix) {\n height: 16px;\n width: 16px;\n right: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-content) {\n font-weight: 600;\n line-height: 1.3;\n}\n\n/* antd 6 outlines a focused borderless select through\n `:has(input:focus-visible)`, which a text input matches on a mouse click\n too, so every click boxed the headline. The underline below already marks\n focus. `!important` because antd's status variants of that rule reach\n (0,5,1) specificity. */\n.headlinedSelect:global(.ant-select) {\n outline: none !important;\n}\n\n/* Hover state - show underline */\n.headlinedSelect:global(.ant-select):hover {\n border-bottom-color: var(--j2-color-primary);\n}\n\n/* Open/focused state - keep underline and text color */\n.headlinedSelect:global(.ant-select-open),\n.headlinedSelect:global(.ant-select-focused) {\n border-bottom-color: var(--j2-color-primary);\n}\n\n.headlinedSelect:global(.ant-select-open) :global(.ant-select-content),\n.headlinedSelect:global(.ant-select-focused) :global(.ant-select-content) {\n color: inherit;\n}\n\n/* Headline dropdown styles - needs !important to override .menuContainer */\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.clearAllButton {\n color: var(--j2-color-primary);\n}\n\n.clearAllButton:hover {\n background-color: var(--j2-color-primary-bg-hover);\n}\n\n/*\n * Dropdown trigger (`trigger=\"dropdown\"`)\n * Reads as emphasized text with an affordance, not as a link: semibold\n * primary text, no underline, and a fade on hover instead of a color shift.\n * The semibold weight is a utility class added in the component, skipped when\n * the consumer passes its own `font-*` weight. No cascade layers here: this\n * file is compiled into dist/style.css, and Tailwind 3 refuses a stylesheet\n * that declares a components layer without its own Tailwind directives.\n * Color needs `.ant-typography` to beat antd's link color.\n */\n\n.dropdownTrigger:global(.ant-typography),\n.dropdownTrigger:global(.ant-typography):hover,\n.dropdownTrigger:global(.ant-typography):focus {\n color: var(--j2-color-primary);\n text-decoration: none;\n}\n\n.dropdownTrigger:global(.ant-typography):hover {\n opacity: 0.7;\n}\n\n.dropdownTrigger:global(.ant-typography-disabled),\n.dropdownTrigger:global(.ant-typography-disabled):hover {\n color: var(--j2-color-text-disabled);\n opacity: 1;\n}\n\n/*\n * Field variant (`variant=\"field\"`)\n * A form field: full width, the field's own text color, a muted caret.\n */\n.fieldSelect :global(.ant-select-suffix) {\n color: var(--j2-color-text-secondary);\n}\n\n/* A line between option groups, drawn on every group after the first. */\n.groupDivider {\n border-top: 1px solid var(--j2-color-border-secondary);\n border-radius: 0 !important;\n}\n\n/* A search-box suffix opens its own list inside this popup, and that list can\n hang past the bottom of a short one. */\n.hasSearchSuffix {\n overflow: visible !important;\n}\n"],"mappings":""}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
// src/components/select/SummarizedSelect.module.css
|
|
2
|
-
var hemisphericSelect = "
|
|
3
|
-
var summarizedSelect = "
|
|
4
|
-
var isActive = "
|
|
5
|
-
var menuContainer = "
|
|
6
|
-
var menuContainerMultiple = "
|
|
7
|
-
var headlinedSelect = "
|
|
8
|
-
var headlinedMenuContainer = "
|
|
9
|
-
var clearAllButton = "
|
|
10
|
-
var dropdownTrigger = "
|
|
11
|
-
var fieldSelect = "
|
|
12
|
-
var groupDivider = "
|
|
2
|
+
var hemisphericSelect = "_hemisphericSelect_1pri4_1";
|
|
3
|
+
var summarizedSelect = "_summarizedSelect_1pri4_9";
|
|
4
|
+
var isActive = "_isActive_1pri4_46";
|
|
5
|
+
var menuContainer = "_menuContainer_1pri4_58";
|
|
6
|
+
var menuContainerMultiple = "_menuContainerMultiple_1pri4_68";
|
|
7
|
+
var headlinedSelect = "_headlinedSelect_1pri4_83";
|
|
8
|
+
var headlinedMenuContainer = "_headlinedMenuContainer_1pri4_135";
|
|
9
|
+
var clearAllButton = "_clearAllButton_1pri4_146";
|
|
10
|
+
var dropdownTrigger = "_dropdownTrigger_1pri4_165";
|
|
11
|
+
var fieldSelect = "_fieldSelect_1pri4_186";
|
|
12
|
+
var groupDivider = "_groupDivider_1pri4_191";
|
|
13
|
+
var hasSearchSuffix = "_hasSearchSuffix_1pri4_198";
|
|
13
14
|
var SummarizedSelect_module_default = {
|
|
14
15
|
hemisphericSelect,
|
|
15
16
|
summarizedSelect,
|
|
@@ -21,8 +22,9 @@ var SummarizedSelect_module_default = {
|
|
|
21
22
|
clearAllButton,
|
|
22
23
|
dropdownTrigger,
|
|
23
24
|
fieldSelect,
|
|
24
|
-
groupDivider
|
|
25
|
+
groupDivider,
|
|
26
|
+
hasSearchSuffix
|
|
25
27
|
};
|
|
26
|
-
export { clearAllButton, SummarizedSelect_module_default as default, dropdownTrigger, fieldSelect, groupDivider, headlinedMenuContainer, headlinedSelect, hemisphericSelect, isActive, menuContainer, menuContainerMultiple, summarizedSelect };
|
|
28
|
+
export { clearAllButton, SummarizedSelect_module_default as default, dropdownTrigger, fieldSelect, groupDivider, hasSearchSuffix, headlinedMenuContainer, headlinedSelect, hemisphericSelect, isActive, menuContainer, menuContainerMultiple, summarizedSelect };
|
|
27
29
|
|
|
28
30
|
//# sourceMappingURL=SummarizedSelect.module.css.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummarizedSelect.module.css.js","names":[],"sources":["../../../../src/components/select/SummarizedSelect.module.css"],"sourcesContent":[".hemisphericSelect {\n border-radius: 9999px !important;\n\n :global(.ant-select-placeholder) {\n color: var(--j2-color-primary) !important;\n }\n}\n\n.summarizedSelect {\n :global(.ant-select-suffix) {\n color: var(--j2-color-primary);\n }\n\n :global(.ant-select-selection-item) {\n background: none !important;\n border: none !important;\n padding-inline-end: 0 !important;\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-selection-item-content) {\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-content-item-rest) {\n max-width: 100%;\n }\n\n :global(.ant-select-content-item-suffix) {\n position: absolute;\n width: 1px;\n }\n\n /* antd 6 sizes a multiple select from its in-flow items. With the suffix\n (search input) and the placeholder both absolute, an empty select\n collapses to the font size (18px tall). Hold the row at one item's\n height, which the search input supplied before it was taken out of flow. */\n &:global(.ant-select-multiple) :global(.ant-select-content) {\n min-height: calc(\n var(--ant-select-multi-item-height, 24px) +\n var(--ant-select-internal_fixed_item_margin, 2px) * 2\n );\n }\n}\n\n.isActive {\n background: var(--j2-color-primary) !important;\n\n :global(.ant-select-selection-item-content) {\n color: white !important;\n }\n\n :global(.ant-select-suffix) {\n color: white !important;\n }\n}\n\n.menuContainer :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.menuContainerMultiple :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary-bg-hover) !important;\n}\n\n.menuContainerMultiple\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: inherit;\n}\n\n/*\n * Headlined variant styles\n * The select root owns its border and background in Ant Design 6.\n */\n\n.headlinedSelect:global(.ant-select):global(.ant-select-single) {\n font-size: var(--j2-font-size-heading-2);\n height: 40px;\n width: fit-content !important;\n}\n\n.headlinedSelect:global(.ant-select) {\n background: transparent;\n padding-left: 0;\n padding-right: 4px;\n font-size: var(--j2-font-size-heading-2);\n border-bottom: 1px solid transparent;\n border-radius: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-suffix) {\n height: 16px;\n width: 16px;\n right: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-content) {\n font-weight: 600;\n line-height: 1.3;\n}\n\n/* antd 6 outlines a focused borderless select through\n `:has(input:focus-visible)`, which a text input matches on a mouse click\n too, so every click boxed the headline. The underline below already marks\n focus. `!important` because antd's status variants of that rule reach\n (0,5,1) specificity. */\n.headlinedSelect:global(.ant-select) {\n outline: none !important;\n}\n\n/* Hover state - show underline */\n.headlinedSelect:global(.ant-select):hover {\n border-bottom-color: var(--j2-color-primary);\n}\n\n/* Open/focused state - keep underline and text color */\n.headlinedSelect:global(.ant-select-open),\n.headlinedSelect:global(.ant-select-focused) {\n border-bottom-color: var(--j2-color-primary);\n}\n\n.headlinedSelect:global(.ant-select-open) :global(.ant-select-content),\n.headlinedSelect:global(.ant-select-focused) :global(.ant-select-content) {\n color: inherit;\n}\n\n/* Headline dropdown styles - needs !important to override .menuContainer */\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.clearAllButton {\n color: var(--j2-color-primary);\n}\n\n.clearAllButton:hover {\n background-color: var(--j2-color-primary-bg-hover);\n}\n\n/*\n * Dropdown trigger (`trigger=\"dropdown\"`)\n * Reads as emphasized text with an affordance, not as a link: semibold\n * primary text, no underline, and a fade on hover instead of a color shift.\n * The semibold weight is a utility class added in the component, skipped when\n * the consumer passes its own `font-*` weight. No cascade layers here: this\n * file is compiled into dist/style.css, and Tailwind 3 refuses a stylesheet\n * that declares a components layer without its own Tailwind directives.\n * Color needs `.ant-typography` to beat antd's link color.\n */\n\n.dropdownTrigger:global(.ant-typography),\n.dropdownTrigger:global(.ant-typography):hover,\n.dropdownTrigger:global(.ant-typography):focus {\n color: var(--j2-color-primary);\n text-decoration: none;\n}\n\n.dropdownTrigger:global(.ant-typography):hover {\n opacity: 0.7;\n}\n\n.dropdownTrigger:global(.ant-typography-disabled),\n.dropdownTrigger:global(.ant-typography-disabled):hover {\n color: var(--j2-color-text-disabled);\n opacity: 1;\n}\n\n/*\n * Field variant (`variant=\"field\"`)\n * A form field: full width, the field's own text color, a muted caret.\n */\n.fieldSelect :global(.ant-select-suffix) {\n color: var(--j2-color-text-secondary);\n}\n\n/* A line between option groups, drawn on every group after the first. */\n.groupDivider {\n border-top: 1px solid var(--j2-color-border-secondary);\n border-radius: 0 !important;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"SummarizedSelect.module.css.js","names":[],"sources":["../../../../src/components/select/SummarizedSelect.module.css"],"sourcesContent":[".hemisphericSelect {\n border-radius: 9999px !important;\n\n :global(.ant-select-placeholder) {\n color: var(--j2-color-primary) !important;\n }\n}\n\n.summarizedSelect {\n :global(.ant-select-suffix) {\n color: var(--j2-color-primary);\n }\n\n :global(.ant-select-selection-item) {\n background: none !important;\n border: none !important;\n padding-inline-end: 0 !important;\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-selection-item-content) {\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-content-item-rest) {\n max-width: 100%;\n }\n\n :global(.ant-select-content-item-suffix) {\n position: absolute;\n width: 1px;\n }\n\n /* antd 6 sizes a multiple select from its in-flow items. With the suffix\n (search input) and the placeholder both absolute, an empty select\n collapses to the font size (18px tall). Hold the row at one item's\n height, which the search input supplied before it was taken out of flow. */\n &:global(.ant-select-multiple) :global(.ant-select-content) {\n min-height: calc(\n var(--ant-select-multi-item-height, 24px) +\n var(--ant-select-internal_fixed_item_margin, 2px) * 2\n );\n }\n}\n\n.isActive {\n background: var(--j2-color-primary) !important;\n\n :global(.ant-select-selection-item-content) {\n color: white !important;\n }\n\n :global(.ant-select-suffix) {\n color: white !important;\n }\n}\n\n.menuContainer :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.menuContainerMultiple :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary-bg-hover) !important;\n}\n\n.menuContainerMultiple\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: inherit;\n}\n\n/*\n * Headlined variant styles\n * The select root owns its border and background in Ant Design 6.\n */\n\n.headlinedSelect:global(.ant-select):global(.ant-select-single) {\n font-size: var(--j2-font-size-heading-2);\n height: 40px;\n width: fit-content !important;\n}\n\n.headlinedSelect:global(.ant-select) {\n background: transparent;\n padding-left: 0;\n padding-right: 4px;\n font-size: var(--j2-font-size-heading-2);\n border-bottom: 1px solid transparent;\n border-radius: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-suffix) {\n height: 16px;\n width: 16px;\n right: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-content) {\n font-weight: 600;\n line-height: 1.3;\n}\n\n/* antd 6 outlines a focused borderless select through\n `:has(input:focus-visible)`, which a text input matches on a mouse click\n too, so every click boxed the headline. The underline below already marks\n focus. `!important` because antd's status variants of that rule reach\n (0,5,1) specificity. */\n.headlinedSelect:global(.ant-select) {\n outline: none !important;\n}\n\n/* Hover state - show underline */\n.headlinedSelect:global(.ant-select):hover {\n border-bottom-color: var(--j2-color-primary);\n}\n\n/* Open/focused state - keep underline and text color */\n.headlinedSelect:global(.ant-select-open),\n.headlinedSelect:global(.ant-select-focused) {\n border-bottom-color: var(--j2-color-primary);\n}\n\n.headlinedSelect:global(.ant-select-open) :global(.ant-select-content),\n.headlinedSelect:global(.ant-select-focused) :global(.ant-select-content) {\n color: inherit;\n}\n\n/* Headline dropdown styles - needs !important to override .menuContainer */\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.clearAllButton {\n color: var(--j2-color-primary);\n}\n\n.clearAllButton:hover {\n background-color: var(--j2-color-primary-bg-hover);\n}\n\n/*\n * Dropdown trigger (`trigger=\"dropdown\"`)\n * Reads as emphasized text with an affordance, not as a link: semibold\n * primary text, no underline, and a fade on hover instead of a color shift.\n * The semibold weight is a utility class added in the component, skipped when\n * the consumer passes its own `font-*` weight. No cascade layers here: this\n * file is compiled into dist/style.css, and Tailwind 3 refuses a stylesheet\n * that declares a components layer without its own Tailwind directives.\n * Color needs `.ant-typography` to beat antd's link color.\n */\n\n.dropdownTrigger:global(.ant-typography),\n.dropdownTrigger:global(.ant-typography):hover,\n.dropdownTrigger:global(.ant-typography):focus {\n color: var(--j2-color-primary);\n text-decoration: none;\n}\n\n.dropdownTrigger:global(.ant-typography):hover {\n opacity: 0.7;\n}\n\n.dropdownTrigger:global(.ant-typography-disabled),\n.dropdownTrigger:global(.ant-typography-disabled):hover {\n color: var(--j2-color-text-disabled);\n opacity: 1;\n}\n\n/*\n * Field variant (`variant=\"field\"`)\n * A form field: full width, the field's own text color, a muted caret.\n */\n.fieldSelect :global(.ant-select-suffix) {\n color: var(--j2-color-text-secondary);\n}\n\n/* A line between option groups, drawn on every group after the first. */\n.groupDivider {\n border-top: 1px solid var(--j2-color-border-secondary);\n border-radius: 0 !important;\n}\n\n/* A search-box suffix opens its own list inside this popup, and that list can\n hang past the bottom of a short one. */\n.hasSearchSuffix {\n overflow: visible !important;\n}\n"],"mappings":""}
|
package/dist/style.css
CHANGED
|
@@ -792,7 +792,7 @@
|
|
|
792
792
|
color: white;
|
|
793
793
|
font-weight: 700;
|
|
794
794
|
}
|
|
795
|
-
.
|
|
795
|
+
._hemisphericSelect_1pri4_1 {
|
|
796
796
|
border-radius: 9999px !important;
|
|
797
797
|
|
|
798
798
|
.ant-select-placeholder {
|
|
@@ -800,7 +800,7 @@
|
|
|
800
800
|
}
|
|
801
801
|
}
|
|
802
802
|
|
|
803
|
-
.
|
|
803
|
+
._summarizedSelect_1pri4_9 {
|
|
804
804
|
.ant-select-suffix {
|
|
805
805
|
color: var(--j2-color-primary);
|
|
806
806
|
}
|
|
@@ -837,7 +837,7 @@
|
|
|
837
837
|
}
|
|
838
838
|
}
|
|
839
839
|
|
|
840
|
-
.
|
|
840
|
+
._isActive_1pri4_46 {
|
|
841
841
|
background: var(--j2-color-primary) !important;
|
|
842
842
|
|
|
843
843
|
.ant-select-selection-item-content {
|
|
@@ -849,21 +849,21 @@
|
|
|
849
849
|
}
|
|
850
850
|
}
|
|
851
851
|
|
|
852
|
-
.
|
|
852
|
+
._menuContainer_1pri4_58 .ant-select-item-option-selected {
|
|
853
853
|
background: var(--j2-color-primary) !important;
|
|
854
854
|
}
|
|
855
855
|
|
|
856
|
-
.
|
|
856
|
+
._menuContainer_1pri4_58
|
|
857
857
|
.ant-select-item-option-selected
|
|
858
858
|
.ant-select-item-option-content {
|
|
859
859
|
color: white;
|
|
860
860
|
}
|
|
861
861
|
|
|
862
|
-
.
|
|
862
|
+
._menuContainerMultiple_1pri4_68 .ant-select-item-option-selected {
|
|
863
863
|
background: var(--j2-color-primary-bg-hover) !important;
|
|
864
864
|
}
|
|
865
865
|
|
|
866
|
-
.
|
|
866
|
+
._menuContainerMultiple_1pri4_68
|
|
867
867
|
.ant-select-item-option-selected
|
|
868
868
|
.ant-select-item-option-content {
|
|
869
869
|
color: inherit;
|
|
@@ -874,14 +874,14 @@
|
|
|
874
874
|
* The select root owns its border and background in Ant Design 6.
|
|
875
875
|
*/
|
|
876
876
|
|
|
877
|
-
.
|
|
877
|
+
._headlinedSelect_1pri4_83.ant-select.ant-select-single {
|
|
878
878
|
font-size: var(--j2-font-size-heading-2);
|
|
879
879
|
height: 40px;
|
|
880
880
|
width: -moz-fit-content !important;
|
|
881
881
|
width: fit-content !important;
|
|
882
882
|
}
|
|
883
883
|
|
|
884
|
-
.
|
|
884
|
+
._headlinedSelect_1pri4_83.ant-select {
|
|
885
885
|
background: transparent;
|
|
886
886
|
padding-left: 0;
|
|
887
887
|
padding-right: 4px;
|
|
@@ -890,13 +890,13 @@
|
|
|
890
890
|
border-radius: 0;
|
|
891
891
|
}
|
|
892
892
|
|
|
893
|
-
.
|
|
893
|
+
._headlinedSelect_1pri4_83.ant-select .ant-select-suffix {
|
|
894
894
|
height: 16px;
|
|
895
895
|
width: 16px;
|
|
896
896
|
right: 0;
|
|
897
897
|
}
|
|
898
898
|
|
|
899
|
-
.
|
|
899
|
+
._headlinedSelect_1pri4_83.ant-select .ant-select-content {
|
|
900
900
|
font-weight: 600;
|
|
901
901
|
line-height: 1.3;
|
|
902
902
|
}
|
|
@@ -906,43 +906,43 @@
|
|
|
906
906
|
too, so every click boxed the headline. The underline below already marks
|
|
907
907
|
focus. `!important` because antd's status variants of that rule reach
|
|
908
908
|
(0,5,1) specificity. */
|
|
909
|
-
.
|
|
909
|
+
._headlinedSelect_1pri4_83.ant-select {
|
|
910
910
|
outline: none !important;
|
|
911
911
|
}
|
|
912
912
|
|
|
913
913
|
/* Hover state - show underline */
|
|
914
|
-
.
|
|
914
|
+
._headlinedSelect_1pri4_83.ant-select:hover {
|
|
915
915
|
border-bottom-color: var(--j2-color-primary);
|
|
916
916
|
}
|
|
917
917
|
|
|
918
918
|
/* Open/focused state - keep underline and text color */
|
|
919
|
-
.
|
|
920
|
-
.
|
|
919
|
+
._headlinedSelect_1pri4_83.ant-select-open,
|
|
920
|
+
._headlinedSelect_1pri4_83.ant-select-focused {
|
|
921
921
|
border-bottom-color: var(--j2-color-primary);
|
|
922
922
|
}
|
|
923
923
|
|
|
924
|
-
.
|
|
925
|
-
.
|
|
924
|
+
._headlinedSelect_1pri4_83.ant-select-open .ant-select-content,
|
|
925
|
+
._headlinedSelect_1pri4_83.ant-select-focused .ant-select-content {
|
|
926
926
|
color: inherit;
|
|
927
927
|
}
|
|
928
928
|
|
|
929
929
|
/* Headline dropdown styles - needs !important to override .menuContainer */
|
|
930
|
-
.
|
|
930
|
+
._menuContainer_1pri4_58._headlinedMenuContainer_1pri4_135
|
|
931
931
|
.ant-select-item-option-selected {
|
|
932
932
|
background: var(--j2-color-primary) !important;
|
|
933
933
|
}
|
|
934
934
|
|
|
935
|
-
.
|
|
935
|
+
._menuContainer_1pri4_58._headlinedMenuContainer_1pri4_135
|
|
936
936
|
.ant-select-item-option-selected
|
|
937
937
|
.ant-select-item-option-content {
|
|
938
938
|
color: white;
|
|
939
939
|
}
|
|
940
940
|
|
|
941
|
-
.
|
|
941
|
+
._clearAllButton_1pri4_146 {
|
|
942
942
|
color: var(--j2-color-primary);
|
|
943
943
|
}
|
|
944
944
|
|
|
945
|
-
.
|
|
945
|
+
._clearAllButton_1pri4_146:hover {
|
|
946
946
|
background-color: var(--j2-color-primary-bg-hover);
|
|
947
947
|
}
|
|
948
948
|
|
|
@@ -957,19 +957,19 @@
|
|
|
957
957
|
* Color needs `.ant-typography` to beat antd's link color.
|
|
958
958
|
*/
|
|
959
959
|
|
|
960
|
-
.
|
|
961
|
-
.
|
|
962
|
-
.
|
|
960
|
+
._dropdownTrigger_1pri4_165.ant-typography,
|
|
961
|
+
._dropdownTrigger_1pri4_165.ant-typography:hover,
|
|
962
|
+
._dropdownTrigger_1pri4_165.ant-typography:focus {
|
|
963
963
|
color: var(--j2-color-primary);
|
|
964
964
|
text-decoration: none;
|
|
965
965
|
}
|
|
966
966
|
|
|
967
|
-
.
|
|
967
|
+
._dropdownTrigger_1pri4_165.ant-typography:hover {
|
|
968
968
|
opacity: 0.7;
|
|
969
969
|
}
|
|
970
970
|
|
|
971
|
-
.
|
|
972
|
-
.
|
|
971
|
+
._dropdownTrigger_1pri4_165.ant-typography-disabled,
|
|
972
|
+
._dropdownTrigger_1pri4_165.ant-typography-disabled:hover {
|
|
973
973
|
color: var(--j2-color-text-disabled);
|
|
974
974
|
opacity: 1;
|
|
975
975
|
}
|
|
@@ -978,15 +978,21 @@
|
|
|
978
978
|
* Field variant (`variant="field"`)
|
|
979
979
|
* A form field: full width, the field's own text color, a muted caret.
|
|
980
980
|
*/
|
|
981
|
-
.
|
|
981
|
+
._fieldSelect_1pri4_186 .ant-select-suffix {
|
|
982
982
|
color: var(--j2-color-text-secondary);
|
|
983
983
|
}
|
|
984
984
|
|
|
985
985
|
/* A line between option groups, drawn on every group after the first. */
|
|
986
|
-
.
|
|
986
|
+
._groupDivider_1pri4_191 {
|
|
987
987
|
border-top: 1px solid var(--j2-color-border-secondary);
|
|
988
988
|
border-radius: 0 !important;
|
|
989
989
|
}
|
|
990
|
+
|
|
991
|
+
/* A search-box suffix opens its own list inside this popup, and that list can
|
|
992
|
+
hang past the bottom of a short one. */
|
|
993
|
+
._hasSearchSuffix_1pri4_198 {
|
|
994
|
+
overflow: visible !important;
|
|
995
|
+
}
|
|
990
996
|
._pill_16f8w_1 {
|
|
991
997
|
display: inline-flex;
|
|
992
998
|
align-items: center;
|