pixelize-design-library 2.4.2-beta.46 → 2.4.2-beta.48

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +76 -3
  2. package/COMPONENT-GOTCHAS.md +76 -7
  3. package/dist/Components/Common/chipTriggerSize.d.ts +10 -0
  4. package/dist/Components/Common/chipTriggerSize.js +15 -0
  5. package/dist/Components/Dropdown/DropDown.js +10 -8
  6. package/dist/Components/SearchSelect/SearchSelect.js +66 -20
  7. package/dist/Components/SearchSelect/SearchSelectProps.d.ts +5 -1
  8. package/dist/Components/SearchSelect/searchSelectSize.d.ts +0 -5
  9. package/dist/Components/SearchSelect/searchSelectSize.js +0 -12
  10. package/dist/Components/Select/SelectNative.d.ts +2 -0
  11. package/dist/Components/Select/SelectPopup.js +104 -43
  12. package/dist/Components/Select/SelectProps.d.ts +4 -0
  13. package/dist/Components/Select/optionRowInk.d.ts +4 -0
  14. package/dist/Components/Select/optionRowInk.js +12 -1
  15. package/dist/Components/SelectSearch/SelectSearch.js +8 -4
  16. package/dist/Components/SelectV2/SelectV2.d.ts +2 -9
  17. package/dist/Components/SelectV2/SelectV2.js +2 -10
  18. package/dist/Components/Switch/Switch.d.ts +1 -1
  19. package/dist/Components/Switch/Switch.js +4 -2
  20. package/dist/Components/Table/Table.js +6 -7
  21. package/dist/Components/Table/TableProps.d.ts +9 -1
  22. package/dist/Components/Table/components/Pagination.js +8 -5
  23. package/dist/Components/Table/components/TableBody.d.ts +2 -1
  24. package/dist/Components/Table/components/TableBody.js +82 -15
  25. package/dist/Components/Table/components/TableHeader.d.ts +1 -1
  26. package/dist/Components/Table/components/TableHeader.js +8 -9
  27. package/dist/Components/Table/components/rowMetrics.d.ts +0 -1
  28. package/dist/Components/Table/components/rowMetrics.js +1 -2
  29. package/dist/Components/Table/filters/CompactSelect.js +6 -3
  30. package/dist/Components/Table/hooks/useTable.d.ts +5 -1
  31. package/dist/Components/Table/hooks/useTable.js +43 -7
  32. package/dist/Theme/chakra/Menu.styles.d.ts +6 -0
  33. package/dist/Theme/chakra/Menu.styles.js +8 -0
  34. package/dist/Theme/chakra/componentStyles.d.ts +6 -0
  35. package/dist/Theme/tokens/builders/outlineRung.d.ts +2 -0
  36. package/dist/Theme/tokens/builders/outlineRung.js +14 -1
  37. package/dist/Theme/tokens/builders/rowStates.js +3 -4
  38. package/dist/Theme/tokens/primitives/optionRowSizes.d.ts +20 -0
  39. package/dist/Theme/tokens/primitives/optionRowSizes.js +29 -0
  40. package/dist/esm/Components/Common/chipTriggerSize.js +11 -0
  41. package/dist/esm/Components/Dropdown/DropDown.js +10 -8
  42. package/dist/esm/Components/SearchSelect/SearchSelect.js +66 -20
  43. package/dist/esm/Components/SearchSelect/searchSelectSize.js +0 -12
  44. package/dist/esm/Components/Select/SelectPopup.js +105 -44
  45. package/dist/esm/Components/Select/optionRowInk.js +9 -0
  46. package/dist/esm/Components/SelectSearch/SelectSearch.js +9 -5
  47. package/dist/esm/Components/SelectV2/SelectV2.js +2 -9
  48. package/dist/esm/Components/Switch/Switch.js +4 -2
  49. package/dist/esm/Components/Table/Table.js +6 -7
  50. package/dist/esm/Components/Table/components/Pagination.js +8 -5
  51. package/dist/esm/Components/Table/components/TableBody.js +81 -16
  52. package/dist/esm/Components/Table/components/TableHeader.js +8 -9
  53. package/dist/esm/Components/Table/components/rowMetrics.js +0 -1
  54. package/dist/esm/Components/Table/filters/CompactSelect.js +7 -4
  55. package/dist/esm/Components/Table/hooks/useTable.js +44 -8
  56. package/dist/esm/Theme/chakra/Menu.styles.js +8 -0
  57. package/dist/esm/Theme/tokens/builders/outlineRung.js +12 -0
  58. package/dist/esm/Theme/tokens/builders/rowStates.js +4 -5
  59. package/dist/esm/Theme/tokens/primitives/optionRowSizes.js +25 -0
  60. package/dist/esm/index.js +2 -0
  61. package/dist/index.d.ts +1 -0
  62. package/dist/index.js +9 -4
  63. package/package.json +1 -1
@@ -44,10 +44,12 @@ const useCustomTheme_1 = require("../../Theme/useCustomTheme");
44
44
  const focusRing_styles_1 = require("../../Theme/chakra/focusRing.styles");
45
45
  const rowStates_1 = require("../../Theme/tokens/builders/rowStates");
46
46
  const optionRowInk_1 = require("./optionRowInk");
47
+ const optionRowSizes_1 = require("../../Theme/tokens/primitives/optionRowSizes");
47
48
  const scrollbar_1 = require("../../Theme/tokens/builders/scrollbar");
48
49
  const controlSizes_1 = require("../../Theme/tokens/primitives/controlSizes");
49
50
  const motion_1 = require("../../Theme/tokens/primitives/motion");
50
51
  const motion_2 = require("../../Theme/chakra/motion");
52
+ const chipTriggerSize_1 = require("../Common/chipTriggerSize");
51
53
  const fieldStyles_1 = require("../Common/fieldStyles");
52
54
  const useFieldIds_1 = require("../Common/useFieldIds");
53
55
  const FieldMessage_1 = __importDefault(require("../Common/FieldMessage"));
@@ -59,17 +61,7 @@ const CHEVRON_TRANSITION = (0, motion_1.transitionFor)(["transform"], "base");
59
61
  const PAGE_STEP = 8;
60
62
  const LOAD_MORE_THRESHOLD_PX = 8;
61
63
  const DEFAULT_MAX_VISIBLE_CHIPS = 6;
62
- // NOTE: approximate single-row height (px 2.5 + ~13px text); used only to window `virtualizeAfter`, never for layout.
63
- const VIRTUAL_ROW_HEIGHT_PX = 34;
64
64
  const VIRTUAL_OVERSCAN = 4;
65
- const CHIP_TAG_HEIGHT_PX = { xs: 20, sm: 24 };
66
- const controlHeightPx = (size) => parseFloat(controlSizes_1.CONTROL_SIZES[size].height) * 16;
67
- const chipRowPaddingY = (size, chipSize) => `${(controlHeightPx(size) - CHIP_TAG_HEIGHT_PX[chipSize]) / 2 / 16}rem`;
68
- const chipTriggerSizeStyles = (size, hasChips, chipSize = "sm") => {
69
- const spec = controlSizes_1.CONTROL_SIZES[size];
70
- const base = { minH: spec.height, fontSize: spec.fontSize, px: spec.paddingX };
71
- return hasChips ? { ...base, py: chipRowPaddingY(size, chipSize) } : { ...base, h: spec.height };
72
- };
73
65
  const asIdSet = (values) => new Set((values !== null && values !== void 0 ? values : []).map((v) => v.toString()));
74
66
  /** Regression-guarded id scheme — tickets e2e (`e2e/tests/helpers/selectV2.ts`) resolves it verbatim. */
75
67
  const optionDomId = (listboxId, id) => `${listboxId}-option-${id.toString().replace(/[^a-zA-Z0-9_-]/g, "-")}`;
@@ -77,11 +69,11 @@ const parseRemToPx = (value, fallbackPx) => {
77
69
  const match = /^(\d*\.?\d+)rem$/.exec(value);
78
70
  return match ? parseFloat(match[1]) * 16 : fallbackPx;
79
71
  };
80
- const OptionRow = react_1.default.memo(function OptionRow({ option, index, listboxId, isSelected, isActive, isMulti, theme, backgrounds, renderOption, onSelect, onActivate, }) {
72
+ const OptionRow = react_1.default.memo(function OptionRow({ option, index, listboxId, isSelected, isActive, isMulti, theme, backgrounds, spec, renderOption, onSelect, onActivate, }) {
81
73
  const isSingleSelected = isSelected && !isMulti;
82
74
  const selectedBg = isActive ? backgrounds.selectedActive : backgrounds.selected;
83
75
  const restBg = isActive ? backgrounds.active : "transparent";
84
- return ((0, jsx_runtime_1.jsxs)(react_2.Box, { id: optionDomId(listboxId, option.id), "data-index": index, role: "option", "aria-selected": isSelected, "aria-disabled": option.isDisabled, onMouseEnter: () => onActivate(index), onClick: () => onSelect(option), mx: 1.5, px: 2.5, py: 1.5, borderRadius: "md", cursor: option.isDisabled ? "not-allowed" : "pointer", opacity: option.isDisabled ? 0.4 : 1, display: "flex", alignItems: "center", gap: 2, fontSize: "0.8125rem", fontWeight: isSingleSelected ? 600 : 400, color: (0, optionRowInk_1.optionRowInk)(theme.colors, isSingleSelected), bg: isSingleSelected ? selectedBg : restBg, transition: ROW_TRANSITION, sx: (0, motion_2.reducedMotionSx)(), children: [isMulti ? ((0, jsx_runtime_1.jsx)(react_2.Checkbox, { id: `${optionDomId(listboxId, option.id)}-checkbox`, isChecked: isSelected, isDisabled: option.isDisabled, pointerEvents: "none", tabIndex: -1 })) : null, renderOption ? ((0, jsx_runtime_1.jsx)(react_2.Box, { flex: 1, minW: 0, children: renderOption(option, { isSelected, isActive }) })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [option.icon ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "inline-flex", flexShrink: 0, children: option.icon })) : null, (0, jsx_runtime_1.jsxs)(react_2.Box, { flex: 1, minW: 0, isTruncated: true, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", isTruncated: true, children: option.label }), option.description ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "block", fontSize: "0.75rem", color: theme.colors.textMuted, isTruncated: true, children: option.description })) : null] })] })), isSingleSelected ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: lucide_react_1.Check, size: 16, color: theme.colors.accentText, flexShrink: 0 })) : null] }));
76
+ return ((0, jsx_runtime_1.jsxs)(react_2.Box, { id: optionDomId(listboxId, option.id), "data-index": index, role: "option", "aria-selected": isSelected, "aria-disabled": option.isDisabled, onMouseEnter: () => onActivate(index), onClick: () => onSelect(option), mx: spec.mx, px: spec.px, py: spec.py, minH: spec.minH, borderRadius: "md", cursor: option.isDisabled ? "not-allowed" : "pointer", opacity: option.isDisabled ? 0.4 : 1, display: "flex", alignItems: "center", gap: spec.gap, fontSize: spec.fontSize, fontWeight: (0, optionRowInk_1.optionRowWeight)(isSingleSelected), color: (0, optionRowInk_1.optionRowInk)(theme.colors, isSingleSelected), bg: isSingleSelected ? selectedBg : restBg, transition: ROW_TRANSITION, sx: (0, motion_2.reducedMotionSx)(), children: [isMulti ? ((0, jsx_runtime_1.jsx)(react_2.Checkbox, { id: `${optionDomId(listboxId, option.id)}-checkbox`, isChecked: isSelected, isDisabled: option.isDisabled, pointerEvents: "none", tabIndex: -1 })) : null, renderOption ? ((0, jsx_runtime_1.jsx)(react_2.Box, { flex: 1, minW: 0, children: renderOption(option, { isSelected, isActive }) })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [option.icon ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "inline-flex", flexShrink: 0, children: option.icon })) : null, (0, jsx_runtime_1.jsxs)(react_2.Box, { flex: 1, minW: 0, isTruncated: true, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", isTruncated: true, children: option.label }), option.description ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "block", fontSize: spec.descriptionFontSize, color: (0, optionRowInk_1.optionRowDescriptionInk)(theme.colors), isTruncated: true, children: option.description })) : null] })] })), isSingleSelected ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: lucide_react_1.Check, size: spec.iconSize, color: theme.colors.accentText, flexShrink: 0 })) : null] }));
85
77
  });
86
78
  const buildGroupedRows = (options) => {
87
79
  const rows = [];
@@ -99,7 +91,7 @@ const buildGroupedRows = (options) => {
99
91
  /** The unified `Select`'s popup mode (`native={false}`) — absorbs SelectV2's behaviour, plus clear/create/groups/virtualization. */
100
92
  const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
101
93
  var _a, _b, _c, _d;
102
- const { options = [], id, name, placeholder = "Select Option", label, error = false, errorMessage, helperText, isDisabled = false, isReadOnly = false, isRequired = false, isInformation = false, informationMessage, size = controlSizes_1.DEFAULT_CONTROL_SIZE, isSearchable = true, width, formControlStyle, onBlur, onFocus, renderOption, renderValue, maxMenuHeight = "16rem", defaultOpen = false, isLoading = false, loadingText = "Loading...", onLoadMore, onSearchChange, searchValue, defaultSearchValue, searchDebounceMs = 0, isClearable = false, onClear, noOptionsMessage, onCreate, createLabel, virtualizeAfter, "data-testid": dataTestId, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, } = props;
94
+ const { options = [], id, name, placeholder = "Select Option", label, error = false, errorMessage, helperText, isDisabled = false, isReadOnly = false, isRequired = false, isInformation = false, informationMessage, size = controlSizes_1.DEFAULT_CONTROL_SIZE, isSearchable = true, width, formControlStyle, onBlur, onFocus, renderOption, renderValue, maxMenuHeight = "16rem", defaultOpen = false, isLoading = false, loadingText = "Loading...", onLoadMore, hasMore, onSearchChange, searchValue, defaultSearchValue, searchDebounceMs = 0, filterOptions, isClearable = false, onClear, noOptionsMessage, onCreate, createLabel, virtualizeAfter, "data-testid": dataTestId, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, } = props;
103
95
  const theme = (0, useCustomTheme_1.useCustomTheme)();
104
96
  const { colors } = theme;
105
97
  const { isOpen, onOpen, onClose } = (0, react_2.useDisclosure)({ defaultIsOpen: defaultOpen });
@@ -109,6 +101,8 @@ const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
109
101
  const mergedTriggerRef = (0, react_2.useMergeRefs)(triggerRef, ref);
110
102
  const filterInputRef = (0, react_1.useRef)(null);
111
103
  const listRef = (0, react_1.useRef)(null);
104
+ const lastActiveIndex = (0, react_1.useRef)(-1);
105
+ const wasVirtualized = (0, react_1.useRef)(false);
112
106
  const [triggerWidth, setTriggerWidth] = (0, react_1.useState)(0);
113
107
  const ids = (0, useFieldIds_1.useFieldIds)(id, { error, errorMessage, helperText });
114
108
  const listboxId = `${ids.inputId}-listbox`;
@@ -126,13 +120,28 @@ const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
126
120
  const selectedIds = (0, react_1.useMemo)(() => props.isMulti
127
121
  ? asIdSet(currentValue)
128
122
  : asIdSet(currentValue !== undefined ? [currentValue] : undefined), [props.isMulti, currentValue]);
129
- const selectedOptions = (0, react_1.useMemo)(() => options.filter((option) => selectedIds.has(option.id.toString())), [options, selectedIds]);
123
+ const selectionCacheRef = (0, react_1.useRef)(new Map());
124
+ const selectedOptions = (0, react_1.useMemo)(() => {
125
+ const cache = selectionCacheRef.current;
126
+ options.forEach((option) => {
127
+ if (selectedIds.has(option.id.toString()))
128
+ cache.set(option.id.toString(), option);
129
+ });
130
+ Array.from(cache.keys()).forEach((cachedId) => {
131
+ if (!selectedIds.has(cachedId))
132
+ cache.delete(cachedId);
133
+ });
134
+ return Array.from(selectedIds)
135
+ .map((selectedId) => cache.get(selectedId))
136
+ .filter((option) => option !== undefined);
137
+ }, [options, selectedIds]);
138
+ const shouldFilterLocally = filterOptions !== null && filterOptions !== void 0 ? filterOptions : !onSearchChange;
130
139
  const filteredOptions = (0, react_1.useMemo)(() => {
131
- if (!isSearchable || !currentSearch.trim())
140
+ if (!isSearchable || !currentSearch.trim() || !shouldFilterLocally)
132
141
  return options;
133
142
  const needle = currentSearch.trim().toLowerCase();
134
143
  return options.filter((option) => option.label.toString().toLowerCase().includes(needle));
135
- }, [options, currentSearch, isSearchable]);
144
+ }, [options, currentSearch, isSearchable, shouldFilterLocally]);
136
145
  const hasGroups = (0, react_1.useMemo)(() => options.some((option) => option.group), [options]);
137
146
  const resetAndClose = (0, react_1.useCallback)((opts) => {
138
147
  if (props.isMulti && (opts === null || opts === void 0 ? void 0 : opts.keepOpenForMulti))
@@ -154,15 +163,19 @@ const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
154
163
  : currentValue;
155
164
  setActiveIndex(filteredOptions.findIndex((option) => option.id.toString() === (firstSelected === null || firstSelected === void 0 ? void 0 : firstSelected.toString())));
156
165
  };
166
+ const selectedIdsRef = (0, react_1.useRef)(selectedIds);
167
+ selectedIdsRef.current = selectedIds;
168
+ const selectedOptionsRef = (0, react_1.useRef)(selectedOptions);
169
+ selectedOptionsRef.current = selectedOptions;
157
170
  const handleSelect = (0, react_1.useCallback)((option) => {
158
171
  var _a, _b;
159
172
  if (option.isDisabled)
160
173
  return;
161
174
  if (props.isMulti) {
162
- const alreadySelected = selectedIds.has(option.id.toString());
175
+ const alreadySelected = selectedIdsRef.current.has(option.id.toString());
163
176
  const next = alreadySelected
164
- ? selectedOptions.filter((selected) => selected.id.toString() !== option.id.toString())
165
- : [...selectedOptions, option];
177
+ ? selectedOptionsRef.current.filter((selected) => selected.id.toString() !== option.id.toString())
178
+ : [...selectedOptionsRef.current, option];
166
179
  if (!isValueControlled)
167
180
  setUncontrolledValue(next.map((o) => o.id));
168
181
  props.onChange(next);
@@ -177,7 +190,7 @@ const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
177
190
  (_b = triggerRef.current) === null || _b === void 0 ? void 0 : _b.focus();
178
191
  },
179
192
  // eslint-disable-next-line react-hooks/exhaustive-deps
180
- [props.isMulti, props.onChange, selectedIds, selectedOptions, resetAndClose, isValueControlled]);
193
+ [props.isMulti, props.onChange, resetAndClose, isValueControlled]);
181
194
  const handleCreate = (0, react_1.useCallback)(() => {
182
195
  if (!onCreate)
183
196
  return;
@@ -215,27 +228,51 @@ const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
215
228
  const frame = requestAnimationFrame(() => { var _a; return (_a = filterInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); });
216
229
  return () => cancelAnimationFrame(frame);
217
230
  }, [isOpen, isSearchable]);
231
+ const spec = (0, react_1.useMemo)(() => (0, optionRowSizes_1.optionRowSpec)(size), [size]);
218
232
  const maxMenuHeightPx = (0, react_1.useMemo)(() => parseRemToPx(maxMenuHeight, 256), [maxMenuHeight]);
219
233
  const shouldVirtualize = !!virtualizeAfter && !hasGroups && filteredOptions.length > virtualizeAfter;
220
234
  const [scrollTop, setScrollTop] = (0, react_1.useState)(0);
221
- const visibleCount = Math.ceil(maxMenuHeightPx / VIRTUAL_ROW_HEIGHT_PX) + VIRTUAL_OVERSCAN * 2;
235
+ // A description, an avatar or a renderOption row outgrows the spec's single-line height.
236
+ const [rowHeightPx, setRowHeightPx] = (0, react_1.useState)(spec.virtualRowHeightPx);
237
+ const visibleCount = Math.ceil(maxMenuHeightPx / rowHeightPx) + VIRTUAL_OVERSCAN * 2;
222
238
  const startIndex = shouldVirtualize
223
- ? Math.max(0, Math.floor(scrollTop / VIRTUAL_ROW_HEIGHT_PX) - VIRTUAL_OVERSCAN)
239
+ ? Math.max(0, Math.floor(scrollTop / rowHeightPx) - VIRTUAL_OVERSCAN)
224
240
  : 0;
225
241
  const endIndex = shouldVirtualize
226
242
  ? Math.min(filteredOptions.length, startIndex + visibleCount)
227
243
  : filteredOptions.length;
228
244
  const renderedOptions = shouldVirtualize ? filteredOptions.slice(startIndex, endIndex) : filteredOptions;
229
- const topPadPx = shouldVirtualize ? startIndex * VIRTUAL_ROW_HEIGHT_PX : 0;
230
- const bottomPadPx = shouldVirtualize ? (filteredOptions.length - endIndex) * VIRTUAL_ROW_HEIGHT_PX : 0;
245
+ const topPadPx = shouldVirtualize ? startIndex * rowHeightPx : 0;
246
+ const bottomPadPx = shouldVirtualize ? (filteredOptions.length - endIndex) * rowHeightPx : 0;
247
+ (0, react_1.useLayoutEffect)(() => {
248
+ var _a;
249
+ if (!isOpen)
250
+ return;
251
+ const row = (_a = listRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('[role="option"]');
252
+ if (!row)
253
+ return;
254
+ const measured = row.getBoundingClientRect().height;
255
+ if (measured > 0 && Math.abs(measured - rowHeightPx) > 0.5)
256
+ setRowHeightPx(measured);
257
+ }, [isOpen, rowHeightPx, filteredOptions.length]);
258
+ // Windowing starts mid-list, so the window must open where the user already is.
259
+ (0, react_1.useLayoutEffect)(() => {
260
+ var _a, _b;
261
+ if (shouldVirtualize && !wasVirtualized.current)
262
+ setScrollTop((_b = (_a = listRef.current) === null || _a === void 0 ? void 0 : _a.scrollTop) !== null && _b !== void 0 ? _b : 0);
263
+ wasVirtualized.current = shouldVirtualize;
264
+ }, [shouldVirtualize]);
231
265
  (0, react_1.useEffect)(() => {
232
266
  var _a, _b;
233
267
  if (activeIndex < 0 || !listRef.current)
234
268
  return;
269
+ if (lastActiveIndex.current === activeIndex)
270
+ return;
271
+ lastActiveIndex.current = activeIndex;
235
272
  const el = listRef.current;
236
273
  if (shouldVirtualize) {
237
- const targetTop = activeIndex * VIRTUAL_ROW_HEIGHT_PX;
238
- const targetBottom = targetTop + VIRTUAL_ROW_HEIGHT_PX;
274
+ const targetTop = activeIndex * rowHeightPx;
275
+ const targetBottom = targetTop + rowHeightPx;
239
276
  if (targetTop < el.scrollTop) {
240
277
  el.scrollTop = targetTop;
241
278
  setScrollTop(targetTop);
@@ -248,18 +285,44 @@ const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
248
285
  return;
249
286
  }
250
287
  (_b = (_a = el.querySelector(`[data-index="${activeIndex}"]`)) === null || _a === void 0 ? void 0 : _a.scrollIntoView) === null || _b === void 0 ? void 0 : _b.call(_a, { block: "nearest" });
251
- }, [activeIndex, shouldVirtualize, maxMenuHeightPx]);
288
+ }, [activeIndex, shouldVirtualize, maxMenuHeightPx, rowHeightPx]);
289
+ const loadMoreInFlightRef = (0, react_1.useRef)(false);
290
+ const prevOptionsLengthRef = (0, react_1.useRef)(options.length);
291
+ const prevIsLoadingRef = (0, react_1.useRef)(isLoading);
292
+ (0, react_1.useEffect)(() => {
293
+ if (options.length !== prevOptionsLengthRef.current)
294
+ loadMoreInFlightRef.current = false;
295
+ prevOptionsLengthRef.current = options.length;
296
+ }, [options.length]);
297
+ (0, react_1.useEffect)(() => {
298
+ if (prevIsLoadingRef.current && !isLoading)
299
+ loadMoreInFlightRef.current = false;
300
+ prevIsLoadingRef.current = isLoading;
301
+ }, [isLoading]);
302
+ const canLoadMore = !!onLoadMore && hasMore !== false;
303
+ const triggerLoadMore = (0, react_1.useCallback)(() => {
304
+ if (!onLoadMore || hasMore === false || isLoading || loadMoreInFlightRef.current)
305
+ return;
306
+ loadMoreInFlightRef.current = true;
307
+ onLoadMore();
308
+ }, [onLoadMore, hasMore, isLoading]);
252
309
  const moveActive = (delta) => {
253
310
  if (!filteredOptions.length)
254
311
  return;
255
- setActiveIndex((current) => {
256
- const next = current + delta;
257
- if (next < 0)
258
- return filteredOptions.length - 1;
259
- if (next >= filteredOptions.length)
260
- return 0;
261
- return next;
262
- });
312
+ const next = activeIndex + delta;
313
+ if (delta > 0 && next >= filteredOptions.length) {
314
+ if (canLoadMore) {
315
+ triggerLoadMore();
316
+ return;
317
+ }
318
+ setActiveIndex(0);
319
+ return;
320
+ }
321
+ if (next < 0) {
322
+ setActiveIndex(filteredOptions.length - 1);
323
+ return;
324
+ }
325
+ setActiveIndex(next);
263
326
  };
264
327
  const moveActiveBy = (delta) => {
265
328
  if (!filteredOptions.length)
@@ -346,10 +409,8 @@ const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
346
409
  const { scrollTop: nextScrollTop, clientHeight, scrollHeight } = event.currentTarget;
347
410
  if (shouldVirtualize)
348
411
  setScrollTop(nextScrollTop);
349
- if (!onLoadMore || isLoading)
350
- return;
351
412
  if (nextScrollTop + clientHeight >= scrollHeight - LOAD_MORE_THRESHOLD_PX)
352
- onLoadMore();
413
+ triggerLoadMore();
353
414
  };
354
415
  const handleFilterChange = (event) => {
355
416
  const nextText = event.target.value;
@@ -381,7 +442,7 @@ const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
381
442
  const showClear = isClearable && isInteractive && selectedOptions.length > 0;
382
443
  const triggerSx = (0, react_1.useMemo)(() => ({
383
444
  ...(0, fieldStyles_1.fieldControlStyles)(colors),
384
- ...chipTriggerSizeStyles(size, showChips, chipSize),
445
+ ...(0, chipTriggerSize_1.chipTriggerSizeStyles)(size, showChips, chipSize),
385
446
  ...(selectedOptions.length ? {} : { color: colors.textMuted }),
386
447
  ...(isOpen
387
448
  ? { borderColor: error ? colors.semanticText.error : colors.primary[500], boxShadow: (0, focusRing_styles_1.focusGlowShadow)(colors) }
@@ -411,14 +472,14 @@ const SelectPopup = (0, react_1.forwardRef)(function SelectPopup(props, ref) {
411
472
  const selectedValueIds = selectedOptions.map((option) => option.id.toString());
412
473
  const hiddenValues = !name ? [] : props.isMulti ? selectedValueIds : [(_c = selectedValueIds[0]) !== null && _c !== void 0 ? _c : ""];
413
474
  const groupedRows = (0, react_1.useMemo)(() => (hasGroups ? buildGroupedRows(filteredOptions) : []), [hasGroups, filteredOptions]);
414
- return ((0, jsx_runtime_1.jsxs)(react_2.FormControl, { isInvalid: error, isDisabled: isDisabled, isReadOnly: isReadOnly, style: formControlStyle, width: width, children: [label && ((0, jsx_runtime_1.jsx)(FormLabel_1.TextLabel, { label: label, id: ids.inputId, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), (0, jsx_runtime_1.jsxs)(react_2.Popover, { isOpen: isOpen, onClose: () => resetAndClose(), placement: "bottom-start", autoFocus: false, returnFocusOnClose: false, gutter: 4, children: [(0, jsx_runtime_1.jsx)(react_2.PopoverAnchor, { children: (0, jsx_runtime_1.jsxs)(react_2.Box, { as: "div", ref: mergedTriggerRef, ...ids.controlProps, role: "combobox", tabIndex: isDisabled ? -1 : 0, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-controls": listboxId, "aria-owns": `${listboxId} ${filterInputId}`, "aria-activedescendant": activeDescendantId, "aria-disabled": isDisabled || undefined, "data-readonly": isReadOnly || undefined, "aria-required": isRequired || undefined, "aria-label": triggerAriaLabel(), "aria-labelledby": ariaLabelledBy, onClick: handleOpen, onKeyDown: handleTriggerKeyDown, display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%", textAlign: "left", cursor: isDisabled ? "not-allowed" : isReadOnly ? "default" : "pointer", "data-testid": dataTestId, sx: triggerSx, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "inline-flex", flexWrap: showChips ? "wrap" : "nowrap", alignItems: "center", gap: showChips ? 1 : 1.5, minW: 0, flex: 1, isTruncated: !showChips, children: showChips ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [visibleChipOptions.map((option) => ((0, jsx_runtime_1.jsx)(Tag_1.default, { label: String(option.label), size: chipSize, variant: "subtle", icon: isInteractive ? lucide_react_1.X : undefined, onIconClick: isInteractive ? () => handleSelect(option) : undefined }, option.id))), overflowChipCount > 0 && ((0, jsx_runtime_1.jsx)(Tag_1.default, { label: `+${overflowChipCount}`, size: chipSize, variant: "subtle", colorScheme: "gray" }))] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [triggerIcon ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "inline-flex", flexShrink: 0, children: triggerIcon })) : null, (0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", isTruncated: true, children: renderValue ? renderValue(selectedOptions) : defaultTriggerContent() })] })) }), showClear && ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "button", type: "button", "aria-label": "Clear selection", onClick: handleClear, display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0, ml: 2, color: colors.textMuted, _hover: { color: colors.text[700] }, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: controlSizes_1.CONTROL_SIZES[size].iconSize }) })), (0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "inline-flex", flexShrink: 0, ml: 2, transition: CHEVRON_TRANSITION, transform: isOpen ? "rotate(180deg)" : "rotate(0deg)", color: colors.textMuted, sx: (0, motion_2.reducedMotionSx)(), children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: controlSizes_1.CONTROL_SIZES[size].iconSize }) })] }) }), (0, jsx_runtime_1.jsx)(react_2.Portal, { children: (0, jsx_runtime_1.jsxs)(react_2.PopoverContent, { width: "max-content", minWidth: triggerWidth ? `${triggerWidth}px` : undefined, maxWidth: "min(24rem, calc(100vw - 2rem))", borderRadius: "xl", boxShadow: theme.shadows.lg, overflow: "hidden", onKeyDown: handleListKeyDown, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { p: 2, borderBottom: `0.063rem solid ${colors.boxborder[200]}`, display: isSearchable ? undefined : "none", children: (0, jsx_runtime_1.jsx)(react_2.Input, { ref: filterInputRef, id: filterInputId, size: "sm", placeholder: "Type to filter...", value: currentSearch, onChange: handleFilterChange, "aria-activedescendant": activeDescendantId, "aria-controls": listboxId, "aria-label": "Filter options", tabIndex: isSearchable ? undefined : -1 }) }), (0, jsx_runtime_1.jsxs)(react_2.Box, { id: listboxId, ref: listRef, role: "listbox", "aria-label": (_d = label !== null && label !== void 0 ? label : ariaLabel) !== null && _d !== void 0 ? _d : placeholder, "aria-multiselectable": props.isMulti || undefined, "aria-busy": isLoading || undefined, maxH: maxMenuHeight, overflowY: "auto", py: 1, sx: listScrollStyles, onScroll: handleListScroll, children: [filteredOptions.length === 0 && !isLoading && !showCreateRow && ((0, jsx_runtime_1.jsx)(react_2.Box, { px: 3, py: 2, fontSize: "0.8125rem", color: colors.textMuted, children: noOptionsMessage !== null && noOptionsMessage !== void 0 ? noOptionsMessage : "No Options" })), showCreateRow && ((0, jsx_runtime_1.jsx)(react_2.Box, { id: createRowId, role: "option", "aria-selected": false, "data-index": -1, onClick: handleCreate, mx: 1.5, px: 2.5, py: 1.5, borderRadius: "md", cursor: "pointer", fontSize: "0.8125rem", fontWeight: 600, color: colors.primary[600], bg: activeDescendantId === createRowId ? rowBackgrounds.active : "transparent", children: createLabel ? createLabel(currentSearch.trim()) : `Create "${currentSearch.trim()}"` })), hasGroups
475
+ return ((0, jsx_runtime_1.jsxs)(react_2.FormControl, { isInvalid: error, isDisabled: isDisabled, isReadOnly: isReadOnly, style: formControlStyle, width: width, children: [label && ((0, jsx_runtime_1.jsx)(FormLabel_1.TextLabel, { label: label, id: ids.inputId, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), (0, jsx_runtime_1.jsxs)(react_2.Popover, { isOpen: isOpen, onClose: () => resetAndClose(), placement: "bottom-start", autoFocus: false, returnFocusOnClose: false, gutter: 4, children: [(0, jsx_runtime_1.jsx)(react_2.PopoverAnchor, { children: (0, jsx_runtime_1.jsxs)(react_2.Box, { as: "div", ref: mergedTriggerRef, ...ids.controlProps, role: "combobox", tabIndex: isDisabled ? -1 : 0, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-controls": listboxId, "aria-owns": `${listboxId} ${filterInputId}`, "aria-activedescendant": activeDescendantId, "aria-disabled": isDisabled || undefined, "data-readonly": isReadOnly || undefined, "aria-required": isRequired || undefined, "aria-label": triggerAriaLabel(), "aria-labelledby": ariaLabelledBy, onClick: handleOpen, onKeyDown: handleTriggerKeyDown, display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%", textAlign: "left", cursor: isDisabled ? "not-allowed" : isReadOnly ? "default" : "pointer", "data-testid": dataTestId, sx: triggerSx, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "inline-flex", flexWrap: showChips ? "wrap" : "nowrap", alignItems: "center", gap: showChips ? 1 : 1.5, minW: 0, flex: 1, isTruncated: !showChips, children: showChips ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [visibleChipOptions.map((option) => ((0, jsx_runtime_1.jsx)(Tag_1.default, { label: String(option.label), size: chipSize, variant: "subtle", icon: isInteractive ? lucide_react_1.X : undefined, onIconClick: isInteractive ? () => handleSelect(option) : undefined }, option.id))), overflowChipCount > 0 && ((0, jsx_runtime_1.jsx)(Tag_1.default, { label: `+${overflowChipCount}`, size: chipSize, variant: "subtle", colorScheme: "gray" }))] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [triggerIcon ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "inline-flex", flexShrink: 0, children: triggerIcon })) : null, (0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", isTruncated: true, children: renderValue ? renderValue(selectedOptions) : defaultTriggerContent() })] })) }), showClear && ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "button", type: "button", "aria-label": "Clear selection", onClick: handleClear, display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0, ml: 2, color: colors.textMuted, _hover: { color: colors.text[700] }, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: controlSizes_1.CONTROL_SIZES[size].iconSize }) })), (0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", display: "inline-flex", flexShrink: 0, ml: 2, transition: CHEVRON_TRANSITION, transform: isOpen ? "rotate(180deg)" : "rotate(0deg)", color: colors.textMuted, sx: (0, motion_2.reducedMotionSx)(), children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: controlSizes_1.CONTROL_SIZES[size].iconSize }) })] }) }), (0, jsx_runtime_1.jsx)(react_2.Portal, { children: (0, jsx_runtime_1.jsxs)(react_2.PopoverContent, { width: "max-content", minWidth: triggerWidth ? `${triggerWidth}px` : undefined, maxWidth: "min(24rem, calc(100vw - 2rem))", borderRadius: "xl", boxShadow: theme.shadows.lg, overflow: "hidden", onKeyDown: handleListKeyDown, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { p: spec.mx, borderBottom: `0.063rem solid ${colors.boxborder[200]}`, display: isSearchable ? undefined : "none", children: (0, jsx_runtime_1.jsx)(react_2.Input, { ref: filterInputRef, id: filterInputId, size: size, px: spec.px, placeholder: "Type to filter...", value: currentSearch, onChange: handleFilterChange, "aria-activedescendant": activeDescendantId, "aria-controls": listboxId, "aria-label": "Filter options", tabIndex: isSearchable ? undefined : -1 }) }), (0, jsx_runtime_1.jsxs)(react_2.Box, { id: listboxId, ref: listRef, role: "listbox", "aria-label": (_d = label !== null && label !== void 0 ? label : ariaLabel) !== null && _d !== void 0 ? _d : placeholder, "aria-multiselectable": props.isMulti || undefined, "aria-busy": isLoading || undefined, maxH: maxMenuHeight, overflowY: "auto", py: 1, sx: listScrollStyles, onScroll: handleListScroll, children: [filteredOptions.length === 0 && !isLoading && !showCreateRow && ((0, jsx_runtime_1.jsx)(react_2.Box, { mx: spec.mx, px: spec.px, py: spec.py, fontSize: spec.fontSize, color: colors.textMuted, children: noOptionsMessage !== null && noOptionsMessage !== void 0 ? noOptionsMessage : "No Options" })), showCreateRow && ((0, jsx_runtime_1.jsx)(react_2.Box, { id: createRowId, role: "option", "aria-selected": false, "data-index": -1, onClick: handleCreate, mx: spec.mx, px: spec.px, py: spec.py, minH: spec.minH, borderRadius: "md", cursor: "pointer", fontSize: spec.fontSize, fontWeight: 600, color: colors.primary[600], bg: activeDescendantId === createRowId ? rowBackgrounds.active : "transparent", children: createLabel ? createLabel(currentSearch.trim()) : `Create "${currentSearch.trim()}"` })), hasGroups
415
476
  ? groupedRows.map((row) => {
416
477
  var _a;
417
- return row.kind === "header" ? ((0, jsx_runtime_1.jsx)(react_2.Box, { px: 3, pt: 2, pb: 1, fontSize: "0.6875rem", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.03em", color: colors.textMuted, children: row.group }, row.key)) : ((0, jsx_runtime_1.jsx)(OptionRow, { option: row.option, index: row.index, listboxId: listboxId, isSelected: selectedIds.has(row.option.id.toString()), isActive: row.index === activeIndex, isMulti: (_a = props.isMulti) !== null && _a !== void 0 ? _a : false, theme: theme, backgrounds: rowBackgrounds, renderOption: renderOption, onSelect: handleSelect, onActivate: setActiveIndex }, row.key));
478
+ return row.kind === "header" ? ((0, jsx_runtime_1.jsx)(react_2.Box, { mx: spec.mx, px: spec.px, pt: 2, pb: 1, fontSize: "0.6875rem", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.03em", color: colors.textMuted, children: row.group }, row.key)) : ((0, jsx_runtime_1.jsx)(OptionRow, { option: row.option, index: row.index, listboxId: listboxId, isSelected: selectedIds.has(row.option.id.toString()), isActive: row.index === activeIndex, isMulti: (_a = props.isMulti) !== null && _a !== void 0 ? _a : false, theme: theme, backgrounds: rowBackgrounds, spec: spec, renderOption: renderOption, onSelect: handleSelect, onActivate: setActiveIndex }, row.key));
418
479
  })
419
480
  : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [topPadPx > 0 && (0, jsx_runtime_1.jsx)(react_2.Box, { height: `${topPadPx}px` }), renderedOptions.map((option, i) => {
420
481
  var _a;
421
- return ((0, jsx_runtime_1.jsx)(OptionRow, { option: option, index: startIndex + i, listboxId: listboxId, isSelected: selectedIds.has(option.id.toString()), isActive: startIndex + i === activeIndex, isMulti: (_a = props.isMulti) !== null && _a !== void 0 ? _a : false, theme: theme, backgrounds: rowBackgrounds, renderOption: renderOption, onSelect: handleSelect, onActivate: setActiveIndex }, option.id));
422
- }), bottomPadPx > 0 && (0, jsx_runtime_1.jsx)(react_2.Box, { height: `${bottomPadPx}px` })] })), isLoading && ((0, jsx_runtime_1.jsxs)(react_2.Box, { px: 3, py: 2, display: "flex", alignItems: "center", gap: 2, fontSize: "0.8125rem", color: colors.textMuted, children: [(0, jsx_runtime_1.jsx)(react_2.Spinner, { size: "xs" }), loadingText] }))] })] }) })] }), hiddenValues.map((value) => ((0, jsx_runtime_1.jsx)("input", { type: "hidden", name: name, value: value }, value))), (0, jsx_runtime_1.jsx)(FieldMessage_1.default, { error: error, errorMessage: errorMessage, helperText: helperText, helperId: ids.helperId, errorId: ids.errorId })] }));
482
+ return ((0, jsx_runtime_1.jsx)(OptionRow, { option: option, index: startIndex + i, listboxId: listboxId, isSelected: selectedIds.has(option.id.toString()), isActive: startIndex + i === activeIndex, isMulti: (_a = props.isMulti) !== null && _a !== void 0 ? _a : false, theme: theme, backgrounds: rowBackgrounds, spec: spec, renderOption: renderOption, onSelect: handleSelect, onActivate: setActiveIndex }, option.id));
483
+ }), bottomPadPx > 0 && (0, jsx_runtime_1.jsx)(react_2.Box, { height: `${bottomPadPx}px` })] })), isLoading && ((0, jsx_runtime_1.jsxs)(react_2.Box, { mx: spec.mx, px: spec.px, py: spec.py, display: "flex", alignItems: "center", gap: spec.gap, fontSize: spec.fontSize, color: colors.textMuted, children: [(0, jsx_runtime_1.jsx)(react_2.Spinner, { size: "xs" }), loadingText] }))] })] }) })] }), hiddenValues.map((value) => ((0, jsx_runtime_1.jsx)("input", { type: "hidden", name: name, value: value }, value))), (0, jsx_runtime_1.jsx)(FieldMessage_1.default, { error: error, errorMessage: errorMessage, helperText: helperText, helperId: ids.helperId, errorId: ids.errorId })] }));
423
484
  });
424
485
  exports.default = SelectPopup;
@@ -72,6 +72,8 @@ type SelectCommonProps = {
72
72
  onSearchChange?: (query: string) => void;
73
73
  /** Debounce for `onSearchChange`, in ms. Defaults to 0 — every keystroke, matching SelectV2 today. */
74
74
  searchDebounceMs?: number;
75
+ /** Applies the local label-substring filter. Defaults to false once `onSearchChange` is set (server owns matching), true otherwise. */
76
+ filterOptions?: boolean;
75
77
  /** Shows a clear (x) control once a value is selected. Popup mode only. */
76
78
  isClearable?: boolean;
77
79
  /** Fires after a clear action, in addition to `onChange`. Popup mode only. */
@@ -84,6 +86,8 @@ type SelectCommonProps = {
84
86
  noOptionsMessage?: ReactNode;
85
87
  /** Fires when the list is scrolled to its end and not loading — append the next page. Popup mode only. */
86
88
  onLoadMore?: () => void;
89
+ /** Set explicitly to false once paging is exhausted, to stop further `onLoadMore` calls. Popup mode only. */
90
+ hasMore?: boolean;
87
91
  /** Full control over an option row; receives isSelected/isActive. Popup mode only. */
88
92
  renderOption?: (option: OptionProp, state: {
89
93
  isSelected: boolean;
@@ -1,3 +1,7 @@
1
1
  import type { PaletteProps } from "../../Theme/tokens/types";
2
2
  /** Selection is carried by weight and a trailing brand check, so the label itself stays neutral. */
3
3
  export declare const optionRowInk: (colors: PaletteProps, isSingleSelected: boolean) => string;
4
+ export declare const optionRowDescriptionInk: (colors: PaletteProps) => string;
5
+ export declare const OPTION_ROW_REST_WEIGHT = 400;
6
+ export declare const OPTION_ROW_SELECTED_WEIGHT = 500;
7
+ export declare const optionRowWeight: (isSingleSelected: boolean) => number;
@@ -1,6 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.optionRowInk = void 0;
3
+ exports.optionRowWeight = exports.OPTION_ROW_SELECTED_WEIGHT = exports.OPTION_ROW_REST_WEIGHT = exports.optionRowDescriptionInk = exports.optionRowInk = void 0;
4
+ const accentText_1 = require("../../Theme/tokens/builders/accentText");
5
+ const outlineRung_1 = require("../../Theme/tokens/builders/outlineRung");
6
+ const rowStates_1 = require("../../Theme/tokens/builders/rowStates");
4
7
  /** Selection is carried by weight and a trailing brand check, so the label itself stays neutral. */
5
8
  const optionRowInk = (colors, isSingleSelected) => isSingleSelected ? colors.text[900] : colors.text[700];
6
9
  exports.optionRowInk = optionRowInk;
10
+ // A 12px sub-line reached only 4.00:1 on the hovered selected row in dark.
11
+ const optionRowDescriptionInk = (colors) => (0, outlineRung_1.liftToContrast)(colors.textMuted, (0, rowStates_1.listRowBackgrounds)(colors).selectedActive, accentText_1.AA_NORMAL_TEXT);
12
+ exports.optionRowDescriptionInk = optionRowDescriptionInk;
13
+ exports.OPTION_ROW_REST_WEIGHT = 400;
14
+ // NOTE: 600 beside a tinted fill and a check read as three signals for one state.
15
+ exports.OPTION_ROW_SELECTED_WEIGHT = 500;
16
+ const optionRowWeight = (isSingleSelected) => isSingleSelected ? exports.OPTION_ROW_SELECTED_WEIGHT : exports.OPTION_ROW_REST_WEIGHT;
17
+ exports.optionRowWeight = optionRowWeight;
@@ -14,21 +14,25 @@ const useFieldIds_1 = require("../Common/useFieldIds");
14
14
  const FieldMessage_1 = __importDefault(require("../Common/FieldMessage"));
15
15
  const motion_1 = require("../../Theme/tokens/primitives/motion");
16
16
  const controlSizes_1 = require("../../Theme/tokens/primitives/controlSizes");
17
+ const optionRowSizes_1 = require("../../Theme/tokens/primitives/optionRowSizes");
17
18
  const motion_2 = require("../../Theme/chakra/motion");
18
19
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
19
20
  const rowStates_1 = require("../../Theme/tokens/builders/rowStates");
21
+ const optionRowInk_1 = require("../Select/optionRowInk");
20
22
  const useExclusiveOverlay_1 = require("../../Hooks/useExclusiveOverlay");
21
23
  const lucide_react_1 = require("lucide-react");
22
24
  const ROW_TRANSITION = (0, motion_1.transitionFor)(["background-color"]);
23
- const RenderOptions = ({ isOptionLoading, filteredOptions, loadingText, handleOptionClick, isProfile, isColorOptions, isOptionSelected, activeIndex, optionRefs, }) => {
25
+ const RenderOptions = ({ isOptionLoading, filteredOptions, loadingText, handleOptionClick, isProfile, isColorOptions, isOptionSelected, activeIndex, optionRefs, size, isMultipleSelect, }) => {
24
26
  const theme = (0, useCustomTheme_1.useCustomTheme)();
25
27
  const rowBackgrounds = (0, react_1.useMemo)(() => (0, rowStates_1.listRowBackgrounds)(theme.colors), [theme.colors]);
28
+ const spec = (0, optionRowSizes_1.optionRowSpec)(size);
26
29
  if (isOptionLoading) {
27
30
  return ((0, jsx_runtime_1.jsxs)(react_2.VStack, { py: 2, children: [(0, jsx_runtime_1.jsx)(react_2.Spinner, { size: "sm", color: theme.colors.accentText }), (0, jsx_runtime_1.jsx)(react_2.Text, { color: theme.colors.accentText, children: loadingText })] }));
28
31
  }
29
32
  if (filteredOptions === null || filteredOptions === void 0 ? void 0 : filteredOptions.length) {
30
33
  return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: filteredOptions.map((option, index) => {
31
34
  const selected = isOptionSelected(option);
35
+ const isSingleSelected = selected && !isMultipleSelect;
32
36
  const isActive = index === activeIndex;
33
37
  const rowBg = selected
34
38
  ? isActive
@@ -39,14 +43,14 @@ const RenderOptions = ({ isOptionLoading, filteredOptions, loadingText, handleOp
39
43
  : "transparent";
40
44
  return ((0, jsx_runtime_1.jsxs)(react_2.Box, { as: "button", type: "button", ref: (el) => {
41
45
  optionRefs.current[index] = el;
42
- }, role: "option", "aria-selected": selected, tabIndex: isActive ? 0 : -1, w: "100%", textAlign: "left", border: "none", fontFamily: "inherit", bg: rowBg, px: 4, py: 1.5, fontSize: "0.8125rem", cursor: "pointer", color: theme.colors.text[700], fontWeight: selected ? 600 : 400, transition: ROW_TRANSITION, sx: (0, motion_2.reducedMotionSx)(), _hover: {
46
+ }, role: "option", "aria-selected": selected, tabIndex: isActive ? 0 : -1, w: `calc(100% - 2 * ${spec.mx})`, minH: spec.minH, textAlign: "left", border: "none", fontFamily: "inherit", bg: rowBg, mx: spec.mx, px: spec.px, py: spec.py, borderRadius: optionRowSizes_1.OPTION_ROW_RADIUS, fontSize: spec.fontSize, cursor: "pointer", color: (0, optionRowInk_1.optionRowInk)(theme.colors, isSingleSelected), fontWeight: (0, optionRowInk_1.optionRowWeight)(isSingleSelected), transition: ROW_TRANSITION, sx: (0, motion_2.reducedMotionSx)(), _hover: {
43
47
  bg: selected ? rowBackgrounds.selectedActive : rowBackgrounds.active,
44
48
  }, onClick: () => handleOptionClick(option), onKeyDown: (e) => {
45
49
  if (e.key === "Enter" || e.key === " ") {
46
50
  e.preventDefault();
47
51
  handleOptionClick(option);
48
52
  }
49
- }, display: "flex", alignItems: "center", gap: "0.5rem", children: [isProfile && ((0, jsx_runtime_1.jsx)(react_2.Box, { children: (0, jsx_runtime_1.jsx)(Avatar_1.default, { size: "sm", name: option.label.toLocaleUpperCase(), src: option.profileUrl ? option.profileUrl : undefined }) })), isColorOptions && ((0, jsx_runtime_1.jsx)(react_2.Box, { width: "0.8rem", height: "0.8rem", content: "", backgroundColor: option === null || option === void 0 ? void 0 : option.color, borderRadius: "50%" })), (0, jsx_runtime_1.jsxs)(react_2.Box, { children: [(0, jsx_runtime_1.jsx)(react_2.Box, { children: option.label }), option.email && ((0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "0.75rem", color: theme.colors.textMuted, children: option.email }))] })] }, option.id));
53
+ }, display: "flex", alignItems: "center", gap: spec.gap, children: [isProfile && ((0, jsx_runtime_1.jsx)(react_2.Box, { children: (0, jsx_runtime_1.jsx)(Avatar_1.default, { size: spec.avatarSize, name: option.label.toLocaleUpperCase(), src: option.profileUrl ? option.profileUrl : undefined }) })), isColorOptions && ((0, jsx_runtime_1.jsx)(react_2.Box, { width: "0.8rem", height: "0.8rem", content: "", backgroundColor: option === null || option === void 0 ? void 0 : option.color, borderRadius: "50%" })), (0, jsx_runtime_1.jsxs)(react_2.Box, { flex: 1, minW: 0, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { children: option.label }), option.email && ((0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: spec.descriptionFontSize, color: (0, optionRowInk_1.optionRowDescriptionInk)(theme.colors), children: option.email }))] }), isSingleSelected && ((0, jsx_runtime_1.jsx)(react_2.Box, { as: lucide_react_1.Check, size: spec.iconSize, color: theme.colors.accentText, flexShrink: 0 }))] }, option.id));
50
54
  }) }));
51
55
  }
52
56
  return ((0, jsx_runtime_1.jsx)(react_2.Text, { px: 4, py: 2, color: theme.colors.textMuted, children: "No options found" }));
@@ -230,7 +234,7 @@ function SelectSearch({ options, initialSelectedOption, onOptionSelect, inputOnc
230
234
  return;
231
235
  }
232
236
  openDropdown();
233
- }, onChange: (e) => handleInputChange(e.target.value), placeholder: placeholder, onKeyDown: handleKeyDown, name: name, role: "combobox", "aria-autocomplete": "list", "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-controls": listboxId, "aria-required": isRequired || undefined, cursor: "pointer", sx: { ...(0, fieldStyles_1.fieldControlStyles)(theme.colors), ...(0, fieldStyles_1.controlSizeStyles)(size), ...(0, motion_2.reducedMotionSx)() }, style: inputStyle }), rightIcon && ((0, jsx_runtime_1.jsx)(react_2.InputRightElement, { pointerEvents: "none", children: rightIcon, style: { ...rightElementStyle } }))] }), isOpen && ((0, jsx_runtime_1.jsxs)(react_2.Box, { ref: dropdownRef, marginTop: "0.313rem", position: "absolute", top: position === "below" ? "100%" : "auto", bottom: position === "above" ? "100%" : "auto", left: 0, right: 0, border: "0.063rem solid", borderColor: theme.colors.boxborder[200], borderRadius: "xl", boxShadow: theme.shadows.lg, bg: theme.colors.surfaceRaised, maxHeight: "9.375rem", overflowY: "auto", zIndex: 10, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { id: listboxId, role: "listbox", "aria-label": label !== null && label !== void 0 ? label : placeholder, onKeyDown: handleListKeyDown, children: (0, jsx_runtime_1.jsx)(RenderOptions, { isOptionLoading: isOptionLoading, filteredOptions: filteredOptions, loadingText: loadingText, handleOptionClick: handleOptionClick, isProfile: isProfile, isColorOptions: isColorOptions, isOptionSelected: isOptionSelected, activeIndex: activeIndex, optionRefs: optionRefs }) }), (0, jsx_runtime_1.jsx)("hr", {}), isBottomIcon && ((0, jsx_runtime_1.jsxs)(react_2.Box, { position: "sticky", bottom: 0, background: theme.colors.surfaceRaised, display: "flex", alignItems: "center", pl: "1rem", cursor: "pointer", onClick: handleBottomClick, borderColor: theme.colors.boxborder[200], zIndex: 1, borderTop: `1px solid ${theme.colors.boxborder[200]}`, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { children: BottomIcon ? BottomIcon : (0, jsx_runtime_1.jsx)(lucide_react_1.PlusIcon, { size: "1rem" }) }), (0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "0.875rem", color: BottomTextColor
237
+ }, onChange: (e) => handleInputChange(e.target.value), placeholder: placeholder, onKeyDown: handleKeyDown, name: name, role: "combobox", "aria-autocomplete": "list", "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-controls": listboxId, "aria-required": isRequired || undefined, cursor: "pointer", sx: { ...(0, fieldStyles_1.fieldControlStyles)(theme.colors), ...(0, fieldStyles_1.controlSizeStyles)(size), ...(0, motion_2.reducedMotionSx)() }, style: inputStyle }), rightIcon && ((0, jsx_runtime_1.jsx)(react_2.InputRightElement, { pointerEvents: "none", children: rightIcon, style: { ...rightElementStyle } }))] }), isOpen && ((0, jsx_runtime_1.jsxs)(react_2.Box, { ref: dropdownRef, marginTop: "0.313rem", position: "absolute", top: position === "below" ? "100%" : "auto", bottom: position === "above" ? "100%" : "auto", left: 0, right: 0, border: "0.063rem solid", borderColor: theme.colors.boxborder[200], borderRadius: "xl", boxShadow: theme.shadows.lg, bg: theme.colors.surfaceRaised, maxHeight: "9.375rem", overflowY: "auto", zIndex: 10, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { id: listboxId, role: "listbox", "aria-label": label !== null && label !== void 0 ? label : placeholder, onKeyDown: handleListKeyDown, children: (0, jsx_runtime_1.jsx)(RenderOptions, { isOptionLoading: isOptionLoading, filteredOptions: filteredOptions, loadingText: loadingText, handleOptionClick: handleOptionClick, isProfile: isProfile, isColorOptions: isColorOptions, isOptionSelected: isOptionSelected, activeIndex: activeIndex, optionRefs: optionRefs, size: size, isMultipleSelect: isMultipleSelect }) }), (0, jsx_runtime_1.jsx)("hr", {}), isBottomIcon && ((0, jsx_runtime_1.jsxs)(react_2.Box, { position: "sticky", bottom: 0, background: theme.colors.surfaceRaised, display: "flex", alignItems: "center", pl: "1rem", cursor: "pointer", onClick: handleBottomClick, borderColor: theme.colors.boxborder[200], zIndex: 1, borderTop: `1px solid ${theme.colors.boxborder[200]}`, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { children: BottomIcon ? BottomIcon : (0, jsx_runtime_1.jsx)(lucide_react_1.PlusIcon, { size: "1rem" }) }), (0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "0.875rem", color: BottomTextColor
234
238
  ? BottomTextColor
235
239
  : theme.colors.accentText, padding: "8px 8px", children: BottomText || "Add New" })] }))] })), (0, jsx_runtime_1.jsx)(FieldMessage_1.default, { error: error, errorMessage: errorMessage, helperText: helperText, helperId: ids.helperId, errorId: ids.errorId })] }) }) }));
236
240
  }
@@ -1,14 +1,7 @@
1
1
  import React from "react";
2
- import { type ControlSize } from "../../Theme/tokens/primitives/controlSizes";
2
+ import { chipTriggerSizeStyles } from "../Common/chipTriggerSize";
3
3
  import type { SelectV2Props } from "./SelectV2Props";
4
- type ChipSize = "xs" | "sm";
5
- export declare const chipTriggerSizeStyles: (size: ControlSize, hasChips: boolean, chipSize?: ChipSize) => {
6
- minH: string;
7
- fontSize: string;
8
- px: string;
9
- h?: string;
10
- py?: string;
11
- };
4
+ export { chipTriggerSizeStyles };
12
5
  /** @deprecated Use `Select` with `native={false}`. See MERGE-NOTES-select-deprecation.md. */
13
6
  declare const SelectV2: React.ForwardRefExoticComponent<SelectV2Props & React.RefAttributes<HTMLDivElement>>;
14
7
  /** @deprecated Use `Select` with `native={false}`. */
@@ -7,16 +7,8 @@ exports.chipTriggerSizeStyles = void 0;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const react_1 = require("react");
9
9
  const Select_1 = __importDefault(require("../Select/Select"));
10
- const controlSizes_1 = require("../../Theme/tokens/primitives/controlSizes");
11
- const CHIP_TAG_HEIGHT_PX = { xs: 20, sm: 24 };
12
- const controlHeightPx = (size) => parseFloat(controlSizes_1.CONTROL_SIZES[size].height) * 16;
13
- const chipRowPaddingY = (size, chipSize) => `${(controlHeightPx(size) - CHIP_TAG_HEIGHT_PX[chipSize]) / 2 / 16}rem`;
14
- const chipTriggerSizeStyles = (size, hasChips, chipSize = "sm") => {
15
- const spec = controlSizes_1.CONTROL_SIZES[size];
16
- const base = { minH: spec.height, fontSize: spec.fontSize, px: spec.paddingX };
17
- return hasChips ? { ...base, py: chipRowPaddingY(size, chipSize) } : { ...base, h: spec.height };
18
- };
19
- exports.chipTriggerSizeStyles = chipTriggerSizeStyles;
10
+ const chipTriggerSize_1 = require("../Common/chipTriggerSize");
11
+ Object.defineProperty(exports, "chipTriggerSizeStyles", { enumerable: true, get: function () { return chipTriggerSize_1.chipTriggerSizeStyles; } });
20
12
  /** @deprecated Use `Select` with `native={false}`. See MERGE-NOTES-select-deprecation.md. */
21
13
  const SelectV2 = (0, react_1.forwardRef)(function SelectV2(props, ref) {
22
14
  return (0, jsx_runtime_1.jsx)(Select_1.default, { ...props, native: false, ref: ref });
@@ -1,3 +1,3 @@
1
1
  import { SwitchProps } from "./SwitchProps";
2
- /** @deprecated Use `SegmentedControl` — Switch renders it at 12.5rem, growing when the labels need it. */
2
+ /** @deprecated Two labelled choices; for a single on/off field use `ToggleSwitch`. Renders `SegmentedControl` at 12.5rem when labelled. */
3
3
  export default function Switch({ leftText, rightText, leftIcon, rightIcon, onSwitchToggle, switchActive, surface, "aria-label": ariaLabel, }: SwitchProps): import("react/jsx-runtime").JSX.Element;
@@ -7,11 +7,13 @@ exports.default = Switch;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const react_1 = require("@chakra-ui/react");
9
9
  const SegmentedControl_1 = __importDefault(require("../SegmentedControl/SegmentedControl"));
10
- /** @deprecated Use `SegmentedControl` — Switch renders it at 12.5rem, growing when the labels need it. */
10
+ /** @deprecated Two labelled choices; for a single on/off field use `ToggleSwitch`. Renders `SegmentedControl` at 12.5rem when labelled. */
11
11
  function Switch({ leftText, rightText, leftIcon, rightIcon, onSwitchToggle, switchActive, surface, "aria-label": ariaLabel, }) {
12
12
  const options = [
13
13
  { value: "left", label: leftText, icon: leftIcon },
14
14
  { value: "right", label: rightText, icon: rightIcon },
15
15
  ];
16
- return ((0, jsx_runtime_1.jsx)(react_1.Box, { w: "fit-content", minW: "12.5rem", children: (0, jsx_runtime_1.jsx)(SegmentedControl_1.default, { options: options, value: switchActive, onChange: onSwitchToggle, variant: "brandSlide", surface: surface, isFullWidth: true, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : `${leftText} or ${rightText}` }) }));
16
+ // Unlabelled segments have nothing to size to, so the 12.5rem floor only overflowed its cell.
17
+ const hasLabels = Boolean(leftText || rightText);
18
+ return ((0, jsx_runtime_1.jsx)(react_1.Box, { w: "fit-content", maxW: "100%", minW: hasLabels ? "12.5rem" : undefined, children: (0, jsx_runtime_1.jsx)(SegmentedControl_1.default, { options: options, value: switchActive, onChange: onSwitchToggle, variant: "brandSlide", surface: surface, isFullWidth: true, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : `${leftText} or ${rightText}` }) }));
17
19
  }
@@ -83,7 +83,7 @@ function Table({ data, columns, onSelection, isLoading, isCheckbox = false, free
83
83
  }
84
84
  return {};
85
85
  }, [tablePreferencesData]);
86
- const { tableData, isContent, isLink, headerRefs, columnWidths, handleSort, handleCheckbox, filteredData, startRow, selection, columnsSort, currentPage, pages, rowsPerPage, handlePageSizeChange, setCurrentPage, columnsList, handleColumnPreferences, isSelecting, selectAllRowsRef, } = (0, useTable_1.default)({
86
+ const { tableData, isContent, isLink, headerRefs, columnWidths, slotRef, slotWidth, handleSort, handleCheckbox, filteredData, searchedData, startRow, selection, columnsSort, currentPage, pages, rowsPerPage, handlePageSizeChange, setCurrentPage, columnsList, handleColumnPreferences, isSelecting, selectAllRowsRef, } = (0, useTable_1.default)({
87
87
  data,
88
88
  isPagination,
89
89
  selections,
@@ -96,6 +96,7 @@ function Table({ data, columns, onSelection, isLoading, isCheckbox = false, free
96
96
  isServerPagination,
97
97
  onNoOfRowsPerPageChange,
98
98
  defaultVisibleColumns,
99
+ columnsSearch,
99
100
  });
100
101
  // Density + grouping are managed here so the Table Settings tabs can change +
101
102
  // persist them (seeded from the prop / saved preferences when they load).
@@ -178,9 +179,7 @@ function Table({ data, columns, onSelection, isLoading, isCheckbox = false, free
178
179
  setGroupByState(group);
179
180
  handleColumnPreferences(cols, { density: densityState, groupBy: group !== null && group !== void 0 ? group : null });
180
181
  };
181
- const _filteredData = (0, react_1.useMemo)(() => {
182
- return (0, table_1.searchAndSortData)(filteredData, columnsSearch);
183
- }, [columnsSearch, filteredData]);
182
+ const _filteredData = filteredData;
184
183
  // --- Monday-style grouping. Active whenever the user has picked a group column
185
184
  // (in Settings > Group). When active, the numbered pager / infinite scroll are
186
185
  // hidden and the body renders colored, collapsible groups over the loaded rows.
@@ -285,7 +284,7 @@ function Table({ data, columns, onSelection, isLoading, isCheckbox = false, free
285
284
  : "Showing all records";
286
285
  const tablePaginationText = isServerPagination
287
286
  ? `${startRow + 1} - ${Math.min(startRow + rowsPerPage, totalRecords)} of ${totalRecords}`
288
- : `${startRow + 1} - ${Math.min(startRow + rowsPerPage, tableData.length)} of ${tableData.length}`;
287
+ : `${startRow + 1} - ${Math.min(startRow + rowsPerPage, searchedData.length)} of ${searchedData.length}`;
289
288
  const rowHeight = (0, rowMetrics_1.rowHeightFor)(densityState);
290
289
  const headerHeight = (0, rowMetrics_1.pxOf)(variantTokens.header.height);
291
290
  const actualRows = isGrouped ? groupedSource.length : _filteredData.length;
@@ -406,7 +405,7 @@ function Table({ data, columns, onSelection, isLoading, isCheckbox = false, free
406
405
  headerActions && ((0, jsx_runtime_1.jsx)(HeaderActions_1.default, { actions: headerActions, selections: selection }, "actions")),
407
406
  ]
408
407
  .filter(Boolean)
409
- .flatMap((tool, i) => (i === 0 ? [tool] : [(0, jsx_runtime_1.jsx)(Divider_1.default, {}, `divider-${i}`), tool])), (0, jsx_runtime_1.jsx)(ActiveFilters_1.default, { columns: columnsList, columnsSearch: columnsSearch, setColumnsSearch: setColumnsSearch }), (0, jsx_runtime_1.jsxs)(react_2.Box, { ml: "auto", display: "flex", alignItems: "center", gap: 2, children: [groupLoadMoreActive && loadMorePosition === "top" && (groupLoadMoreCaption || canGroupLoadMore) && ((0, jsx_runtime_1.jsxs)(react_2.Box, { display: "flex", alignItems: "center", gap: 2, flex: "0 0 auto", children: [groupLoadMoreCaption && ((0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "0.75rem", color: theme.colors.text[500], whiteSpace: "nowrap", children: groupLoadMoreCaption })), canGroupLoadMore && ((0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "outline", colorScheme: "gray", isLoading: isLoadingMore, loadingText: loadMoreText, onClick: handleGroupLoadMore, label: loadMoreText }))] })), (isPagination || isServerPagination) && !isGrouped && !canInfinite && !isCompactHeader && ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(Pagination_1.default, { currentPage: currentPage, setCurrentPage: setCurrentPage, rowsPerPage: rowsPerPage, pages: pages, paginationText: tablePaginationText, handlePageSizeChange: handlePageSizeChange, dataLength: tableData.length, isServerPagination: isServerPagination, paginationSelectOptions: paginationSelectOptions }) })), (isPagination || isServerPagination) && !isGrouped && !canInfinite && isCompactHeader && tableData.length > 0 && ((0, jsx_runtime_1.jsxs)(react_2.Popover, { isOpen: isPaginationPopoverOpen, onClose: () => setIsPaginationPopoverOpen(false), placement: "bottom-end", children: [(0, jsx_runtime_1.jsx)(react_2.PopoverTrigger, { children: (0, jsx_runtime_1.jsx)(react_2.IconButton, { "aria-label": "Pagination", size: "sm", variant: "ghost", icon: (0, jsx_runtime_1.jsx)(lucide_react_1.EllipsisVertical, { size: 18 }), color: theme.colors.text[500], _hover: {
408
+ .flatMap((tool, i) => (i === 0 ? [tool] : [(0, jsx_runtime_1.jsx)(Divider_1.default, {}, `divider-${i}`), tool])), (0, jsx_runtime_1.jsx)(ActiveFilters_1.default, { columns: columnsList, columnsSearch: columnsSearch, setColumnsSearch: setColumnsSearch }), (0, jsx_runtime_1.jsxs)(react_2.Box, { ml: "auto", display: "flex", alignItems: "center", gap: 2, children: [groupLoadMoreActive && loadMorePosition === "top" && (groupLoadMoreCaption || canGroupLoadMore) && ((0, jsx_runtime_1.jsxs)(react_2.Box, { display: "flex", alignItems: "center", gap: 2, flex: "0 0 auto", children: [groupLoadMoreCaption && ((0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "0.75rem", color: theme.colors.text[500], whiteSpace: "nowrap", children: groupLoadMoreCaption })), canGroupLoadMore && ((0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "outline", colorScheme: "gray", isLoading: isLoadingMore, loadingText: loadMoreText, onClick: handleGroupLoadMore, label: loadMoreText }))] })), (isPagination || isServerPagination) && !isGrouped && !canInfinite && !isCompactHeader && ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(Pagination_1.default, { currentPage: currentPage, setCurrentPage: setCurrentPage, rowsPerPage: rowsPerPage, pages: pages, paginationText: tablePaginationText, handlePageSizeChange: handlePageSizeChange, dataLength: tableData.length, isServerPagination: isServerPagination, paginationSelectOptions: paginationSelectOptions }) })), (isPagination || isServerPagination) && !isGrouped && !canInfinite && isCompactHeader && ((0, jsx_runtime_1.jsxs)(react_2.Popover, { isOpen: isPaginationPopoverOpen, onClose: () => setIsPaginationPopoverOpen(false), placement: "bottom-end", children: [(0, jsx_runtime_1.jsx)(react_2.PopoverTrigger, { children: (0, jsx_runtime_1.jsx)(react_2.IconButton, { "aria-label": "Pagination", size: "sm", variant: "ghost", icon: (0, jsx_runtime_1.jsx)(lucide_react_1.EllipsisVertical, { size: 18 }), color: theme.colors.text[500], _hover: {
410
409
  color: theme.colors.accentText,
411
410
  }, onClick: () => setIsPaginationPopoverOpen((open) => !open) }) }), (0, jsx_runtime_1.jsx)(react_2.Portal, { children: (0, jsx_runtime_1.jsx)(react_2.PopoverContent, { maxW: "22rem", p: 2, zIndex: 1600, bg: theme.colors.surfaceRaised, boxShadow: "lg", children: (0, jsx_runtime_1.jsx)(react_2.PopoverBody, { p: 0, children: (0, jsx_runtime_1.jsx)(Pagination_1.default, { currentPage: currentPage, setCurrentPage: setCurrentPage, rowsPerPage: rowsPerPage, pages: pages, paginationText: tablePaginationText, handlePageSizeChange: handlePageSizeChange, dataLength: tableData.length, isServerPagination: isServerPagination, paginationSelectOptions: paginationSelectOptions }) }) }) })] }))] })] }), (0, jsx_runtime_1.jsxs)(react_2.TableContainer, { ref: tableContainerRef, position: "relative", h: isTableLoading ? tableMaxH : undefined, maxH: !isTableLoading ? tableMaxH : undefined, pb: isTableLoading ? 0 : compactScrollbarPadding, overflowY: isCompactRows ? "hidden" : "auto", overflowX: "auto", sx: {
412
411
  ...(0, scrollShadow_1.scrollShadowStyles)(theme.colors.background[50]),
@@ -436,5 +435,5 @@ function Table({ data, columns, onSelection, isLoading, isCheckbox = false, free
436
435
  backgroundColor: "transparent",
437
436
  zIndex: 999,
438
437
  },
439
- }, children: [(0, jsx_runtime_1.jsx)(react_3.Thead, { position: "sticky", top: 0, zIndex: 4, bg: variantTokens.header.bg, children: (0, jsx_runtime_1.jsx)(TableHeader_1.default, { columns: columnsList, isCheckbox: isCheckbox, freezedTextColor: freezedTextColor !== null && freezedTextColor !== void 0 ? freezedTextColor : theme.colors.text[500], handleSort: handleSort, headerRefs: headerRefs, columnWidths: columnWidths, columnsSort: columnsSort, noBorders: noBorders, handleCheckbox: handleCheckbox, isLoading: isTableLoading, checked: headerChecked, isContent: isContent, isLink: isLink, isActionFreeze: isActionFreeze, setColumnsSearch: setColumnsSearch, columnsSearch: columnsSearch, isSelecting: isSelecting }) }), (0, jsx_runtime_1.jsx)(react_3.Tbody, { children: (0, jsx_runtime_1.jsx)(TableBody_1.default, { data: isGrouped ? groupedSource : _filteredData, groups: renderGroups, onAddItem: onAddItem, columns: columnsList, startRow: isGrouped ? 0 : startRow, scrollContainerRef: tableContainerRef, isCheckbox: isCheckbox, columnWidths: columnWidths, noBorders: noBorders, freezedBgColor: freezedBgColor !== null && freezedBgColor !== void 0 ? freezedBgColor : theme.colors.backgroundColor.secondary, freezedTextColor: freezedTextColor !== null && freezedTextColor !== void 0 ? freezedTextColor : theme.colors.text[500], handleCheckbox: handleCheckbox, selections: selection, isLoading: isTableLoading, loadingSkeletonRows: loadingSkeletonRows, onRowClick: onRowClick, isContent: isContent, isLink: isLink, isActionFreeze: isActionFreeze, density: densityState, stripe: stripe, emptyState: emptyState }) })] }), canInfinite && isLoadingMore && ((0, jsx_runtime_1.jsxs)(react_2.Flex, { justify: "center", align: "center", py: 3, gap: 2, children: [(0, jsx_runtime_1.jsx)(react_2.Spinner, { size: "sm", color: theme.colors.accentText }), (0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "0.75rem", color: theme.colors.text[500], children: "Loading more\u2026" })] }))] }), groupLoadMoreActive && loadMorePosition === "bottom" && (groupLoadMoreCaption || canGroupLoadMore) && ((0, jsx_runtime_1.jsxs)(react_2.Flex, { justify: "center", align: "center", gap: 3, py: 3, borderTop: `0.063rem solid ${theme.colors.boxborder[200]}`, children: [groupLoadMoreCaption && ((0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "0.75rem", color: theme.colors.text[500], children: groupLoadMoreCaption })), canGroupLoadMore && ((0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "outline", colorScheme: "gray", isLoading: isLoadingMore, loadingText: loadMoreText, onClick: handleGroupLoadMore, label: loadMoreText }))] }))] })] })] })] }));
438
+ }, children: [(0, jsx_runtime_1.jsx)(react_3.Thead, { position: "sticky", top: 0, zIndex: 4, bg: variantTokens.header.bg, children: (0, jsx_runtime_1.jsx)(TableHeader_1.default, { columns: columnsList, isCheckbox: isCheckbox, freezedTextColor: freezedTextColor !== null && freezedTextColor !== void 0 ? freezedTextColor : theme.colors.text[500], handleSort: handleSort, headerRefs: headerRefs, columnWidths: columnWidths, slotRef: slotRef, slotWidth: slotWidth, columnsSort: columnsSort, noBorders: noBorders, handleCheckbox: handleCheckbox, isLoading: isTableLoading, checked: headerChecked, isContent: isContent, isLink: isLink, isActionFreeze: isActionFreeze, setColumnsSearch: setColumnsSearch, columnsSearch: columnsSearch, isSelecting: isSelecting }) }), (0, jsx_runtime_1.jsx)(react_3.Tbody, { children: (0, jsx_runtime_1.jsx)(TableBody_1.default, { data: isGrouped ? groupedSource : _filteredData, groups: renderGroups, onAddItem: onAddItem, columns: columnsList, startRow: isGrouped ? 0 : startRow, rowsPerPage: rowsPerPage, scrollContainerRef: tableContainerRef, isCheckbox: isCheckbox, columnWidths: columnWidths, slotWidth: slotWidth, noBorders: noBorders, freezedBgColor: freezedBgColor !== null && freezedBgColor !== void 0 ? freezedBgColor : theme.colors.backgroundColor.secondary, freezedTextColor: freezedTextColor !== null && freezedTextColor !== void 0 ? freezedTextColor : theme.colors.text[500], handleCheckbox: handleCheckbox, selections: selection, isLoading: isTableLoading, loadingSkeletonRows: loadingSkeletonRows, onRowClick: onRowClick, isContent: isContent, isLink: isLink, isActionFreeze: isActionFreeze, density: densityState, stripe: stripe, emptyState: emptyState }) })] }), canInfinite && isLoadingMore && ((0, jsx_runtime_1.jsxs)(react_2.Flex, { justify: "center", align: "center", py: 3, gap: 2, children: [(0, jsx_runtime_1.jsx)(react_2.Spinner, { size: "sm", color: theme.colors.accentText }), (0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "0.75rem", color: theme.colors.text[500], children: "Loading more\u2026" })] }))] }), groupLoadMoreActive && loadMorePosition === "bottom" && (groupLoadMoreCaption || canGroupLoadMore) && ((0, jsx_runtime_1.jsxs)(react_2.Flex, { justify: "center", align: "center", gap: 3, py: 3, borderTop: `0.063rem solid ${theme.colors.boxborder[200]}`, children: [groupLoadMoreCaption && ((0, jsx_runtime_1.jsx)(react_2.Box, { fontSize: "0.75rem", color: theme.colors.text[500], children: groupLoadMoreCaption })), canGroupLoadMore && ((0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "outline", colorScheme: "gray", isLoading: isLoadingMore, loadingText: loadMoreText, onClick: handleGroupLoadMore, label: loadMoreText }))] }))] })] })] })] }));
440
439
  }