prime-ui-kit 0.19.0 → 0.20.1

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 (85) hide show
  1. package/README.md +1 -1
  2. package/dist/chunks/{chunk-RZNGLELR.js → chunk-3PY52JP3.js} +1603 -1609
  3. package/dist/chunks/{chunk-WYCTXD63.js → chunk-4374EBWV.js} +3593 -2889
  4. package/dist/chunks/{chunk-ZTZ2ML2B.js → chunk-4KONMO7Z.js} +1 -1
  5. package/dist/color-picker.js +2 -2
  6. package/dist/components/data-table/ColumnsMenu.d.ts +34 -8
  7. package/dist/components/data-table/DataTable.d.ts +31 -5
  8. package/dist/components/data-table/DataTableColumnsMenu.d.ts +45 -0
  9. package/dist/components/data-table/Head.d.ts +14 -8
  10. package/dist/components/data-table/Row.d.ts +8 -8
  11. package/dist/components/data-table/StateRows.d.ts +5 -5
  12. package/dist/components/data-table/columnOrder.d.ts +14 -0
  13. package/dist/components/data-table/reorder.d.ts +15 -5
  14. package/dist/components/data-table/types.d.ts +5 -0
  15. package/dist/components/data-table/useFrozenColumns.d.ts +6 -2
  16. package/dist/components/datepicker/DatepickerPanel.d.ts +1 -1
  17. package/dist/components/dnd/Dnd.d.ts +9 -5
  18. package/dist/components/dnd/inPlaceRow.d.ts +7 -0
  19. package/dist/components/dnd/useDragSource.d.ts +2 -0
  20. package/dist/components/dnd/useSortableList.d.ts +5 -0
  21. package/dist/components/field-list/FieldList.d.ts +34 -12
  22. package/dist/components/gantt/Gantt.d.ts +1 -1
  23. package/dist/components/index.d.ts +2 -0
  24. package/dist/components/scroll-container/ScrollContainer.d.ts +1 -1
  25. package/dist/index.css +1 -1
  26. package/dist/index.js +4 -2
  27. package/dist/internal/ToolRow.d.ts +23 -0
  28. package/dist/internal/fieldCell.d.ts +0 -6
  29. package/dist/layout/page/Page.d.ts +7 -7
  30. package/dist/skill/anti-slop.md +43 -12
  31. package/dist/skill/api-contract.md +1 -1
  32. package/dist/skill/cheatsheet.md +7 -3
  33. package/dist/skill/checklist.md +4 -1
  34. package/dist/skill/choosing.md +1 -0
  35. package/dist/skill/components.md +1 -1
  36. package/dist/skill/composition.md +137 -20
  37. package/dist/skill/reference/components/data-table/COMPONENT.md +101 -40
  38. package/dist/skill/reference/components/data-table/examples/column-order.tsx +152 -0
  39. package/dist/skill/reference/components/data-table/examples/columns-visibility.tsx +20 -11
  40. package/dist/skill/reference/components/data-table/examples/controlled.tsx +32 -17
  41. package/dist/skill/reference/components/data-table/examples/examples.module.css +14 -36
  42. package/dist/skill/reference/components/data-table/examples/narrow.tsx +24 -11
  43. package/dist/skill/reference/components/data-table/examples/reorder.tsx +24 -2
  44. package/dist/skill/reference/components/data-table/examples/selection.tsx +13 -18
  45. package/dist/skill/reference/components/data-table/examples/server.tsx +45 -31
  46. package/dist/skill/reference/components/data-table/examples/toolbar.tsx +5 -12
  47. package/dist/skill/reference/components/datepicker/COMPONENT.md +2 -2
  48. package/dist/skill/reference/components/dnd/COMPONENT.md +12 -7
  49. package/dist/skill/reference/components/dnd/examples/table-columns.tsx +75 -0
  50. package/dist/skill/reference/components/field-list/COMPONENT.md +70 -43
  51. package/dist/skill/reference/components/field-list/examples/narrow.tsx +108 -33
  52. package/dist/skill/reference/components/field-list/examples/reorder.tsx +1 -1
  53. package/dist/skill/reference/components/field-list/examples/row-menu.tsx +71 -0
  54. package/dist/skill/reference/components/field-list/examples/screen.tsx +2 -1
  55. package/dist/skill/reference/components/field-list/examples/variants.tsx +51 -0
  56. package/dist/skill/reference/components/gantt/COMPONENT.md +4 -4
  57. package/dist/skill/reference/components/scroll-container/COMPONENT.md +1 -1
  58. package/dist/skill/reference/components/smart-filter/COMPONENT.md +2 -2
  59. package/dist/skill/reference/layout/page/COMPONENT.md +8 -5
  60. package/dist/skill/responsive.md +10 -8
  61. package/dist/tokens/semantic.d.ts +1 -1
  62. package/package.json +1 -1
  63. package/src/components/data-table/COMPONENT.md +101 -40
  64. package/src/components/data-table/examples/column-order.tsx +152 -0
  65. package/src/components/data-table/examples/columns-visibility.tsx +20 -11
  66. package/src/components/data-table/examples/controlled.tsx +32 -17
  67. package/src/components/data-table/examples/examples.module.css +14 -36
  68. package/src/components/data-table/examples/narrow.tsx +24 -11
  69. package/src/components/data-table/examples/reorder.tsx +24 -2
  70. package/src/components/data-table/examples/selection.tsx +13 -18
  71. package/src/components/data-table/examples/server.tsx +45 -31
  72. package/src/components/data-table/examples/toolbar.tsx +5 -12
  73. package/src/components/datepicker/COMPONENT.md +2 -2
  74. package/src/components/dnd/COMPONENT.md +12 -7
  75. package/src/components/dnd/examples/table-columns.tsx +75 -0
  76. package/src/components/field-list/COMPONENT.md +70 -43
  77. package/src/components/field-list/examples/narrow.tsx +108 -33
  78. package/src/components/field-list/examples/reorder.tsx +1 -1
  79. package/src/components/field-list/examples/row-menu.tsx +71 -0
  80. package/src/components/field-list/examples/screen.tsx +2 -1
  81. package/src/components/field-list/examples/variants.tsx +51 -0
  82. package/src/components/gantt/COMPONENT.md +4 -4
  83. package/src/components/scroll-container/COMPONENT.md +1 -1
  84. package/src/components/smart-filter/COMPONENT.md +2 -2
  85. package/src/layout/page/COMPONENT.md +8 -5
@@ -4358,8 +4358,8 @@ var Thumbnail = {
4358
4358
  Fallback: ThumbnailFallback
4359
4359
  };
4360
4360
 
4361
- // src/components/popover/Popover.tsx
4362
- import * as React47 from "react";
4361
+ // src/components/tooltip/Tooltip.tsx
4362
+ import * as React45 from "react";
4363
4363
 
4364
4364
  // src/hooks/useSwipeDismiss.ts
4365
4365
  import * as React36 from "react";
@@ -4887,32 +4887,18 @@ function FloatingTrigger({ triggerProps, children, ...forwarded }) {
4887
4887
  return /* @__PURE__ */ jsx26(Slot, { ...forwarded, children: /* @__PURE__ */ jsx26(Slot, { ...triggerProps, children }) });
4888
4888
  }
4889
4889
 
4890
- // src/internal/overlay/useAnchorName.ts
4891
- import * as React41 from "react";
4892
- var CONTROL = "button, a[href], input, select, textarea, [tabindex]";
4893
- function useAnchorName(open, named, anchorRef) {
4894
- const [name, setName] = React41.useState({});
4895
- React41.useLayoutEffect(() => {
4896
- if (!open || named) return;
4897
- const anchor = anchorRef.current;
4898
- if (!anchor) return;
4899
- const control = anchor.matches(CONTROL) ? anchor : getFocusable(anchor)[0] ?? anchor;
4900
- const next = control.id ? { id: control.id } : {
4901
- label: control.getAttribute("aria-label") ?? (control.textContent?.trim() || void 0)
4902
- };
4903
- setName((current) => current.id === next.id && current.label === next.label ? current : next);
4904
- }, [open, named, anchorRef]);
4905
- if (named) return {};
4906
- return name.id ? { "aria-labelledby": name.id } : { "aria-label": name.label };
4907
- }
4890
+ // src/internal/overlay/tooltipSurface.module.css
4891
+ var tooltipSurface_default = {
4892
+ chip: "tooltipSurface_chip"
4893
+ };
4908
4894
 
4909
4895
  // src/internal/overlay/useFloatingLayer.ts
4910
- import * as React45 from "react";
4896
+ import * as React44 from "react";
4911
4897
 
4912
4898
  // src/hooks/useMediaQuery.ts
4913
- import * as React42 from "react";
4899
+ import * as React41 from "react";
4914
4900
  function useMediaQuery(query, enabled = true) {
4915
- const subscribe = React42.useCallback(
4901
+ const subscribe = React41.useCallback(
4916
4902
  (onChange) => {
4917
4903
  if (!enabled || typeof window === "undefined" || !window.matchMedia) return () => {
4918
4904
  };
@@ -4923,11 +4909,11 @@ function useMediaQuery(query, enabled = true) {
4923
4909
  [enabled, query]
4924
4910
  );
4925
4911
  const getSnapshot = () => enabled && typeof window !== "undefined" && !!window.matchMedia ? window.matchMedia(query).matches : false;
4926
- return React42.useSyncExternalStore(subscribe, getSnapshot, () => false);
4912
+ return React41.useSyncExternalStore(subscribe, getSnapshot, () => false);
4927
4913
  }
4928
4914
 
4929
4915
  // src/hooks/useScrollLock.ts
4930
- import * as React43 from "react";
4916
+ import * as React42 from "react";
4931
4917
  var lockCount = 0;
4932
4918
  var saved = null;
4933
4919
  function lockScroll() {
@@ -4952,7 +4938,7 @@ function unlockScroll() {
4952
4938
  }
4953
4939
  }
4954
4940
  function useScrollLock(enabled) {
4955
- React43.useEffect(() => {
4941
+ React42.useEffect(() => {
4956
4942
  if (!enabled) return;
4957
4943
  lockScroll();
4958
4944
  return unlockScroll;
@@ -4960,7 +4946,7 @@ function useScrollLock(enabled) {
4960
4946
  }
4961
4947
 
4962
4948
  // src/internal/overlay/useContainScroll.ts
4963
- import * as React44 from "react";
4949
+ import * as React43 from "react";
4964
4950
  function canScroll(el, deltaY) {
4965
4951
  const { overflowY } = getComputedStyle(el);
4966
4952
  if (overflowY !== "auto" && overflowY !== "scroll") return false;
@@ -4968,7 +4954,7 @@ function canScroll(el, deltaY) {
4968
4954
  return deltaY < 0 ? el.scrollTop > 0 : el.scrollTop + el.clientHeight < el.scrollHeight;
4969
4955
  }
4970
4956
  function useContainScroll(panel) {
4971
- React44.useEffect(() => {
4957
+ React43.useEffect(() => {
4972
4958
  if (!panel) return;
4973
4959
  const onWheel = (event) => {
4974
4960
  for (let el = event.target; el; el = el.parentElement) {
@@ -5001,12 +4987,12 @@ function useFloatingLayer({
5001
4987
  const sheet = useMediaQuery(COMPACT_QUERY, sheetOption);
5002
4988
  const presence = usePresence(open, { exitDuration: sheet ? "base" : exitDuration });
5003
4989
  const mounted = presence.mounted && (open || !skipExit);
5004
- const contentRef = React45.useRef(null);
4990
+ const contentRef = React44.useRef(null);
5005
4991
  const position = usePosition(mounted && !sheet, triggerRef, contentRef, positionOptions);
5006
4992
  useScrollLock(open && sheet);
5007
- const [panel, setPanel] = React45.useState(null);
4993
+ const [panel, setPanel] = React44.useState(null);
5008
4994
  const { attachLayer } = position;
5009
- const panelRef = React45.useCallback(
4995
+ const panelRef = React44.useCallback(
5010
4996
  (node) => {
5011
4997
  attachLayer(node);
5012
4998
  setPanel(node);
@@ -5015,12 +5001,12 @@ function useFloatingLayer({
5015
5001
  );
5016
5002
  const passive = dismiss === "none";
5017
5003
  useContainScroll(open && !sheet && !passive ? panel : null);
5018
- const outsideRef = React45.useRef(false);
5019
- const close = React45.useCallback(() => {
5004
+ const outsideRef = React44.useRef(false);
5005
+ const close = React44.useCallback(() => {
5020
5006
  outsideRef.current = false;
5021
5007
  onOpenChange(false);
5022
5008
  }, [onOpenChange]);
5023
- const dismissOutside = React45.useCallback(() => {
5009
+ const dismissOutside = React44.useCallback(() => {
5024
5010
  outsideRef.current = true;
5025
5011
  onOpenChange(false);
5026
5012
  }, [onOpenChange]);
@@ -5041,7 +5027,7 @@ function useFloatingLayer({
5041
5027
  trap,
5042
5028
  onDismiss
5043
5029
  });
5044
- React45.useEffect(() => {
5030
+ React44.useEffect(() => {
5045
5031
  if (!open || !panel || passive) return;
5046
5032
  outsideRef.current = false;
5047
5033
  if (focusOnOpen) {
@@ -5102,220 +5088,6 @@ function floatingTriggerProps({
5102
5088
  };
5103
5089
  }
5104
5090
 
5105
- // src/internal/overlay/useOpenState.ts
5106
- import * as React46 from "react";
5107
- function useOpenState({
5108
- open,
5109
- defaultOpen = false,
5110
- onOpenChange,
5111
- disabled = false
5112
- }) {
5113
- const [isOpen, setIsOpen] = useControllableState({
5114
- value: open,
5115
- defaultValue: defaultOpen,
5116
- onChange: onOpenChange
5117
- });
5118
- const disabledRef = React46.useRef(disabled);
5119
- disabledRef.current = disabled;
5120
- const setOpen = React46.useCallback(
5121
- (next) => {
5122
- setIsOpen((current) => {
5123
- const value = typeof next === "function" ? next(current && !disabledRef.current) : next;
5124
- return value && disabledRef.current ? current : value;
5125
- });
5126
- },
5127
- [setIsOpen]
5128
- );
5129
- return [isOpen && !disabled, setOpen];
5130
- }
5131
-
5132
- // src/components/popover/Popover.module.css
5133
- var Popover_default = {
5134
- content: "Popover_content",
5135
- header: "Popover_header",
5136
- title: "Popover_title",
5137
- description: "Popover_description",
5138
- actions: "Popover_actions"
5139
- };
5140
-
5141
- // src/components/popover/Popover.tsx
5142
- import { jsx as jsx27 } from "react/jsx-runtime";
5143
- var [PopoverProvider, usePopoverContext] = createComponentContext("Popover");
5144
- function PopoverRoot({
5145
- open,
5146
- defaultOpen = false,
5147
- onOpenChange,
5148
- closeOnOutsideClick = true,
5149
- closeOnEscape = true,
5150
- openOnArrow = false,
5151
- children
5152
- }) {
5153
- const [isOpen, setOpen] = useOpenState({ open, defaultOpen, onOpenChange });
5154
- const id = React47.useId();
5155
- const triggerRef = React47.useRef(null);
5156
- const anchoredRef = React47.useRef(false);
5157
- const value = React47.useMemo(
5158
- () => ({
5159
- isOpen,
5160
- setOpen,
5161
- triggerId: `${id}-trigger`,
5162
- contentId: `${id}-content`,
5163
- triggerRef,
5164
- closeOnOutsideClick,
5165
- closeOnEscape,
5166
- openOnArrow,
5167
- anchoredRef
5168
- }),
5169
- [isOpen, setOpen, id, closeOnOutsideClick, closeOnEscape, openOnArrow]
5170
- );
5171
- return /* @__PURE__ */ jsx27(PopoverProvider, { value, children });
5172
- }
5173
- PopoverRoot.displayName = "Popover.Root";
5174
- function PopoverTrigger(props) {
5175
- const { isOpen, setOpen, triggerId, contentId, triggerRef, openOnArrow } = usePopoverContext("Popover.Trigger");
5176
- return /* @__PURE__ */ jsx27(
5177
- FloatingTrigger,
5178
- {
5179
- ...props,
5180
- triggerProps: {
5181
- ref: triggerRef,
5182
- id: triggerId,
5183
- "aria-haspopup": "dialog",
5184
- "aria-controls": isOpen ? contentId : void 0,
5185
- ...floatingTriggerProps({ open: isOpen, setOpen, openOnArrow })
5186
- }
5187
- }
5188
- );
5189
- }
5190
- PopoverTrigger.displayName = "Popover.Trigger";
5191
- function PopoverAnchor({ children }) {
5192
- const { triggerRef, anchoredRef } = usePopoverContext("Popover.Anchor");
5193
- anchoredRef.current = true;
5194
- return /* @__PURE__ */ jsx27(Slot, { ref: triggerRef, children });
5195
- }
5196
- PopoverAnchor.displayName = "Popover.Anchor";
5197
- function PopoverClose({ children }) {
5198
- const { setOpen } = usePopoverContext("Popover.Close");
5199
- return /* @__PURE__ */ jsx27(Slot, { onClick: () => setOpen(false), children });
5200
- }
5201
- PopoverClose.displayName = "Popover.Close";
5202
- function PopoverContent({
5203
- side = DEFAULT_SIDE,
5204
- align = DEFAULT_ALIGN,
5205
- size = OVERLAY_CONTENT_SIZE,
5206
- width = "auto",
5207
- trapFocus = false,
5208
- initialFocus,
5209
- flush = false,
5210
- className,
5211
- children,
5212
- ...rest
5213
- }) {
5214
- const {
5215
- isOpen,
5216
- setOpen,
5217
- triggerRef,
5218
- contentId,
5219
- closeOnOutsideClick,
5220
- closeOnEscape,
5221
- anchoredRef
5222
- } = usePopoverContext("Popover.Content");
5223
- const floating = useFloatingLayer({
5224
- open: isOpen,
5225
- onOpenChange: setOpen,
5226
- triggerRef,
5227
- side,
5228
- align,
5229
- matchAnchorWidth: width === "trigger" || width === "min-trigger",
5230
- closeOnEscape,
5231
- closeOnOutsideClick,
5232
- focusOnOpen: initialFocus ?? !anchoredRef.current,
5233
- trap: trapFocus,
5234
- tabExit: "edges",
5235
- // A panel driven by typing in its anchor stays next to the field.
5236
- sheet: !anchoredRef.current
5237
- });
5238
- const [titleId, setTitleId] = React47.useState(null);
5239
- const [descriptionId, setDescriptionId] = React47.useState(null);
5240
- const fallbackId = `${contentId}-title`;
5241
- const fallbackDescriptionId = `${contentId}-description`;
5242
- const slots = React47.useMemo(
5243
- () => ({ fallbackId, fallbackDescriptionId, setTitleId, setDescriptionId }),
5244
- [fallbackId, fallbackDescriptionId]
5245
- );
5246
- const anchorName = useAnchorName(isOpen, titleId !== null, triggerRef);
5247
- return /* @__PURE__ */ jsx27(
5248
- FloatingPanel,
5249
- {
5250
- ...rest,
5251
- floating,
5252
- size,
5253
- width,
5254
- scroll: true,
5255
- id: contentId,
5256
- role: "dialog",
5257
- "aria-modal": false,
5258
- ...anchorName,
5259
- "aria-labelledby": titleId ?? anchorName["aria-labelledby"],
5260
- "aria-describedby": descriptionId ?? void 0,
5261
- tabIndex: -1,
5262
- "data-flush": flush || void 0,
5263
- className: cx(fieldTierClass, Popover_default.content, className),
5264
- children: /* @__PURE__ */ jsx27(PopoverSlotsContext.Provider, { value: slots, children })
5265
- }
5266
- );
5267
- }
5268
- PopoverContent.displayName = "Popover.Content";
5269
- var PopoverSlotsContext = React47.createContext(null);
5270
- function useSlotId(id, kind) {
5271
- const slots = React47.useContext(PopoverSlotsContext);
5272
- const resolved = id ?? (kind === "title" ? slots?.fallbackId : slots?.fallbackDescriptionId);
5273
- const register = kind === "title" ? slots?.setTitleId : slots?.setDescriptionId;
5274
- React47.useLayoutEffect(() => {
5275
- if (!register || !resolved) return;
5276
- register(resolved);
5277
- return () => register(null);
5278
- }, [register, resolved]);
5279
- return resolved;
5280
- }
5281
- function PopoverHeader({ className, ...rest }) {
5282
- return /* @__PURE__ */ jsx27("div", { className: cx(Popover_default.header, className), ...rest });
5283
- }
5284
- PopoverHeader.displayName = "Popover.Header";
5285
- function PopoverTitle({ className, id, ...rest }) {
5286
- const resolvedId = useSlotId(id, "title");
5287
- return /* @__PURE__ */ jsx27("h2", { id: resolvedId, className: cx(Popover_default.title, className), ...rest });
5288
- }
5289
- PopoverTitle.displayName = "Popover.Title";
5290
- function PopoverDescription({ className, id, ...rest }) {
5291
- const resolvedId = useSlotId(id, "description");
5292
- return /* @__PURE__ */ jsx27("p", { id: resolvedId, className: cx(Popover_default.description, className), ...rest });
5293
- }
5294
- PopoverDescription.displayName = "Popover.Description";
5295
- function PopoverActions({ className, ...rest }) {
5296
- return /* @__PURE__ */ jsx27("div", { className: cx(Popover_default.actions, className), ...rest });
5297
- }
5298
- PopoverActions.displayName = "Popover.Actions";
5299
- var Popover = {
5300
- Root: PopoverRoot,
5301
- Trigger: PopoverTrigger,
5302
- Anchor: PopoverAnchor,
5303
- Content: PopoverContent,
5304
- Header: PopoverHeader,
5305
- Title: PopoverTitle,
5306
- Description: PopoverDescription,
5307
- Actions: PopoverActions,
5308
- Close: PopoverClose
5309
- };
5310
-
5311
- // src/components/tooltip/Tooltip.tsx
5312
- import * as React48 from "react";
5313
-
5314
- // src/internal/overlay/tooltipSurface.module.css
5315
- var tooltipSurface_default = {
5316
- chip: "tooltipSurface_chip"
5317
- };
5318
-
5319
5091
  // src/components/tooltip/Tooltip.module.css
5320
5092
  var Tooltip_default = {
5321
5093
  content: "Tooltip_content",
@@ -5325,7 +5097,7 @@ var Tooltip_default = {
5325
5097
  };
5326
5098
 
5327
5099
  // src/components/tooltip/Tooltip.tsx
5328
- import { jsx as jsx28, jsxs as jsxs15 } from "react/jsx-runtime";
5100
+ import { jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
5329
5101
  var DEFAULT_DELAY_MS = 400;
5330
5102
  var DEFAULT_SKIP_DELAY_MS = 300;
5331
5103
  var CLOSE_GRACE_MS = 100;
@@ -5346,17 +5118,17 @@ function createTooltipGroup(delayDuration, skipDelayDuration) {
5346
5118
  };
5347
5119
  }
5348
5120
  var defaultGroup = createTooltipGroup(DEFAULT_DELAY_MS, DEFAULT_SKIP_DELAY_MS);
5349
- var TooltipGroupContext = React48.createContext(defaultGroup);
5121
+ var TooltipGroupContext = React45.createContext(defaultGroup);
5350
5122
  function TooltipProvider({
5351
5123
  delayDuration = DEFAULT_DELAY_MS,
5352
5124
  skipDelayDuration = DEFAULT_SKIP_DELAY_MS,
5353
5125
  children
5354
5126
  }) {
5355
- const group = React48.useMemo(
5127
+ const group = React45.useMemo(
5356
5128
  () => createTooltipGroup(delayDuration, skipDelayDuration),
5357
5129
  [delayDuration, skipDelayDuration]
5358
5130
  );
5359
- return /* @__PURE__ */ jsx28(TooltipGroupContext.Provider, { value: group, children });
5131
+ return /* @__PURE__ */ jsx27(TooltipGroupContext.Provider, { value: group, children });
5360
5132
  }
5361
5133
  var [TooltipRootProvider, useTooltipRootContext] = createComponentContext("Tooltip");
5362
5134
  function TooltipRoot({
@@ -5366,34 +5138,34 @@ function TooltipRoot({
5366
5138
  onOpenChange,
5367
5139
  delayDuration: delayProp
5368
5140
  }) {
5369
- const group = React48.useContext(TooltipGroupContext);
5141
+ const group = React45.useContext(TooltipGroupContext);
5370
5142
  const delayDuration = delayProp ?? group.delayDuration;
5371
5143
  const [isOpen, setIsOpen] = useControllableState({
5372
5144
  value: open,
5373
5145
  defaultValue: defaultOpen ?? false,
5374
5146
  onChange: onOpenChange
5375
5147
  });
5376
- const [instant, setInstant] = React48.useState(false);
5377
- const triggerRef = React48.useRef(null);
5378
- const timerRef = React48.useRef(void 0);
5379
- const contentId = React48.useId();
5380
- const cancelPending = React48.useCallback(() => clearTimeout(timerRef.current), []);
5381
- const closeInstantlyRef = React48.useRef(() => {
5148
+ const [instant, setInstant] = React45.useState(false);
5149
+ const triggerRef = React45.useRef(null);
5150
+ const timerRef = React45.useRef(void 0);
5151
+ const contentId = React45.useId();
5152
+ const cancelPending = React45.useCallback(() => clearTimeout(timerRef.current), []);
5153
+ const closeInstantlyRef = React45.useRef(() => {
5382
5154
  });
5383
5155
  closeInstantlyRef.current = () => {
5384
5156
  clearTimeout(timerRef.current);
5385
5157
  setInstant(true);
5386
5158
  setIsOpen(false);
5387
5159
  };
5388
- const closeInstantly = React48.useCallback(() => closeInstantlyRef.current(), []);
5389
- const show = React48.useCallback(
5160
+ const closeInstantly = React45.useCallback(() => closeInstantlyRef.current(), []);
5161
+ const show = React45.useCallback(
5390
5162
  (asInstant) => {
5391
5163
  setInstant(asInstant);
5392
5164
  setIsOpen(true);
5393
5165
  },
5394
5166
  [setIsOpen]
5395
5167
  );
5396
- const scheduleOpen = React48.useCallback(() => {
5168
+ const scheduleOpen = React45.useCallback(() => {
5397
5169
  clearTimeout(timerRef.current);
5398
5170
  if (group.isWarm() || delayDuration <= 0) {
5399
5171
  show(group.isWarm());
@@ -5401,22 +5173,22 @@ function TooltipRoot({
5401
5173
  }
5402
5174
  timerRef.current = setTimeout(() => show(false), delayDuration);
5403
5175
  }, [delayDuration, group, show]);
5404
- const close = React48.useCallback(() => {
5176
+ const close = React45.useCallback(() => {
5405
5177
  clearTimeout(timerRef.current);
5406
5178
  setInstant(false);
5407
5179
  setIsOpen(false);
5408
5180
  }, [setIsOpen]);
5409
- const scheduleClose = React48.useCallback(() => {
5181
+ const scheduleClose = React45.useCallback(() => {
5410
5182
  clearTimeout(timerRef.current);
5411
5183
  timerRef.current = setTimeout(close, CLOSE_GRACE_MS);
5412
5184
  }, [close]);
5413
- React48.useEffect(() => {
5185
+ React45.useEffect(() => {
5414
5186
  if (!isOpen) return;
5415
5187
  group.opened(closeInstantly);
5416
5188
  return () => group.closed(closeInstantly);
5417
5189
  }, [isOpen, group, closeInstantly]);
5418
- React48.useEffect(() => () => clearTimeout(timerRef.current), []);
5419
- const value = React48.useMemo(
5190
+ React45.useEffect(() => () => clearTimeout(timerRef.current), []);
5191
+ const value = React45.useMemo(
5420
5192
  () => ({
5421
5193
  isOpen,
5422
5194
  instant,
@@ -5429,20 +5201,20 @@ function TooltipRoot({
5429
5201
  }),
5430
5202
  [isOpen, instant, contentId, scheduleOpen, scheduleClose, cancelPending, close]
5431
5203
  );
5432
- return /* @__PURE__ */ jsx28(TooltipRootProvider, { value, children });
5204
+ return /* @__PURE__ */ jsx27(TooltipRootProvider, { value, children });
5433
5205
  }
5434
5206
  var BUTTON = 'button:not([role]), [role="button"]';
5435
5207
  function TooltipTrigger(props) {
5436
5208
  const { children } = props;
5437
5209
  const { isOpen, triggerRef, contentId, scheduleOpen, scheduleClose, close } = useTooltipRootContext("Tooltip.Trigger");
5438
- const pressedRef = React48.useRef(false);
5210
+ const pressedRef = React45.useRef(false);
5439
5211
  const childProps = children.props;
5440
5212
  const inheritedDisabled = useInheritedDisabled();
5441
- const [domDisabled, setDomDisabled] = React48.useState(false);
5213
+ const [domDisabled, setDomDisabled] = React45.useState(false);
5442
5214
  const disabledChild = childProps.disabled === true || inheritedDisabled && domDisabled;
5443
- const [ownTabStop, setOwnTabStop] = React48.useState(true);
5444
- const [buttonHost, setButtonHost] = React48.useState(false);
5445
- React48.useLayoutEffect(() => {
5215
+ const [ownTabStop, setOwnTabStop] = React45.useState(true);
5216
+ const [buttonHost, setButtonHost] = React45.useState(false);
5217
+ React45.useLayoutEffect(() => {
5446
5218
  const node = triggerRef.current;
5447
5219
  if (!node) return;
5448
5220
  const host = node.hasAttribute("data-disabled-host");
@@ -5454,9 +5226,9 @@ function TooltipTrigger(props) {
5454
5226
  if (!disabledChild) setOwnTabStop(childProps.tabIndex !== void 0 || hasNativeTabStop(node));
5455
5227
  });
5456
5228
  const madeFocusable = disabledChild || !ownTabStop;
5457
- const generatedId = React48.useId();
5229
+ const generatedId = React45.useId();
5458
5230
  const controlId = typeof childProps.id === "string" ? childProps.id : generatedId;
5459
- return /* @__PURE__ */ jsx28(
5231
+ return /* @__PURE__ */ jsx27(
5460
5232
  FloatingTrigger,
5461
5233
  {
5462
5234
  ...props,
@@ -5488,13 +5260,13 @@ function TooltipTrigger(props) {
5488
5260
  children: disabledChild ? (
5489
5261
  // Around a button the host is the one button assistive tech meets: disabled, named by the
5490
5262
  // control, which itself is out of reach (no pointer events, no focus) and out of the tree.
5491
- /* @__PURE__ */ jsx28(
5263
+ /* @__PURE__ */ jsx27(
5492
5264
  "span",
5493
5265
  {
5494
5266
  className: Tooltip_default.disabledHost,
5495
5267
  "data-disabled-host": "",
5496
5268
  ...buttonHost ? { role: "button", "aria-disabled": "true", "aria-labelledby": controlId } : null,
5497
- children: buttonHost ? React48.cloneElement(
5269
+ children: buttonHost ? React45.cloneElement(
5498
5270
  children,
5499
5271
  {
5500
5272
  id: controlId,
@@ -5558,7 +5330,7 @@ function TooltipContent({
5558
5330
  ...toDataAttributes({ align, instant: instant ? true : void 0 }),
5559
5331
  children: [
5560
5332
  children,
5561
- /* @__PURE__ */ jsx28(
5333
+ /* @__PURE__ */ jsx27(
5562
5334
  "svg",
5563
5335
  {
5564
5336
  className: Tooltip_default.arrow,
@@ -5566,7 +5338,7 @@ function TooltipContent({
5566
5338
  preserveAspectRatio: "none",
5567
5339
  "aria-hidden": "true",
5568
5340
  focusable: "false",
5569
- children: /* @__PURE__ */ jsx28("path", { d: arrow.d })
5341
+ children: /* @__PURE__ */ jsx27("path", { d: arrow.d })
5570
5342
  }
5571
5343
  )
5572
5344
  ]
@@ -5584,23 +5356,251 @@ var Tooltip = {
5584
5356
  Content: TooltipContent
5585
5357
  };
5586
5358
 
5587
- // src/components/progress-bar/ProgressBar.tsx
5588
- import * as React50 from "react";
5589
-
5590
- // src/internal/ProgressLegend.module.css
5591
- var ProgressLegend_default = {
5592
- legend: "ProgressLegend_legend",
5593
- skeleton: "ProgressLegend_skeleton",
5594
- item: "ProgressLegend_item",
5595
- swatch: "ProgressLegend_swatch",
5596
- name: "ProgressLegend_name",
5597
- value: "ProgressLegend_value",
5598
- share: "ProgressLegend_share",
5599
- skeletonRow: "ProgressLegend_skeletonRow"
5600
- };
5359
+ // src/components/popover/Popover.tsx
5360
+ import * as React48 from "react";
5601
5361
 
5602
- // src/internal/progressSegments.ts
5603
- function resolveValue(value, max) {
5362
+ // src/internal/overlay/useAnchorName.ts
5363
+ import * as React46 from "react";
5364
+ var CONTROL = "button, a[href], input, select, textarea, [tabindex]";
5365
+ function useAnchorName(open, named, anchorRef) {
5366
+ const [name, setName] = React46.useState({});
5367
+ React46.useLayoutEffect(() => {
5368
+ if (!open || named) return;
5369
+ const anchor = anchorRef.current;
5370
+ if (!anchor) return;
5371
+ const control = anchor.matches(CONTROL) ? anchor : getFocusable(anchor)[0] ?? anchor;
5372
+ const next = control.id ? { id: control.id } : {
5373
+ label: control.getAttribute("aria-label") ?? (control.textContent?.trim() || void 0)
5374
+ };
5375
+ setName((current) => current.id === next.id && current.label === next.label ? current : next);
5376
+ }, [open, named, anchorRef]);
5377
+ if (named) return {};
5378
+ return name.id ? { "aria-labelledby": name.id } : { "aria-label": name.label };
5379
+ }
5380
+
5381
+ // src/internal/overlay/useOpenState.ts
5382
+ import * as React47 from "react";
5383
+ function useOpenState({
5384
+ open,
5385
+ defaultOpen = false,
5386
+ onOpenChange,
5387
+ disabled = false
5388
+ }) {
5389
+ const [isOpen, setIsOpen] = useControllableState({
5390
+ value: open,
5391
+ defaultValue: defaultOpen,
5392
+ onChange: onOpenChange
5393
+ });
5394
+ const disabledRef = React47.useRef(disabled);
5395
+ disabledRef.current = disabled;
5396
+ const setOpen = React47.useCallback(
5397
+ (next) => {
5398
+ setIsOpen((current) => {
5399
+ const value = typeof next === "function" ? next(current && !disabledRef.current) : next;
5400
+ return value && disabledRef.current ? current : value;
5401
+ });
5402
+ },
5403
+ [setIsOpen]
5404
+ );
5405
+ return [isOpen && !disabled, setOpen];
5406
+ }
5407
+
5408
+ // src/components/popover/Popover.module.css
5409
+ var Popover_default = {
5410
+ content: "Popover_content",
5411
+ header: "Popover_header",
5412
+ title: "Popover_title",
5413
+ description: "Popover_description",
5414
+ actions: "Popover_actions"
5415
+ };
5416
+
5417
+ // src/components/popover/Popover.tsx
5418
+ import { jsx as jsx28 } from "react/jsx-runtime";
5419
+ var [PopoverProvider, usePopoverContext] = createComponentContext("Popover");
5420
+ function PopoverRoot({
5421
+ open,
5422
+ defaultOpen = false,
5423
+ onOpenChange,
5424
+ closeOnOutsideClick = true,
5425
+ closeOnEscape = true,
5426
+ openOnArrow = false,
5427
+ children
5428
+ }) {
5429
+ const [isOpen, setOpen] = useOpenState({ open, defaultOpen, onOpenChange });
5430
+ const id = React48.useId();
5431
+ const triggerRef = React48.useRef(null);
5432
+ const anchoredRef = React48.useRef(false);
5433
+ const value = React48.useMemo(
5434
+ () => ({
5435
+ isOpen,
5436
+ setOpen,
5437
+ triggerId: `${id}-trigger`,
5438
+ contentId: `${id}-content`,
5439
+ triggerRef,
5440
+ closeOnOutsideClick,
5441
+ closeOnEscape,
5442
+ openOnArrow,
5443
+ anchoredRef
5444
+ }),
5445
+ [isOpen, setOpen, id, closeOnOutsideClick, closeOnEscape, openOnArrow]
5446
+ );
5447
+ return /* @__PURE__ */ jsx28(PopoverProvider, { value, children });
5448
+ }
5449
+ PopoverRoot.displayName = "Popover.Root";
5450
+ function PopoverTrigger(props) {
5451
+ const { isOpen, setOpen, triggerId, contentId, triggerRef, openOnArrow } = usePopoverContext("Popover.Trigger");
5452
+ return /* @__PURE__ */ jsx28(
5453
+ FloatingTrigger,
5454
+ {
5455
+ ...props,
5456
+ triggerProps: {
5457
+ ref: triggerRef,
5458
+ id: triggerId,
5459
+ "aria-haspopup": "dialog",
5460
+ "aria-controls": isOpen ? contentId : void 0,
5461
+ ...floatingTriggerProps({ open: isOpen, setOpen, openOnArrow })
5462
+ }
5463
+ }
5464
+ );
5465
+ }
5466
+ PopoverTrigger.displayName = "Popover.Trigger";
5467
+ function PopoverAnchor({ children }) {
5468
+ const { triggerRef, anchoredRef } = usePopoverContext("Popover.Anchor");
5469
+ anchoredRef.current = true;
5470
+ return /* @__PURE__ */ jsx28(Slot, { ref: triggerRef, children });
5471
+ }
5472
+ PopoverAnchor.displayName = "Popover.Anchor";
5473
+ function PopoverClose({ children }) {
5474
+ const { setOpen } = usePopoverContext("Popover.Close");
5475
+ return /* @__PURE__ */ jsx28(Slot, { onClick: () => setOpen(false), children });
5476
+ }
5477
+ PopoverClose.displayName = "Popover.Close";
5478
+ function PopoverContent({
5479
+ side = DEFAULT_SIDE,
5480
+ align = DEFAULT_ALIGN,
5481
+ size = OVERLAY_CONTENT_SIZE,
5482
+ width = "auto",
5483
+ trapFocus = false,
5484
+ initialFocus,
5485
+ flush = false,
5486
+ className,
5487
+ children,
5488
+ ...rest
5489
+ }) {
5490
+ const {
5491
+ isOpen,
5492
+ setOpen,
5493
+ triggerRef,
5494
+ contentId,
5495
+ closeOnOutsideClick,
5496
+ closeOnEscape,
5497
+ anchoredRef
5498
+ } = usePopoverContext("Popover.Content");
5499
+ const floating = useFloatingLayer({
5500
+ open: isOpen,
5501
+ onOpenChange: setOpen,
5502
+ triggerRef,
5503
+ side,
5504
+ align,
5505
+ matchAnchorWidth: width === "trigger" || width === "min-trigger",
5506
+ closeOnEscape,
5507
+ closeOnOutsideClick,
5508
+ focusOnOpen: initialFocus ?? !anchoredRef.current,
5509
+ trap: trapFocus,
5510
+ tabExit: "edges",
5511
+ // A panel driven by typing in its anchor stays next to the field.
5512
+ sheet: !anchoredRef.current
5513
+ });
5514
+ const [titleId, setTitleId] = React48.useState(null);
5515
+ const [descriptionId, setDescriptionId] = React48.useState(null);
5516
+ const fallbackId = `${contentId}-title`;
5517
+ const fallbackDescriptionId = `${contentId}-description`;
5518
+ const slots = React48.useMemo(
5519
+ () => ({ fallbackId, fallbackDescriptionId, setTitleId, setDescriptionId }),
5520
+ [fallbackId, fallbackDescriptionId]
5521
+ );
5522
+ const anchorName = useAnchorName(isOpen, titleId !== null, triggerRef);
5523
+ return /* @__PURE__ */ jsx28(
5524
+ FloatingPanel,
5525
+ {
5526
+ ...rest,
5527
+ floating,
5528
+ size,
5529
+ width,
5530
+ scroll: true,
5531
+ id: contentId,
5532
+ role: "dialog",
5533
+ "aria-modal": false,
5534
+ ...anchorName,
5535
+ "aria-labelledby": titleId ?? anchorName["aria-labelledby"],
5536
+ "aria-describedby": descriptionId ?? void 0,
5537
+ tabIndex: -1,
5538
+ "data-flush": flush || void 0,
5539
+ className: cx(fieldTierClass, Popover_default.content, className),
5540
+ children: /* @__PURE__ */ jsx28(PopoverSlotsContext.Provider, { value: slots, children })
5541
+ }
5542
+ );
5543
+ }
5544
+ PopoverContent.displayName = "Popover.Content";
5545
+ var PopoverSlotsContext = React48.createContext(null);
5546
+ function useSlotId(id, kind) {
5547
+ const slots = React48.useContext(PopoverSlotsContext);
5548
+ const resolved = id ?? (kind === "title" ? slots?.fallbackId : slots?.fallbackDescriptionId);
5549
+ const register = kind === "title" ? slots?.setTitleId : slots?.setDescriptionId;
5550
+ React48.useLayoutEffect(() => {
5551
+ if (!register || !resolved) return;
5552
+ register(resolved);
5553
+ return () => register(null);
5554
+ }, [register, resolved]);
5555
+ return resolved;
5556
+ }
5557
+ function PopoverHeader({ className, ...rest }) {
5558
+ return /* @__PURE__ */ jsx28("div", { className: cx(Popover_default.header, className), ...rest });
5559
+ }
5560
+ PopoverHeader.displayName = "Popover.Header";
5561
+ function PopoverTitle({ className, id, ...rest }) {
5562
+ const resolvedId = useSlotId(id, "title");
5563
+ return /* @__PURE__ */ jsx28("h2", { id: resolvedId, className: cx(Popover_default.title, className), ...rest });
5564
+ }
5565
+ PopoverTitle.displayName = "Popover.Title";
5566
+ function PopoverDescription({ className, id, ...rest }) {
5567
+ const resolvedId = useSlotId(id, "description");
5568
+ return /* @__PURE__ */ jsx28("p", { id: resolvedId, className: cx(Popover_default.description, className), ...rest });
5569
+ }
5570
+ PopoverDescription.displayName = "Popover.Description";
5571
+ function PopoverActions({ className, ...rest }) {
5572
+ return /* @__PURE__ */ jsx28("div", { className: cx(Popover_default.actions, className), ...rest });
5573
+ }
5574
+ PopoverActions.displayName = "Popover.Actions";
5575
+ var Popover = {
5576
+ Root: PopoverRoot,
5577
+ Trigger: PopoverTrigger,
5578
+ Anchor: PopoverAnchor,
5579
+ Content: PopoverContent,
5580
+ Header: PopoverHeader,
5581
+ Title: PopoverTitle,
5582
+ Description: PopoverDescription,
5583
+ Actions: PopoverActions,
5584
+ Close: PopoverClose
5585
+ };
5586
+
5587
+ // src/components/progress-bar/ProgressBar.tsx
5588
+ import * as React50 from "react";
5589
+
5590
+ // src/internal/ProgressLegend.module.css
5591
+ var ProgressLegend_default = {
5592
+ legend: "ProgressLegend_legend",
5593
+ skeleton: "ProgressLegend_skeleton",
5594
+ item: "ProgressLegend_item",
5595
+ swatch: "ProgressLegend_swatch",
5596
+ name: "ProgressLegend_name",
5597
+ value: "ProgressLegend_value",
5598
+ share: "ProgressLegend_share",
5599
+ skeletonRow: "ProgressLegend_skeletonRow"
5600
+ };
5601
+
5602
+ // src/internal/progressSegments.ts
5603
+ function resolveValue(value, max) {
5604
5604
  const top = max !== void 0 && max > 0 ? max : 100;
5605
5605
  const clamped = Math.min(top, Math.max(Number.isFinite(value) ? value : 0, 0));
5606
5606
  return {
@@ -6790,9 +6790,6 @@ function InputRoot({
6790
6790
  return () => setAffixes((current) => current.filter((item) => item !== affixId));
6791
6791
  }, []);
6792
6792
  const affixIds = affixes.join(" ") || void 0;
6793
- const cell = useFieldCell();
6794
- const cellAction = cell?.action;
6795
- const innerCell = React56.useMemo(() => cell ? { ...cell, action: void 0 } : null, [cell]);
6796
6793
  const contextValue = React56.useMemo(
6797
6794
  () => ({
6798
6795
  size,
@@ -6812,8 +6809,7 @@ function InputRoot({
6812
6809
  setRevealed,
6813
6810
  selectionRef,
6814
6811
  mountedRef,
6815
- suggest,
6816
- cellAction
6812
+ suggest
6817
6813
  }),
6818
6814
  [
6819
6815
  size,
@@ -6829,8 +6825,7 @@ function InputRoot({
6829
6825
  commit,
6830
6826
  hasCommit,
6831
6827
  revealed,
6832
- suggest,
6833
- cellAction
6828
+ suggest
6834
6829
  ]
6835
6830
  );
6836
6831
  const level = strength ? getStrength(strengthValue) : 0;
@@ -6867,7 +6862,7 @@ function InputRoot({
6867
6862
  optionalLabel: labels.optional,
6868
6863
  className: cx(fieldTierClass, Input_default.root, className),
6869
6864
  children: [
6870
- cellAction ? /* @__PURE__ */ jsx36(FieldCellContext, { value: innerCell, children }) : children,
6865
+ children,
6871
6866
  strength ? /* @__PURE__ */ jsx36(
6872
6867
  ProgressBar,
6873
6868
  {
@@ -6886,7 +6881,7 @@ function InputRoot({
6886
6881
  }
6887
6882
  InputRoot.displayName = "Input.Root";
6888
6883
  function InputWrapper({ children, className, ref, ...rest }) {
6889
- const { size, invalid, focusRing, commit, hasCommit, labels, suggest, cellAction } = useInputContext();
6884
+ const { size, invalid, focusRing, commit, hasCommit, labels, suggest } = useInputContext();
6890
6885
  const setRefs = useMergedRefs(suggest?.anchorRef, ref);
6891
6886
  return /* @__PURE__ */ jsxs21(
6892
6887
  "div",
@@ -6902,7 +6897,6 @@ function InputWrapper({ children, className, ref, ...rest }) {
6902
6897
  children: [
6903
6898
  /* @__PURE__ */ jsx36(InputSegmentContext, { value: true, children }),
6904
6899
  hasCommit ? /* @__PURE__ */ jsx36(FieldCommitStatus, { state: commit.state, labels, className: Input_default.status }) : null,
6905
- cellAction,
6906
6900
  suggest ? /* @__PURE__ */ jsx36(InputSuggestionList, { suggest, size }) : null
6907
6901
  ]
6908
6902
  }
@@ -7317,1388 +7311,1388 @@ var EmptyPage = {
7317
7311
  RetryButton: EmptyPageRetryButton
7318
7312
  };
7319
7313
 
7320
- // src/internal/swatch.tsx
7321
- import * as React59 from "react";
7314
+ // src/components/select/Select.tsx
7315
+ import * as React62 from "react";
7322
7316
 
7323
- // src/hooks/useElementSize.ts
7317
+ // src/hooks/useLoadMore.ts
7324
7318
  import * as React58 from "react";
7325
- var rounded = (width, height) => ({
7326
- width: Math.round(width),
7327
- height: Math.round(height)
7328
- });
7329
- var sizeOf = (element) => {
7330
- const rect = element.getBoundingClientRect();
7331
- return rounded(rect.width, rect.height);
7332
- };
7333
- var entrySize = (entry) => {
7334
- const box = entry.borderBoxSize?.[0];
7335
- return box ? rounded(box.inlineSize, box.blockSize) : rounded(entry.contentRect.width, entry.contentRect.height);
7336
- };
7337
- var sameSize = (a, b) => a === b || a !== null && b !== null && a.width === b.width && a.height === b.height;
7338
- function useRefNode(ref, enabled, subscribe) {
7339
- const subscribeRef = React58.useRef(subscribe);
7340
- const active2 = React58.useRef(null);
7319
+ var LIST_ROOT_MARGIN = "0px 0px 48px 0px";
7320
+ var NONE2 = /* @__PURE__ */ Symbol("none");
7321
+ function useLoadMore({
7322
+ enabled,
7323
+ onLoadMore,
7324
+ scrollRef,
7325
+ round,
7326
+ rootMargin = LIST_ROOT_MARGIN
7327
+ }) {
7328
+ const sentinelRef = React58.useRef(null);
7329
+ const handlerRef = React58.useRef(onLoadMore);
7330
+ handlerRef.current = onLoadMore;
7331
+ const askedIn = React58.useRef(NONE2);
7341
7332
  React58.useLayoutEffect(() => {
7342
- subscribeRef.current = subscribe;
7343
- const node = enabled ? ref.current : null;
7344
- if (active2.current?.node === node) return;
7345
- active2.current?.stop();
7346
- active2.current = node ? { node, stop: subscribeRef.current(node) } : null;
7347
- });
7348
- React58.useLayoutEffect(
7349
- () => () => {
7350
- active2.current?.stop();
7351
- active2.current = null;
7352
- },
7353
- []
7354
- );
7355
- }
7356
- function useElementSize(ref, { enabled = true } = {}) {
7357
- const [size, setSize] = React58.useState(null);
7358
- useRefNode(ref, enabled, (node) => {
7359
- const update = (next) => setSize((prev) => sameSize(prev, next) ? prev : next);
7360
- update(sizeOf(node));
7361
- if (typeof ResizeObserver === "undefined") return () => update(null);
7362
- const observer = new ResizeObserver(([entry]) => update(entry ? entrySize(entry) : null));
7363
- observer.observe(node);
7364
- return () => {
7365
- observer.disconnect();
7366
- update(null);
7367
- };
7368
- });
7369
- return size;
7333
+ if (!enabled) askedIn.current = NONE2;
7334
+ }, [enabled]);
7335
+ const request = React58.useCallback(() => {
7336
+ if (!enabled || Object.is(askedIn.current, round)) return;
7337
+ askedIn.current = round;
7338
+ void handlerRef.current?.();
7339
+ }, [enabled, round]);
7340
+ React58.useEffect(() => {
7341
+ const root = scrollRef.current;
7342
+ const target = sentinelRef.current;
7343
+ if (!enabled || !root || !target || typeof IntersectionObserver === "undefined") return;
7344
+ const observer = new IntersectionObserver(
7345
+ ([entry]) => {
7346
+ if (entry?.isIntersecting) request();
7347
+ },
7348
+ { root, rootMargin, threshold: 0 }
7349
+ );
7350
+ observer.observe(target);
7351
+ return () => observer.disconnect();
7352
+ }, [enabled, request, rootMargin, scrollRef]);
7353
+ return { sentinelRef, request };
7370
7354
  }
7371
- function useResizeEffect(ref, onResize, { enabled = true, children = false } = {}) {
7372
- const callback = React58.useRef(onResize);
7373
- React58.useLayoutEffect(() => {
7374
- callback.current = onResize;
7375
- });
7376
- useRefNode(ref, enabled, (node) => {
7377
- if (typeof ResizeObserver === "undefined") return () => {
7378
- };
7379
- const observer = new ResizeObserver(() => callback.current());
7380
- const observeAll = () => {
7381
- observer.observe(node);
7382
- if (children) for (const child of Array.from(node.children)) observer.observe(child);
7383
- };
7384
- observeAll();
7385
- const mutation = children ? new MutationObserver(observeAll) : null;
7386
- mutation?.observe(node, { childList: true });
7387
- return () => {
7388
- mutation?.disconnect();
7389
- observer.disconnect();
7390
- };
7391
- });
7355
+
7356
+ // src/internal/MenuGroup.tsx
7357
+ import * as React59 from "react";
7358
+ import { jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
7359
+ function MenuGroup({ label, className, children, ...rest }) {
7360
+ const labelId = React59.useId();
7361
+ return (
7362
+ // biome-ignore lint/a11y/useSemanticElements: role="group" inside a menu / listbox; <fieldset> is not allowed there
7363
+ /* @__PURE__ */ jsxs23(
7364
+ "div",
7365
+ {
7366
+ ...rest,
7367
+ role: "group",
7368
+ "aria-labelledby": label != null ? labelId : void 0,
7369
+ className: cx(menu_default.group, className),
7370
+ children: [
7371
+ label != null ? /* @__PURE__ */ jsx38("div", { id: labelId, role: "presentation", className: cx(textRole_default.caption, menu_default.groupLabel), children: label }) : null,
7372
+ children
7373
+ ]
7374
+ }
7375
+ )
7376
+ );
7392
7377
  }
7393
7378
 
7394
- // src/internal/swatch.module.css
7395
- var swatch_default = {
7396
- fill: "swatch_fill",
7397
- checker: "swatch_checker",
7398
- checkerboard: "swatch_checkerboard",
7399
- hueFill: "swatch_hueFill",
7400
- tier: "swatch_tier",
7401
- grid: "swatch_grid",
7402
- chip: "swatch_chip",
7403
- swatch: "swatch_swatch",
7404
- trigger: "swatch_trigger",
7405
- check: "swatch_check"
7379
+ // src/components/select/Select.module.css
7380
+ var Select_default = {
7381
+ trigger: "Select_trigger",
7382
+ triggerMain: "Select_triggerMain",
7383
+ value: "Select_value",
7384
+ valueBody: "Select_valueBody",
7385
+ triggerIcon: "Select_triggerIcon",
7386
+ chevron: "Select_chevron",
7387
+ clear: "Select_clear",
7388
+ content: "Select_content",
7389
+ listbox: "Select_listbox",
7390
+ search: "Select_search",
7391
+ group: "Select_group",
7392
+ separator: "Select_separator",
7393
+ actions: "Select_actions",
7394
+ item: "Select_item",
7395
+ itemText: "Select_itemText",
7396
+ itemTitle: "Select_itemTitle",
7397
+ itemDescription: "Select_itemDescription",
7398
+ itemMeta: "Select_itemMeta",
7399
+ media: "Select_media",
7400
+ segment: "Select_segment",
7401
+ segmentTrigger: "Select_segmentTrigger"
7406
7402
  };
7407
7403
 
7408
- // src/internal/swatch.tsx
7409
- import { Fragment as Fragment15, jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
7410
- var COLOR_PRESETS = [
7411
- { value: "#ef4444", label: "\u041A\u0440\u0430\u0441\u043D\u044B\u0439" },
7412
- { value: "#f97316", label: "\u041E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439" },
7413
- { value: "#eab308", label: "\u0416\u0451\u043B\u0442\u044B\u0439" },
7414
- { value: "#22c55e", label: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439" },
7415
- { value: "#14b8a6", label: "\u0411\u0438\u0440\u044E\u0437\u043E\u0432\u044B\u0439" },
7416
- { value: "#5068f5", label: "\u0421\u0438\u043D\u0438\u0439" },
7417
- { value: "#a855f7", label: "\u0424\u0438\u043E\u043B\u0435\u0442\u043E\u0432\u044B\u0439" },
7418
- { value: "#ec4899", label: "\u0420\u043E\u0437\u043E\u0432\u044B\u0439" },
7419
- { value: "#b91c1c", label: "\u0422\u0451\u043C\u043D\u043E-\u043A\u0440\u0430\u0441\u043D\u044B\u0439" },
7420
- { value: "#c2410c", label: "\u0422\u0451\u043C\u043D\u043E-\u043E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439" },
7421
- { value: "#a16207", label: "\u0413\u043E\u0440\u0447\u0438\u0447\u043D\u044B\u0439" },
7422
- { value: "#15803d", label: "\u0422\u0451\u043C\u043D\u043E-\u0437\u0435\u043B\u0451\u043D\u044B\u0439" },
7423
- { value: "#0f766e", label: "\u0422\u0451\u043C\u043D\u043E-\u0431\u0438\u0440\u044E\u0437\u043E\u0432\u044B\u0439" },
7424
- { value: "#2f4ae0", label: "\u0422\u0451\u043C\u043D\u043E-\u0441\u0438\u043D\u0438\u0439" },
7425
- { value: "#7e22ce", label: "\u0422\u0451\u043C\u043D\u043E-\u0444\u0438\u043E\u043B\u0435\u0442\u043E\u0432\u044B\u0439" },
7426
- { value: "#be185d", label: "\u0422\u0451\u043C\u043D\u043E-\u0440\u043E\u0437\u043E\u0432\u044B\u0439" }
7427
- ];
7428
- var PALETTE_COLOR_NAMES = {
7429
- gray: "\u0421\u0435\u0440\u044B\u0439",
7430
- red: "\u041A\u0440\u0430\u0441\u043D\u044B\u0439",
7431
- orange: "\u041E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439",
7432
- yellow: "\u0416\u0451\u043B\u0442\u044B\u0439",
7433
- green: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439",
7434
- teal: "\u0411\u0438\u0440\u044E\u0437\u043E\u0432\u044B\u0439",
7435
- sky: "\u0413\u043E\u043B\u0443\u0431\u043E\u0439",
7436
- blue: "\u0421\u0438\u043D\u0438\u0439",
7437
- purple: "\u0424\u0438\u043E\u043B\u0435\u0442\u043E\u0432\u044B\u0439",
7438
- pink: "\u0420\u043E\u0437\u043E\u0432\u044B\u0439"
7439
- };
7440
- var PALETTE_ORDER = Object.keys(PALETTE_COLOR_NAMES);
7441
- function useSwatchOptions(presets, allowEmpty, emptyLabel) {
7442
- return React59.useMemo(
7443
- () => [
7444
- ...presets.map((preset) => ({ ...preset, contrast: markContrast(preset.value) })),
7445
- ...allowEmpty ? [{ value: null, label: emptyLabel, contrast: "surface" }] : []
7446
- ],
7447
- [presets, allowEmpty, emptyLabel]
7448
- );
7404
+ // src/components/select/SelectItem.tsx
7405
+ import * as React61 from "react";
7406
+
7407
+ // src/internal/nodeText.ts
7408
+ import * as React60 from "react";
7409
+ function nodeText(node) {
7410
+ if (typeof node === "string" || typeof node === "number") return String(node);
7411
+ if (Array.isArray(node)) return node.map(nodeText).join("");
7412
+ if (React60.isValidElement(node)) {
7413
+ return nodeText(node.props.children);
7414
+ }
7415
+ return "";
7449
7416
  }
7450
- function usePaletteOptions(palette, allowEmpty, emptyLabel, names) {
7451
- return React59.useMemo(
7452
- () => [
7453
- ...palette.map((hue) => ({ value: hue, label: names[hue], contrast: "hue" })),
7454
- ...allowEmpty ? [{ value: null, label: emptyLabel, contrast: "surface" }] : []
7455
- ],
7456
- [palette, allowEmpty, emptyLabel, names]
7457
- );
7417
+
7418
+ // src/components/select/selectContext.ts
7419
+ var normalize = (text) => text.trim().toLocaleLowerCase();
7420
+ var [SelectProvider, useSelectContext] = createComponentContext("Select");
7421
+
7422
+ // src/components/select/SelectItem.tsx
7423
+ import { jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
7424
+ function SelectItemIcon({ className, ...rest }) {
7425
+ return /* @__PURE__ */ jsx39("span", { "aria-hidden": "true", className: cx(menu_default.itemIcon, iconSlotClass, className), ...rest });
7458
7426
  }
7459
- var swatchClass = cx(swatch_default.swatch, press_default.press);
7460
- var swatchTriggerClass = cx(swatch_default.trigger, press_default.press);
7461
- var swatchTierClass = cx(fieldTierClass, swatch_default.tier);
7462
- var swatchGridClass = swatch_default.grid;
7463
- var checkerboardClass = swatch_default.checkerboard;
7464
- function SwatchFill({ value, hue = false }) {
7465
- if (value == null) return /* @__PURE__ */ jsx38("span", { "aria-hidden": true, className: swatch_default.checker });
7466
- if (hue) return /* @__PURE__ */ jsx38("span", { "aria-hidden": true, className: cx(swatch_default.fill, swatch_default.hueFill) });
7467
- return /* @__PURE__ */ jsx38("svg", { className: swatch_default.fill, "aria-hidden": "true", viewBox: "0 0 1 1", preserveAspectRatio: "none", children: /* @__PURE__ */ jsx38("rect", { width: "1", height: "1", fill: value }) });
7427
+ SelectItemIcon.displayName = "Select.ItemIcon";
7428
+ var OptionQueryContext = React61.createContext("");
7429
+ function SelectItemText({ children, className, ...rest }) {
7430
+ const query = React61.useContext(OptionQueryContext);
7431
+ return /* @__PURE__ */ jsx39("span", { ...rest, className: cx(Select_default.itemTitle, className), children: highlightChildren(children, query) });
7468
7432
  }
7469
- function SwatchContent({
7470
- value,
7471
- selected,
7472
- hue = false
7433
+ SelectItemText.displayName = "Select.ItemText";
7434
+ function SelectItemDescription({
7435
+ children,
7436
+ className,
7437
+ ...rest
7473
7438
  }) {
7474
- return /* @__PURE__ */ jsxs23(Fragment15, { children: [
7475
- /* @__PURE__ */ jsx38(SwatchFill, { value, hue }),
7476
- /* @__PURE__ */ jsx38(CheckMark, { state: selected ? "checked" : "unchecked", className: swatch_default.check })
7477
- ] });
7439
+ const query = React61.useContext(OptionQueryContext);
7440
+ return /* @__PURE__ */ jsx39("span", { ...rest, className: cx(Select_default.itemDescription, className), children: highlightChildren(children, query) });
7478
7441
  }
7479
- function SwatchChip({ value, className, ...rest }) {
7480
- return /* @__PURE__ */ jsx38("span", { ...rest, "aria-hidden": true, className: cx(swatch_default.chip, className), children: /* @__PURE__ */ jsx38(SwatchFill, { value }) });
7442
+ SelectItemDescription.displayName = "Select.ItemDescription";
7443
+ function SelectItemMeta({ children, className, ...rest }) {
7444
+ return /* @__PURE__ */ jsx39("span", { ...rest, className: cx(Select_default.itemMeta, className), children });
7481
7445
  }
7482
- function parseHexColor(text) {
7483
- const hex = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(text.trim())?.[1]?.toLowerCase();
7484
- if (!hex) return null;
7485
- return `#${hex.length === 3 ? [...hex].map((c) => c + c).join("") : hex}`;
7446
+ SelectItemMeta.displayName = "Select.ItemMeta";
7447
+ function splitItemChildren(children) {
7448
+ const parts = {
7449
+ leading: [],
7450
+ body: [],
7451
+ meta: [],
7452
+ rich: false,
7453
+ title: "",
7454
+ description: ""
7455
+ };
7456
+ let plain = "";
7457
+ for (const child of React61.Children.toArray(children)) {
7458
+ if (!React61.isValidElement(child)) {
7459
+ plain += nodeText(child);
7460
+ parts.body.push(child);
7461
+ } else if (child.type === React61.Fragment) {
7462
+ const inner = splitItemChildren(child.props.children);
7463
+ parts.leading.push(...inner.leading);
7464
+ parts.body.push(...inner.body);
7465
+ parts.meta.push(...inner.meta);
7466
+ parts.rich ||= inner.rich;
7467
+ parts.title ||= inner.title;
7468
+ parts.description ||= inner.description;
7469
+ plain += inner.title;
7470
+ } else if (child.type === SelectItemIcon || child.type === Avatar.Root) {
7471
+ parts.leading.push(child);
7472
+ } else if (child.type === Thumbnail.Root) {
7473
+ parts.leading.push(child);
7474
+ parts.rich = true;
7475
+ } else if (child.type === SelectItemMeta || child.type === Badge.Root) {
7476
+ parts.meta.push(child);
7477
+ } else {
7478
+ if (child.type === SelectItemText) parts.title = nodeText(child.props.children);
7479
+ if (child.type === SelectItemDescription) {
7480
+ parts.description = nodeText(child.props.children);
7481
+ parts.rich = true;
7482
+ }
7483
+ parts.body.push(child);
7484
+ }
7485
+ }
7486
+ parts.title = (parts.title || plain).trim();
7487
+ return parts;
7486
7488
  }
7487
- function sameColor(a, b) {
7488
- return (a ?? "").trim().toLowerCase() === (b ?? "").trim().toLowerCase();
7489
+ function sizeMedia(leading, size) {
7490
+ return leading.map(
7491
+ (node) => React61.isValidElement(node) && (node.type === Thumbnail.Root || node.type === Avatar.Root) ? React61.cloneElement(node, {
7492
+ size: node.props.size ?? tierMappings.rowMedia[size],
7493
+ className: cx(Select_default.media, node.props.className),
7494
+ "aria-hidden": true
7495
+ }) : node
7496
+ );
7489
7497
  }
7490
- function colorToRgb(value) {
7491
- const input = value.trim().toLowerCase();
7492
- const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(input)?.[1];
7493
- if (hex) {
7494
- const full = hex.length <= 4 ? [...hex].map((c) => c + c).join("") : hex;
7495
- return [0, 2, 4].map((i) => Number.parseInt(full.slice(i, i + 2), 16));
7496
- }
7497
- const fn = /^(rgba?|hsla?)\(([^)]+)\)$/.exec(input);
7498
- if (!fn) return null;
7499
- const parts = fn[2].split(/[\s,/]+/).filter(Boolean);
7500
- if (parts.length < 3) return null;
7501
- const num = (part, scale) => part.endsWith("%") ? Number.parseFloat(part) / 100 * scale : Number.parseFloat(part);
7502
- if (fn[1].startsWith("rgb")) {
7503
- const rgb = parts.slice(0, 3).map((part) => num(part, 255));
7504
- return rgb.every(Number.isFinite) ? rgb : null;
7505
- }
7506
- const h = Number.parseFloat(parts[0]);
7507
- const s = num(parts[1], 1);
7508
- const l = num(parts[2], 1);
7509
- if (![h, s, l].every(Number.isFinite)) return null;
7510
- const a = s * Math.min(l, 1 - l);
7511
- const channel = (n) => {
7512
- const k = (n + h / 30) % 12;
7513
- return 255 * (l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)));
7514
- };
7515
- return [channel(0), channel(8), channel(4)];
7516
- }
7517
- function markContrast(value) {
7518
- const rgb = colorToRgb(value);
7519
- if (!rgb) return "dark";
7520
- const lin = (c) => {
7521
- const s = c / 255;
7522
- return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
7523
- };
7524
- const l = 0.2126 * lin(rgb[0]) + 0.7152 * lin(rgb[1]) + 0.0722 * lin(rgb[2]);
7525
- return l > 0.179 ? "dark" : "light";
7526
- }
7527
- function balancedColumns(count, width, cell, gap) {
7528
- if (count < 1 || width <= 0 || cell <= 0) return Math.max(1, count);
7529
- const fit = Math.max(1, Math.floor((width + gap) / (cell + gap)));
7530
- const rows = Math.ceil(count / Math.min(count, fit));
7531
- return Math.ceil(count / rows);
7532
- }
7533
- function useBalancedColumns(gridRef, count, cellSelector) {
7534
- const [columns, setColumns] = React59.useState();
7535
- const measure = React59.useCallback(() => {
7536
- const grid = gridRef.current;
7537
- if (!grid) return;
7538
- const cell = grid.querySelector(cellSelector)?.offsetHeight ?? 0;
7539
- const gap = Number.parseFloat(getComputedStyle(grid).columnGap) || 0;
7540
- setColumns(cell > 0 ? balancedColumns(count, grid.clientWidth, cell, gap) : void 0);
7541
- }, [gridRef, count, cellSelector]);
7542
- React59.useLayoutEffect(measure, [measure]);
7543
- useResizeEffect(gridRef, measure);
7544
- return columns;
7545
- }
7546
- function firstRowLength(items) {
7547
- const top = items[0]?.offsetTop;
7548
- const count = items.findIndex((item) => !item || item.offsetTop !== top);
7549
- return Math.max(1, count === -1 ? items.length : count);
7498
+ function SelectItem({
7499
+ value,
7500
+ label,
7501
+ keywords,
7502
+ disabled = false,
7503
+ className,
7504
+ children,
7505
+ onClick: onClick2,
7506
+ onMouseMove,
7507
+ ref,
7508
+ ...rest
7509
+ }) {
7510
+ const { multiple, size, selected, highlight, pick, registry, listboxId, query, filter } = useSelectContext();
7511
+ const parts = splitItemChildren(children);
7512
+ const resolvedLabel = label || parts.title || value;
7513
+ const haystack = normalize(`${resolvedLabel} ${parts.description} ${keywords ?? ""}`);
7514
+ const isSelected = selected.includes(value);
7515
+ const isHighlighted = useStoreSlice(highlight, (current) => current === value);
7516
+ const nodeRef = React61.useRef(null);
7517
+ const setRefs = useMergedRefs(nodeRef, ref);
7518
+ useListboxItem(
7519
+ registry,
7520
+ value,
7521
+ { label: resolvedLabel, haystack, disabled, onActivate: () => pick(value) },
7522
+ nodeRef
7523
+ );
7524
+ const search = normalize(query);
7525
+ if (filter && search !== "" && !haystack.includes(search)) return null;
7526
+ return (
7527
+ // biome-ignore lint/a11y/useFocusableInteractive: focus stays on the listbox / search (aria-activedescendant)
7528
+ // biome-ignore lint/a11y/useKeyWithClickEvents: the keyboard is handled on the listbox
7529
+ /* @__PURE__ */ jsxs24(
7530
+ "div",
7531
+ {
7532
+ ...rest,
7533
+ ref: setRefs,
7534
+ id: optionDomId(listboxId, value),
7535
+ role: "option",
7536
+ "aria-selected": isSelected,
7537
+ "aria-disabled": disabled || void 0,
7538
+ className: cx(menu_default.item, Select_default.item, className),
7539
+ onClick: (event) => {
7540
+ onClick2?.(event);
7541
+ if (!event.defaultPrevented) registry.activate(value);
7542
+ },
7543
+ onMouseMove: (event) => {
7544
+ onMouseMove?.(event);
7545
+ if (!disabled && !isHighlighted) highlight.set(value);
7546
+ },
7547
+ ...toDataAttributes({
7548
+ value,
7549
+ selected: isSelected,
7550
+ highlighted: isHighlighted,
7551
+ disabled,
7552
+ rich: parts.rich || void 0
7553
+ }),
7554
+ children: [
7555
+ multiple ? /* @__PURE__ */ jsx39(Checkbox.Indicator, { checked: isSelected, disabled, size: stepDown(size) }) : null,
7556
+ sizeMedia(parts.leading, size),
7557
+ /* @__PURE__ */ jsx39("span", { className: Select_default.itemText, children: /* @__PURE__ */ jsx39(OptionQueryContext.Provider, { value: query, children: highlightChildren(parts.body, query) }) }),
7558
+ parts.meta,
7559
+ multiple ? null : /* @__PURE__ */ jsx39("span", { className: menu_default.check, "aria-hidden": "true", children: isSelected ? /* @__PURE__ */ jsx39(Icon, { name: "action.check" }) : null })
7560
+ ]
7561
+ }
7562
+ )
7563
+ );
7550
7564
  }
7551
- function useSwatchGrid(count) {
7552
- const items = React59.useRef([]);
7553
- const itemRef = React59.useCallback(
7554
- (index) => (node) => {
7555
- items.current[index] = node;
7565
+ SelectItem.displayName = "Select.Item";
7566
+ var ACTION_PREFIX = "__prime_select_action";
7567
+ var isActionValue = (value) => value.startsWith(ACTION_PREFIX);
7568
+ function SelectAction({
7569
+ onSelect,
7570
+ disabled = false,
7571
+ className,
7572
+ children,
7573
+ onClick: onClick2,
7574
+ onMouseMove,
7575
+ ref,
7576
+ ...rest
7577
+ }) {
7578
+ const { highlight, listboxId, setOpen, size, registry } = useSelectContext();
7579
+ const value = `${ACTION_PREFIX}${React61.useId()}`;
7580
+ const isHighlighted = useStoreSlice(highlight, (current) => current === value);
7581
+ const parts = splitItemChildren(children);
7582
+ const nodeRef = React61.useRef(null);
7583
+ const setRefs = useMergedRefs(nodeRef, ref);
7584
+ useListboxItem(
7585
+ registry,
7586
+ value,
7587
+ {
7588
+ label: parts.title,
7589
+ haystack: "",
7590
+ disabled,
7591
+ persistent: true,
7592
+ onActivate: () => {
7593
+ onSelect();
7594
+ setOpen(false);
7595
+ }
7556
7596
  },
7557
- []
7597
+ nodeRef
7558
7598
  );
7559
- const move = React59.useCallback(
7560
- (event, from, columns) => {
7561
- const focused = document.activeElement;
7562
- const current = focused instanceof HTMLElement ? items.current.indexOf(focused) : -1;
7563
- const next = gridIndex(
7564
- event.key,
7565
- current === -1 ? from : current,
7566
- count,
7567
- columns ?? firstRowLength(items.current)
7568
- );
7569
- if (next === null) return null;
7570
- event.preventDefault();
7571
- items.current[next]?.focus();
7572
- return next;
7573
- },
7574
- [count]
7599
+ return (
7600
+ // biome-ignore lint/a11y/useFocusableInteractive: focus stays on the listbox / search (aria-activedescendant)
7601
+ // biome-ignore lint/a11y/useKeyWithClickEvents: the keyboard is handled on the listbox
7602
+ /* @__PURE__ */ jsxs24(
7603
+ "div",
7604
+ {
7605
+ ...rest,
7606
+ ref: setRefs,
7607
+ id: optionDomId(listboxId, value),
7608
+ role: "option",
7609
+ "aria-disabled": disabled || void 0,
7610
+ className: cx(menu_default.item, className),
7611
+ onClick: (event) => {
7612
+ onClick2?.(event);
7613
+ if (!event.defaultPrevented) registry.activate(value);
7614
+ },
7615
+ onMouseMove: (event) => {
7616
+ onMouseMove?.(event);
7617
+ if (!disabled && !isHighlighted) highlight.set(value);
7618
+ },
7619
+ ...toDataAttributes({
7620
+ value,
7621
+ action: true,
7622
+ highlighted: isHighlighted,
7623
+ disabled
7624
+ }),
7625
+ children: [
7626
+ sizeMedia(parts.leading, size),
7627
+ /* @__PURE__ */ jsx39("span", { className: Select_default.itemText, children: parts.body })
7628
+ ]
7629
+ }
7630
+ )
7575
7631
  );
7576
- const focus = React59.useCallback((index) => {
7577
- items.current[index]?.focus({ preventScroll: true });
7578
- }, []);
7579
- return { itemRef, move, focus };
7580
7632
  }
7633
+ SelectAction.displayName = "Select.Action";
7581
7634
 
7582
- // src/components/color-swatches/ColorSwatches.tsx
7583
- import * as React60 from "react";
7584
-
7585
- // src/components/color-swatches/ColorSwatches.module.css
7586
- var ColorSwatches_default = {
7587
- grid: "ColorSwatches_grid"
7588
- };
7589
-
7590
- // src/components/color-swatches/ColorSwatches.tsx
7591
- import { jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
7592
- var COLOR_SWATCHES_LABELS = {
7593
- group: "\u0426\u0432\u0435\u0442",
7594
- empty: "\u0411\u0435\u0437 \u0446\u0432\u0435\u0442\u0430",
7635
+ // src/components/select/Select.tsx
7636
+ import { Fragment as Fragment16, jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
7637
+ var SELECT_LABELS = {
7638
+ search: "\u041F\u043E\u0438\u0441\u043A",
7639
+ empty: "\u041D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E",
7640
+ emptyHint: "\u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0437\u0430\u043F\u0440\u043E\u0441",
7641
+ loading: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026",
7642
+ retry: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C",
7643
+ clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
7595
7644
  optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
7596
- colorNames: PALETTE_COLOR_NAMES
7645
+ changeFailed: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0432\u044B\u0431\u043E\u0440"
7597
7646
  };
7598
- function ColorSwatches(props) {
7647
+ function SelectRoot(props) {
7599
7648
  const {
7600
- mode,
7601
- value,
7602
- defaultValue,
7603
- onValueChange,
7604
- presets = COLOR_PRESETS,
7605
- palette = PALETTE_ORDER,
7606
- ...rest
7607
- } = props;
7608
- return /* @__PURE__ */ jsx39(
7609
- SwatchGrid,
7610
- {
7611
- ...rest,
7612
- hues: mode === "palette",
7613
- presets,
7614
- palette,
7615
- value,
7616
- defaultValue: defaultValue ?? null,
7617
- onValueChange
7618
- }
7619
- );
7620
- }
7621
- function SwatchGrid({
7622
- hues,
7623
- presets,
7624
- palette,
7625
- value: valueProp,
7626
- defaultValue,
7627
- onValueChange,
7628
- size: sizeProp,
7629
- disabled: disabledProp = false,
7630
- invalid,
7631
- allowEmpty = false,
7632
- name,
7633
- id,
7634
- className,
7635
- label,
7636
- required,
7637
- optional,
7638
- hint,
7639
- hintTone,
7640
- error,
7641
- "aria-label": ariaLabel,
7642
- "aria-labelledby": ariaLabelledBy,
7643
- "aria-describedby": ariaDescribedBy,
7644
- labels: labelsProp,
7645
- ...rest
7646
- }) {
7647
- const size = useControlSize(sizeProp);
7649
+ size: sizeProp,
7650
+ label,
7651
+ required = false,
7652
+ optional,
7653
+ hint,
7654
+ hintTone,
7655
+ error,
7656
+ invalid,
7657
+ focusRing,
7658
+ disabled: disabledProp = false,
7659
+ placeholder,
7660
+ id,
7661
+ open,
7662
+ defaultOpen = false,
7663
+ onOpenChange,
7664
+ closeOnEscape = true,
7665
+ closeOnOutsideClick = true,
7666
+ clearable = false,
7667
+ name,
7668
+ search,
7669
+ defaultSearch = "",
7670
+ onSearchChange,
7671
+ filter = true,
7672
+ loading = false,
7673
+ loadingMore = false,
7674
+ hasMore = false,
7675
+ onLoadMore,
7676
+ loadError,
7677
+ onRetry,
7678
+ labels: labelsProp,
7679
+ className,
7680
+ children,
7681
+ multiple: _multiple,
7682
+ value: _value,
7683
+ defaultValue: _defaultValue,
7684
+ onValueChange: _onValueChange,
7685
+ "aria-label": ariaLabel,
7686
+ ...rest
7687
+ } = props;
7688
+ const multiple = props.multiple === true;
7689
+ const tier = useHostTier(sizeProp);
7690
+ const { size } = tier;
7648
7691
  const disabled = useInheritedDisabled(disabledProp);
7649
- const frameSize = useControlSize(void 0);
7650
- const merged = useLabels(COLOR_SWATCHES_LABELS, labelsProp);
7651
- const labels = React60.useMemo(
7652
- () => ({
7653
- ...merged,
7654
- colorNames: { ...COLOR_SWATCHES_LABELS.colorNames, ...labelsProp?.colorNames }
7655
- }),
7656
- [merged, labelsProp?.colorNames]
7657
- );
7658
- const [value, setValue] = useControllableState({
7659
- value: valueProp,
7660
- defaultValue,
7661
- onChange: onValueChange
7692
+ const labels = useLabels(SELECT_LABELS, labelsProp);
7693
+ const ids = useFieldFrame(id, { label, hint, error, invalid, required });
7694
+ const [stored, setStored] = useControllableState({
7695
+ value: props.value,
7696
+ defaultValue: props.defaultValue ?? (multiple ? [] : void 0)
7662
7697
  });
7663
- const ids = useFieldFrame(id, { label, hint, error, invalid }, ariaDescribedBy);
7664
- const colorOptions = useSwatchOptions(presets, allowEmpty, labels.empty);
7665
- const hueOptions = usePaletteOptions(palette, allowEmpty, labels.empty, labels.colorNames);
7666
- const options = hues ? hueOptions : colorOptions;
7667
- const selectedIndex = options.findIndex((option) => sameColor(option.value, value));
7668
- const focusIndex = Math.max(0, selectedIndex);
7669
- const grid = useSwatchGrid(options.length);
7670
- const gridRef = React60.useRef(null);
7671
- const columns = useBalancedColumns(gridRef, options.length, "[role='radio']");
7672
- const labelledBy = ariaLabelledBy ?? ids.labelledBy;
7673
- const onKeyDown2 = (event) => {
7674
- const next = grid.move(event, focusIndex);
7675
- if (next !== null) setValue(options[next]?.value ?? null);
7676
- };
7677
- return /* @__PURE__ */ jsx39(
7678
- FieldFrame,
7679
- {
7680
- ...rest,
7681
- size: frameSize,
7682
- ids,
7683
- label,
7684
- required,
7685
- optional,
7686
- hint,
7687
- hintTone,
7688
- error,
7689
- disabled,
7690
- optionalLabel: labels.optional,
7691
- group: true,
7692
- className,
7693
- children: /* @__PURE__ */ jsxs24(
7694
- "div",
7695
- {
7696
- ref: gridRef,
7697
- id: ids.controlId,
7698
- role: "radiogroup",
7699
- "aria-label": labelledBy ? void 0 : ariaLabel ?? labels.group,
7700
- "aria-labelledby": labelledBy,
7701
- "aria-describedby": ids.describedBy,
7702
- "aria-required": required || void 0,
7703
- "aria-invalid": ids.invalid || void 0,
7704
- className: cx(swatchTierClass, swatchGridClass, ColorSwatches_default.grid),
7705
- "data-base": "control",
7706
- "data-stretch": "true",
7707
- style: {
7708
- "--swatch-count": options.length,
7709
- "--swatch-columns": columns
7710
- },
7711
- ...toDataAttributes({
7712
- size,
7713
- invalid: ids.invalid || void 0,
7714
- disabled: disabled || void 0
7715
- }),
7716
- onKeyDown: disabled ? void 0 : onKeyDown2,
7717
- children: [
7718
- options.map((option, index) => {
7719
- const selected = index === selectedIndex;
7720
- return (
7721
- // biome-ignore lint/a11y/useSemanticElements: a swatch is a styled button in a roving radiogroup; a native radio cannot carry the color fill and check mark
7722
- /* @__PURE__ */ jsx39(
7723
- "button",
7724
- {
7725
- ref: grid.itemRef(index),
7726
- type: "button",
7727
- role: "radio",
7728
- "aria-checked": selected,
7729
- "aria-label": option.label,
7730
- title: option.label,
7731
- tabIndex: index === focusIndex ? 0 : -1,
7732
- disabled,
7733
- className: cx(swatchClass, hues && option.value && palette_default.hue),
7734
- ...toDataAttributes({
7735
- state: selected ? "checked" : "unchecked",
7736
- contrast: option.contrast,
7737
- color: hues ? option.value ?? void 0 : void 0
7738
- }),
7739
- onClick: () => setValue(option.value),
7740
- children: /* @__PURE__ */ jsx39(SwatchContent, { value: option.value, selected, hue: hues })
7741
- },
7742
- option.value ?? "empty"
7743
- )
7744
- );
7745
- }),
7746
- name ? /* @__PURE__ */ jsx39("input", { type: "hidden", name, value: value ?? "" }) : null
7747
- ]
7748
- }
7749
- )
7698
+ const changes = usePendingChanges(stored, takeNext);
7699
+ const value = changes.shown;
7700
+ const saving = changes.pending.length > 0;
7701
+ const [announcement, setAnnouncement] = React62.useState("");
7702
+ const onValueChange = props.onValueChange;
7703
+ const commit = (next) => {
7704
+ if (saving || Object.is(next, value)) return;
7705
+ const outcome = onValueChange?.(next);
7706
+ if (!isPromiseLike(outcome)) {
7707
+ setStored(next);
7708
+ return;
7750
7709
  }
7710
+ setAnnouncement("");
7711
+ changes.track(next, outcome, {
7712
+ onResolve: () => setStored(next),
7713
+ onReject: () => setAnnouncement(labels.changeFailed)
7714
+ });
7715
+ };
7716
+ const commitRef = React62.useRef(commit);
7717
+ commitRef.current = commit;
7718
+ const selected = React62.useMemo(
7719
+ () => Array.isArray(value) ? value : value ? [value] : [],
7720
+ [value]
7751
7721
  );
7752
- }
7753
-
7754
- // src/components/select/Select.tsx
7755
- import * as React65 from "react";
7756
-
7757
- // src/hooks/useLoadMore.ts
7758
- import * as React61 from "react";
7759
- var LIST_ROOT_MARGIN = "0px 0px 48px 0px";
7760
- var NONE2 = /* @__PURE__ */ Symbol("none");
7761
- function useLoadMore({
7762
- enabled,
7763
- onLoadMore,
7764
- scrollRef,
7765
- round,
7766
- rootMargin = LIST_ROOT_MARGIN
7767
- }) {
7768
- const sentinelRef = React61.useRef(null);
7769
- const handlerRef = React61.useRef(onLoadMore);
7770
- handlerRef.current = onLoadMore;
7771
- const askedIn = React61.useRef(NONE2);
7772
- React61.useLayoutEffect(() => {
7773
- if (!enabled) askedIn.current = NONE2;
7774
- }, [enabled]);
7775
- const request = React61.useCallback(() => {
7776
- if (!enabled || Object.is(askedIn.current, round)) return;
7777
- askedIn.current = round;
7778
- void handlerRef.current?.();
7779
- }, [enabled, round]);
7780
- React61.useEffect(() => {
7781
- const root = scrollRef.current;
7782
- const target = sentinelRef.current;
7783
- if (!enabled || !root || !target || typeof IntersectionObserver === "undefined") return;
7784
- const observer = new IntersectionObserver(
7785
- ([entry]) => {
7786
- if (entry?.isIntersecting) request();
7787
- },
7788
- { root, rootMargin, threshold: 0 }
7789
- );
7790
- observer.observe(target);
7791
- return () => observer.disconnect();
7792
- }, [enabled, request, rootMargin, scrollRef]);
7793
- return { sentinelRef, request };
7794
- }
7795
-
7796
- // src/internal/MenuGroup.tsx
7797
- import * as React62 from "react";
7798
- import { jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
7799
- function MenuGroup({ label, className, children, ...rest }) {
7800
- const labelId = React62.useId();
7801
- return (
7802
- // biome-ignore lint/a11y/useSemanticElements: role="group" inside a menu / listbox; <fieldset> is not allowed there
7803
- /* @__PURE__ */ jsxs25(
7804
- "div",
7805
- {
7806
- ...rest,
7807
- role: "group",
7808
- "aria-labelledby": label != null ? labelId : void 0,
7809
- className: cx(menu_default.group, className),
7810
- children: [
7811
- label != null ? /* @__PURE__ */ jsx40("div", { id: labelId, role: "presentation", className: cx(textRole_default.caption, menu_default.groupLabel), children: label }) : null,
7812
- children
7813
- ]
7722
+ const [isOpen, setOpen] = useOpenState({ open, defaultOpen, onOpenChange, disabled });
7723
+ const highlight = useCreateStore(void 0);
7724
+ const registry = useListboxRegistry();
7725
+ const [query, setQuery] = useControllableState({
7726
+ value: search,
7727
+ defaultValue: defaultSearch,
7728
+ onChange: onSearchChange
7729
+ });
7730
+ const triggerRef = React62.useRef(null);
7731
+ const inSegment = React62.useContext(InputSegmentContext);
7732
+ const segment = React62.useMemo(
7733
+ () => inSegment ? { label: ariaLabel } : null,
7734
+ [inSegment, ariaLabel]
7735
+ );
7736
+ const wasOpenRef = React62.useRef(isOpen);
7737
+ React62.useEffect(() => {
7738
+ if (wasOpenRef.current && !isOpen) setQuery("");
7739
+ wasOpenRef.current = isOpen;
7740
+ }, [isOpen, setQuery]);
7741
+ const pick = React62.useCallback(
7742
+ (optionValue) => {
7743
+ if (multiple) {
7744
+ const list = Array.isArray(value) ? value : [];
7745
+ commitRef.current(
7746
+ list.includes(optionValue) ? list.filter((item) => item !== optionValue) : [...list, optionValue]
7747
+ );
7748
+ return;
7814
7749
  }
7815
- )
7750
+ commitRef.current(optionValue);
7751
+ setOpen(false);
7752
+ },
7753
+ [multiple, value, setOpen]
7816
7754
  );
7817
- }
7818
-
7819
- // src/components/select/Select.module.css
7820
- var Select_default = {
7821
- trigger: "Select_trigger",
7822
- triggerMain: "Select_triggerMain",
7823
- value: "Select_value",
7824
- valueBody: "Select_valueBody",
7825
- triggerIcon: "Select_triggerIcon",
7826
- chevron: "Select_chevron",
7827
- clear: "Select_clear",
7828
- content: "Select_content",
7829
- listbox: "Select_listbox",
7830
- search: "Select_search",
7831
- group: "Select_group",
7832
- separator: "Select_separator",
7833
- actions: "Select_actions",
7834
- item: "Select_item",
7835
- itemText: "Select_itemText",
7836
- itemTitle: "Select_itemTitle",
7837
- itemDescription: "Select_itemDescription",
7838
- itemMeta: "Select_itemMeta",
7839
- media: "Select_media",
7840
- segment: "Select_segment",
7841
- segmentTrigger: "Select_segmentTrigger"
7842
- };
7843
-
7844
- // src/components/select/SelectItem.tsx
7845
- import * as React64 from "react";
7846
-
7847
- // src/internal/nodeText.ts
7848
- import * as React63 from "react";
7849
- function nodeText(node) {
7850
- if (typeof node === "string" || typeof node === "number") return String(node);
7851
- if (Array.isArray(node)) return node.map(nodeText).join("");
7852
- if (React63.isValidElement(node)) {
7853
- return nodeText(node.props.children);
7755
+ const clear = React62.useCallback(() => commitRef.current(multiple ? [] : ""), [multiple]);
7756
+ const context = React62.useMemo(
7757
+ () => ({
7758
+ size,
7759
+ invalid: ids.invalid,
7760
+ focusRing,
7761
+ required: ids.required,
7762
+ disabled,
7763
+ placeholder,
7764
+ multiple,
7765
+ selected,
7766
+ registry,
7767
+ pick,
7768
+ clear,
7769
+ clearable,
7770
+ loading,
7771
+ saving,
7772
+ loadingMore,
7773
+ hasMore,
7774
+ onLoadMore,
7775
+ loadError,
7776
+ onRetry,
7777
+ filter,
7778
+ isOpen,
7779
+ setOpen,
7780
+ closeOnEscape,
7781
+ closeOnOutsideClick,
7782
+ highlight,
7783
+ query,
7784
+ setQuery,
7785
+ triggerId: ids.controlId,
7786
+ listboxId: `${ids.controlId}-listbox`,
7787
+ describedBy: ids.describedBy,
7788
+ triggerRef,
7789
+ labels,
7790
+ segment
7791
+ }),
7792
+ [
7793
+ size,
7794
+ ids.invalid,
7795
+ ids.controlId,
7796
+ ids.describedBy,
7797
+ focusRing,
7798
+ ids.required,
7799
+ disabled,
7800
+ placeholder,
7801
+ multiple,
7802
+ selected,
7803
+ registry,
7804
+ pick,
7805
+ clear,
7806
+ clearable,
7807
+ loading,
7808
+ saving,
7809
+ loadingMore,
7810
+ hasMore,
7811
+ onLoadMore,
7812
+ loadError,
7813
+ onRetry,
7814
+ filter,
7815
+ isOpen,
7816
+ setOpen,
7817
+ closeOnEscape,
7818
+ closeOnOutsideClick,
7819
+ highlight,
7820
+ query,
7821
+ setQuery,
7822
+ labels,
7823
+ segment
7824
+ ]
7825
+ );
7826
+ const body = /* @__PURE__ */ jsxs25(Fragment16, { children: [
7827
+ /* @__PURE__ */ jsx40(SelectProvider, { value: context, children }),
7828
+ name ? (selected.length > 0 || multiple ? selected : [""]).map((item) => /* @__PURE__ */ jsx40("input", { type: "hidden", name, value: item, disabled }, item)) : null,
7829
+ /* @__PURE__ */ jsx40(VisuallyHidden, { live: "polite", children: announcement })
7830
+ ] });
7831
+ if (segment) {
7832
+ return tier.provide(
7833
+ /* @__PURE__ */ jsx40(
7834
+ "div",
7835
+ {
7836
+ ...rest,
7837
+ className: cx(Select_default.segment, className),
7838
+ "data-field-segment": "",
7839
+ "data-size": size,
7840
+ children: body
7841
+ }
7842
+ )
7843
+ );
7854
7844
  }
7855
- return "";
7856
- }
7857
-
7858
- // src/components/select/selectContext.ts
7859
- var normalize = (text) => text.trim().toLocaleLowerCase();
7860
- var [SelectProvider, useSelectContext] = createComponentContext("Select");
7861
-
7862
- // src/components/select/SelectItem.tsx
7863
- import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
7864
- function SelectItemIcon({ className, ...rest }) {
7865
- return /* @__PURE__ */ jsx41("span", { "aria-hidden": "true", className: cx(menu_default.itemIcon, iconSlotClass, className), ...rest });
7866
- }
7867
- SelectItemIcon.displayName = "Select.ItemIcon";
7868
- var OptionQueryContext = React64.createContext("");
7869
- function SelectItemText({ children, className, ...rest }) {
7870
- const query = React64.useContext(OptionQueryContext);
7871
- return /* @__PURE__ */ jsx41("span", { ...rest, className: cx(Select_default.itemTitle, className), children: highlightChildren(children, query) });
7872
- }
7873
- SelectItemText.displayName = "Select.ItemText";
7874
- function SelectItemDescription({
7875
- children,
7876
- className,
7877
- ...rest
7878
- }) {
7879
- const query = React64.useContext(OptionQueryContext);
7880
- return /* @__PURE__ */ jsx41("span", { ...rest, className: cx(Select_default.itemDescription, className), children: highlightChildren(children, query) });
7881
- }
7882
- SelectItemDescription.displayName = "Select.ItemDescription";
7883
- function SelectItemMeta({ children, className, ...rest }) {
7884
- return /* @__PURE__ */ jsx41("span", { ...rest, className: cx(Select_default.itemMeta, className), children });
7885
- }
7886
- SelectItemMeta.displayName = "Select.ItemMeta";
7887
- function splitItemChildren(children) {
7888
- const parts = {
7889
- leading: [],
7890
- body: [],
7891
- meta: [],
7892
- rich: false,
7893
- title: "",
7894
- description: ""
7895
- };
7896
- let plain = "";
7897
- for (const child of React64.Children.toArray(children)) {
7898
- if (!React64.isValidElement(child)) {
7899
- plain += nodeText(child);
7900
- parts.body.push(child);
7901
- } else if (child.type === React64.Fragment) {
7902
- const inner = splitItemChildren(child.props.children);
7903
- parts.leading.push(...inner.leading);
7904
- parts.body.push(...inner.body);
7905
- parts.meta.push(...inner.meta);
7906
- parts.rich ||= inner.rich;
7907
- parts.title ||= inner.title;
7908
- parts.description ||= inner.description;
7909
- plain += inner.title;
7910
- } else if (child.type === SelectItemIcon || child.type === Avatar.Root) {
7911
- parts.leading.push(child);
7912
- } else if (child.type === Thumbnail.Root) {
7913
- parts.leading.push(child);
7914
- parts.rich = true;
7915
- } else if (child.type === SelectItemMeta || child.type === Badge.Root) {
7916
- parts.meta.push(child);
7917
- } else {
7918
- if (child.type === SelectItemText) parts.title = nodeText(child.props.children);
7919
- if (child.type === SelectItemDescription) {
7920
- parts.description = nodeText(child.props.children);
7921
- parts.rich = true;
7845
+ return tier.provide(
7846
+ /* @__PURE__ */ jsx40(
7847
+ FieldFrame,
7848
+ {
7849
+ ...rest,
7850
+ "aria-label": ariaLabel,
7851
+ size,
7852
+ ids,
7853
+ label,
7854
+ required,
7855
+ optional,
7856
+ hint,
7857
+ hintTone,
7858
+ error,
7859
+ disabled,
7860
+ optionalLabel: labels.optional,
7861
+ className,
7862
+ children: body
7922
7863
  }
7923
- parts.body.push(child);
7924
- }
7925
- }
7926
- parts.title = (parts.title || plain).trim();
7927
- return parts;
7928
- }
7929
- function sizeMedia(leading, size) {
7930
- return leading.map(
7931
- (node) => React64.isValidElement(node) && (node.type === Thumbnail.Root || node.type === Avatar.Root) ? React64.cloneElement(node, {
7932
- size: node.props.size ?? tierMappings.rowMedia[size],
7933
- className: cx(Select_default.media, node.props.className),
7934
- "aria-hidden": true
7935
- }) : node
7864
+ )
7936
7865
  );
7937
7866
  }
7938
- function SelectItem({
7939
- value,
7940
- label,
7941
- keywords,
7942
- disabled = false,
7867
+ SelectRoot.displayName = "Select.Root";
7868
+ var takeNext = (_current, next) => next;
7869
+ function SelectTrigger({
7943
7870
  className,
7944
7871
  children,
7945
7872
  onClick: onClick2,
7946
- onMouseMove,
7873
+ onKeyDown: onKeyDown2,
7874
+ "aria-describedby": ariaDescribedBy,
7947
7875
  ref,
7948
7876
  ...rest
7949
7877
  }) {
7950
- const { multiple, size, selected, highlight, pick, registry, listboxId, query, filter } = useSelectContext();
7951
- const parts = splitItemChildren(children);
7952
- const resolvedLabel = label || parts.title || value;
7953
- const haystack = normalize(`${resolvedLabel} ${parts.description} ${keywords ?? ""}`);
7954
- const isSelected = selected.includes(value);
7955
- const isHighlighted = useStoreSlice(highlight, (current) => current === value);
7956
- const nodeRef = React64.useRef(null);
7957
- const setRefs = useMergedRefs(nodeRef, ref);
7958
- useListboxItem(
7878
+ const {
7879
+ isOpen,
7880
+ setOpen,
7881
+ triggerId,
7882
+ listboxId,
7883
+ disabled,
7884
+ size,
7885
+ invalid,
7886
+ focusRing,
7887
+ required,
7888
+ describedBy,
7889
+ triggerRef,
7890
+ loading,
7891
+ saving,
7892
+ clearable,
7893
+ selected,
7894
+ clear,
7895
+ labels,
7959
7896
  registry,
7960
- value,
7961
- { label: resolvedLabel, haystack, disabled, onActivate: () => pick(value) },
7962
- nodeRef
7963
- );
7964
- const search = normalize(query);
7965
- if (filter && search !== "" && !haystack.includes(search)) return null;
7966
- return (
7967
- // biome-ignore lint/a11y/useFocusableInteractive: focus stays on the listbox / search (aria-activedescendant)
7968
- // biome-ignore lint/a11y/useKeyWithClickEvents: the keyboard is handled on the listbox
7969
- /* @__PURE__ */ jsxs26(
7970
- "div",
7971
- {
7972
- ...rest,
7973
- ref: setRefs,
7974
- id: optionDomId(listboxId, value),
7975
- role: "option",
7976
- "aria-selected": isSelected,
7977
- "aria-disabled": disabled || void 0,
7978
- className: cx(menu_default.item, Select_default.item, className),
7979
- onClick: (event) => {
7980
- onClick2?.(event);
7981
- if (!event.defaultPrevented) registry.activate(value);
7982
- },
7983
- onMouseMove: (event) => {
7984
- onMouseMove?.(event);
7985
- if (!disabled && !isHighlighted) highlight.set(value);
7986
- },
7987
- ...toDataAttributes({
7988
- value,
7989
- selected: isSelected,
7990
- highlighted: isHighlighted,
7991
- disabled,
7992
- rich: parts.rich || void 0
7993
- }),
7994
- children: [
7995
- multiple ? /* @__PURE__ */ jsx41(Checkbox.Indicator, { checked: isSelected, disabled, size: stepDown(size) }) : null,
7996
- sizeMedia(parts.leading, size),
7997
- /* @__PURE__ */ jsx41("span", { className: Select_default.itemText, children: /* @__PURE__ */ jsx41(OptionQueryContext.Provider, { value: query, children: highlightChildren(parts.body, query) }) }),
7998
- parts.meta,
7999
- multiple ? null : /* @__PURE__ */ jsx41("span", { className: menu_default.check, "aria-hidden": "true", children: isSelected ? /* @__PURE__ */ jsx41(Icon, { name: "action.check" }) : null })
8000
- ]
8001
- }
8002
- )
8003
- );
8004
- }
8005
- SelectItem.displayName = "Select.Item";
8006
- var ACTION_PREFIX = "__prime_select_action";
8007
- var isActionValue = (value) => value.startsWith(ACTION_PREFIX);
8008
- function SelectAction({
8009
- onSelect,
8010
- disabled = false,
8011
- className,
8012
- children,
8013
- onClick: onClick2,
8014
- onMouseMove,
8015
- ref,
8016
- ...rest
8017
- }) {
8018
- const { highlight, listboxId, setOpen, size, registry } = useSelectContext();
8019
- const value = `${ACTION_PREFIX}${React64.useId()}`;
8020
- const isHighlighted = useStoreSlice(highlight, (current) => current === value);
8021
- const parts = splitItemChildren(children);
8022
- const nodeRef = React64.useRef(null);
8023
- const setRefs = useMergedRefs(nodeRef, ref);
8024
- useListboxItem(
8025
- registry,
8026
- value,
7897
+ segment
7898
+ } = useSelectContext();
7899
+ const mergedRef = useMergedRefs(triggerRef, ref);
7900
+ useListboxView(registry);
7901
+ const valueText = selected.map(registry.labelOf).join(", ");
7902
+ const segmentName = segment?.label ? valueText ? `${segment.label}: ${valueText}` : segment.label : void 0;
7903
+ const parts = React62.Children.toArray(children);
7904
+ const iconOnly = parts.some((node) => React62.isValidElement(node) && node.type === SelectTriggerIcon) && !parts.some((node) => React62.isValidElement(node) && node.type === SelectValue);
7905
+ const busy = loading || saving;
7906
+ const showClear = clearable && selected.length > 0 && !disabled && !busy;
7907
+ const clearPresence = usePartPresence({ present: showClear, axis: "inline" });
7908
+ const toggle = floatingTriggerProps({ open: isOpen, setOpen, openOnArrow: true });
7909
+ return /* @__PURE__ */ jsxs25(
7910
+ "button",
8027
7911
  {
8028
- label: parts.title,
8029
- haystack: "",
7912
+ ...rest,
7913
+ ref: mergedRef,
7914
+ id: triggerId,
7915
+ type: "button",
7916
+ role: "combobox",
7917
+ "aria-expanded": toggle["aria-expanded"],
7918
+ "aria-haspopup": "listbox",
7919
+ "aria-controls": isOpen ? listboxId : void 0,
7920
+ "aria-invalid": invalid || void 0,
7921
+ "aria-required": required || void 0,
7922
+ "aria-describedby": [ariaDescribedBy, describedBy].filter(Boolean).join(" ") || void 0,
7923
+ "aria-busy": busy || void 0,
7924
+ "aria-label": segmentName ?? rest["aria-label"],
8030
7925
  disabled,
8031
- persistent: true,
8032
- onActivate: () => {
8033
- onSelect();
8034
- setOpen(false);
8035
- }
8036
- },
8037
- nodeRef
7926
+ className: cx(
7927
+ segment ? Select_default.segmentTrigger : cx(fieldTriggerClass, Select_default.trigger),
7928
+ className
7929
+ ),
7930
+ onClick: (event) => {
7931
+ onClick2?.(event);
7932
+ if (!event.defaultPrevented) toggle.onClick();
7933
+ },
7934
+ onKeyDown: (event) => {
7935
+ onKeyDown2?.(event);
7936
+ if (event.defaultPrevented) return;
7937
+ toggle.onKeyDown?.(event);
7938
+ if (event.defaultPrevented) return;
7939
+ if (event.key === " " || event.key === "Enter") {
7940
+ event.preventDefault();
7941
+ if (!isOpen) setOpen(true);
7942
+ } else if (showClear && (event.key === "Delete" || event.key === "Backspace")) {
7943
+ event.preventDefault();
7944
+ clear();
7945
+ }
7946
+ },
7947
+ ...toDataAttributes({
7948
+ state: toggle["data-state"],
7949
+ size,
7950
+ invalid: invalid || void 0,
7951
+ loading: busy || void 0,
7952
+ disabled: disabled || void 0,
7953
+ "focus-ring": focusRing,
7954
+ "icon-only": iconOnly || void 0,
7955
+ segment: segment ? true : void 0
7956
+ }),
7957
+ children: [
7958
+ /* @__PURE__ */ jsxs25("span", { className: Select_default.triggerMain, children: [
7959
+ children,
7960
+ iconOnly ? /* @__PURE__ */ jsx40(SelectValue, { className: visuallyHiddenClass }) : null
7961
+ ] }),
7962
+ showClear ? (
7963
+ // A segment, not a button: interactive content inside a <button> is invalid. The keyboard
7964
+ // clears with Delete / Backspace on the trigger. A touch target in height, like the clear
7965
+ // segment of a field (`FieldAction`).
7966
+ /* @__PURE__ */ jsx40(
7967
+ "span",
7968
+ {
7969
+ ref: clearPresence.ref,
7970
+ className: cx(Select_default.clear, touchTargetBlockClass, clearPresence.className),
7971
+ "aria-hidden": "true",
7972
+ title: labels.clear,
7973
+ "data-select-clear": "",
7974
+ onMouseDown: (event) => event.preventDefault(),
7975
+ onClick: (event) => {
7976
+ event.stopPropagation();
7977
+ clear();
7978
+ },
7979
+ children: /* @__PURE__ */ jsx40(Icon, { name: "action.close" })
7980
+ }
7981
+ )
7982
+ ) : null,
7983
+ /* @__PURE__ */ jsx40("span", { className: Select_default.chevron, "aria-hidden": "true", children: /* @__PURE__ */ jsx40(GlyphSwap, { children: busy ? /* @__PURE__ */ jsx40(Spinner, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx40(Icon, { name: "nav.chevronDown" }) }) })
7984
+ ]
7985
+ }
8038
7986
  );
8039
- return (
8040
- // biome-ignore lint/a11y/useFocusableInteractive: focus stays on the listbox / search (aria-activedescendant)
8041
- // biome-ignore lint/a11y/useKeyWithClickEvents: the keyboard is handled on the listbox
8042
- /* @__PURE__ */ jsxs26(
8043
- "div",
7987
+ }
7988
+ SelectTrigger.displayName = "Select.Trigger";
7989
+ function SelectValue({ renderValue, className, ...rest }) {
7990
+ const { selected, registry, placeholder, multiple, size } = useSelectContext();
7991
+ useListboxView(registry);
7992
+ const text = selected.map(registry.labelOf).join(", ");
7993
+ if (selected.length > 0 && renderValue && !multiple) {
7994
+ const value = selected[0] ?? "";
7995
+ const parts = splitItemChildren(renderValue({ value, label: text }));
7996
+ return /* @__PURE__ */ jsxs25(
7997
+ "span",
8044
7998
  {
8045
7999
  ...rest,
8046
- ref: setRefs,
8047
- id: optionDomId(listboxId, value),
8048
- role: "option",
8049
- "aria-disabled": disabled || void 0,
8050
- className: cx(menu_default.item, className),
8051
- onClick: (event) => {
8052
- onClick2?.(event);
8053
- if (!event.defaultPrevented) registry.activate(value);
8054
- },
8055
- onMouseMove: (event) => {
8056
- onMouseMove?.(event);
8057
- if (!disabled && !isHighlighted) highlight.set(value);
8058
- },
8000
+ className: cx(Select_default.value, className),
8059
8001
  ...toDataAttributes({
8060
- value,
8061
- action: true,
8062
- highlighted: isHighlighted,
8063
- disabled
8002
+ rich: parts.rich || void 0,
8003
+ media: parts.leading.length > 0 || parts.meta.length > 0 || void 0
8064
8004
  }),
8065
8005
  children: [
8066
8006
  sizeMedia(parts.leading, size),
8067
- /* @__PURE__ */ jsx41("span", { className: Select_default.itemText, children: parts.body })
8007
+ /* @__PURE__ */ jsx40("span", { className: Select_default.valueBody, children: parts.body }),
8008
+ parts.meta
8068
8009
  ]
8069
8010
  }
8070
- )
8011
+ );
8012
+ }
8013
+ return /* @__PURE__ */ jsx40(
8014
+ "span",
8015
+ {
8016
+ ...rest,
8017
+ className: cx(Select_default.value, className),
8018
+ ...toDataAttributes({ placeholder: selected.length === 0 || void 0 }),
8019
+ children: selected.length > 0 ? text : placeholder
8020
+ }
8071
8021
  );
8072
8022
  }
8073
- SelectAction.displayName = "Select.Action";
8074
-
8075
- // src/components/select/Select.tsx
8076
- import { Fragment as Fragment17, jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
8077
- var SELECT_LABELS = {
8078
- search: "\u041F\u043E\u0438\u0441\u043A",
8079
- empty: "\u041D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E",
8080
- emptyHint: "\u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0437\u0430\u043F\u0440\u043E\u0441",
8081
- loading: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026",
8082
- retry: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C",
8083
- clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
8084
- optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
8085
- changeFailed: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0432\u044B\u0431\u043E\u0440"
8086
- };
8087
- function SelectRoot(props) {
8023
+ SelectValue.displayName = "Select.Value";
8024
+ function SelectTriggerIcon({ className, ...rest }) {
8025
+ return /* @__PURE__ */ jsx40("span", { "aria-hidden": "true", className: cx(Select_default.triggerIcon, className), ...rest });
8026
+ }
8027
+ SelectTriggerIcon.displayName = "Select.TriggerIcon";
8028
+ var LOADING_ROWS2 = 4;
8029
+ var LOADING_MORE_ROWS = 2;
8030
+ function SkeletonRows({ count }) {
8031
+ return Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsx40(
8032
+ "div",
8033
+ {
8034
+ "aria-hidden": "true",
8035
+ className: cx(menu_default.item, menu_default.skeletonRow),
8036
+ "data-skeleton": "",
8037
+ children: /* @__PURE__ */ jsx40(Skeleton, {})
8038
+ },
8039
+ index
8040
+ ));
8041
+ }
8042
+ function SelectContent({ searchable = false, className, children, ...rest }) {
8088
8043
  const {
8089
- size: sizeProp,
8090
- label,
8091
- required = false,
8092
- optional,
8093
- hint,
8094
- hintTone,
8095
- error,
8096
- invalid,
8097
- focusRing,
8098
- disabled: disabledProp = false,
8099
- placeholder,
8100
- id,
8101
- open,
8102
- defaultOpen = false,
8103
- onOpenChange,
8104
- closeOnEscape = true,
8105
- closeOnOutsideClick = true,
8106
- clearable = false,
8107
- name,
8108
- search,
8109
- defaultSearch = "",
8110
- onSearchChange,
8111
- filter = true,
8112
- loading = false,
8113
- loadingMore = false,
8114
- hasMore = false,
8044
+ isOpen,
8045
+ setOpen,
8046
+ closeOnEscape,
8047
+ closeOnOutsideClick,
8048
+ triggerId,
8049
+ listboxId,
8050
+ triggerRef,
8051
+ highlight,
8052
+ multiple,
8053
+ size,
8054
+ query,
8055
+ setQuery,
8056
+ loading,
8057
+ saving,
8058
+ loadingMore,
8059
+ hasMore,
8115
8060
  onLoadMore,
8116
8061
  loadError,
8117
8062
  onRetry,
8118
- labels: labelsProp,
8119
- className,
8120
- children,
8121
- multiple: _multiple,
8122
- value: _value,
8123
- defaultValue: _defaultValue,
8124
- onValueChange: _onValueChange,
8125
- "aria-label": ariaLabel,
8126
- ...rest
8127
- } = props;
8128
- const multiple = props.multiple === true;
8129
- const tier = useHostTier(sizeProp);
8130
- const { size } = tier;
8131
- const disabled = useInheritedDisabled(disabledProp);
8132
- const labels = useLabels(SELECT_LABELS, labelsProp);
8133
- const ids = useFieldFrame(id, { label, hint, error, invalid, required });
8134
- const [stored, setStored] = useControllableState({
8135
- value: props.value,
8136
- defaultValue: props.defaultValue ?? (multiple ? [] : void 0)
8063
+ filter,
8064
+ labels,
8065
+ registry
8066
+ } = useSelectContext();
8067
+ const listboxRef = React62.useRef(null);
8068
+ const setListboxRef = useMergedRefs(listboxRef);
8069
+ const items = [];
8070
+ const actions = [];
8071
+ for (const child of React62.Children.toArray(children)) {
8072
+ (React62.isValidElement(child) && child.type === SelectAction ? actions : items).push(child);
8073
+ }
8074
+ const actionsId = `${listboxId}-actions`;
8075
+ const floating = useFloatingLayer({
8076
+ open: isOpen,
8077
+ onOpenChange: setOpen,
8078
+ triggerRef,
8079
+ closeOnEscape,
8080
+ closeOnOutsideClick,
8081
+ matchAnchorWidth: true,
8082
+ focusOnOpen: true,
8083
+ tabExit: "always",
8084
+ sheet: true
8137
8085
  });
8138
- const changes = usePendingChanges(stored, takeNext);
8139
- const value = changes.shown;
8140
- const saving = changes.pending.length > 0;
8141
- const [announcement, setAnnouncement] = React65.useState("");
8142
- const onValueChange = props.onValueChange;
8143
- const commit = (next) => {
8144
- if (saving || Object.is(next, value)) return;
8145
- const outcome = onValueChange?.(next);
8146
- if (!isPromiseLike(outcome)) {
8147
- setStored(next);
8086
+ const highlighted = useStoreSlice(highlight, (value) => value);
8087
+ const view = useListboxView(registry, query, filter);
8088
+ const isEmpty = view.matchCount === 0;
8089
+ const typeahead = useTypeahead();
8090
+ const region = hasContent(loadError) ? "error" : loading && isEmpty ? "loading" : "ready";
8091
+ const { sentinelRef, request: requestMore } = useLoadMore({
8092
+ enabled: region === "ready" && hasMore && Boolean(onLoadMore) && !loading && !loadingMore,
8093
+ onLoadMore,
8094
+ scrollRef: listboxRef,
8095
+ round: view
8096
+ });
8097
+ const setSentinelRef = useMergedRefs(sentinelRef);
8098
+ const lastOption = view.navigable.filter((id) => !isActionValue(id)).at(-1);
8099
+ React62.useEffect(() => {
8100
+ if (highlighted !== void 0 && highlighted === lastOption) requestMore();
8101
+ }, [highlighted, lastOption, requestMore]);
8102
+ const handleKeyDown = (event) => {
8103
+ if (region === "error") {
8104
+ if (event.key === "Enter" && onRetry && !(event.target instanceof HTMLButtonElement)) {
8105
+ event.preventDefault();
8106
+ onRetry();
8107
+ }
8148
8108
  return;
8149
8109
  }
8150
- setAnnouncement("");
8151
- changes.track(next, outcome, {
8152
- onResolve: () => setStored(next),
8153
- onReject: () => setAnnouncement(labels.changeFailed)
8110
+ const inSearch = event.target instanceof HTMLInputElement;
8111
+ if (inSearch && [" ", "Home", "End"].includes(event.key)) return;
8112
+ const ids = view.navigable;
8113
+ const printable = event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
8114
+ if (printable && !inSearch && (event.key !== " " || typeahead.isTyping())) {
8115
+ event.preventDefault();
8116
+ const match = typeahead.find(event.key, ids, highlight.get(), registry.labelOf);
8117
+ if (match !== void 0) {
8118
+ highlight.set(match);
8119
+ revealHighlighted(registry.nodeOf(match));
8120
+ }
8121
+ return;
8122
+ }
8123
+ const moved = handleListboxKeyDown(event, {
8124
+ ids,
8125
+ highlight,
8126
+ activate: (value) => registry.activate(value)
8154
8127
  });
8128
+ if (moved !== null) revealHighlighted(registry.nodeOf(moved));
8155
8129
  };
8156
- const commitRef = React65.useRef(commit);
8157
- commitRef.current = commit;
8158
- const selected = React65.useMemo(
8159
- () => Array.isArray(value) ? value : value ? [value] : [],
8160
- [value]
8130
+ if (!floating.mounted) return /* @__PURE__ */ jsx40("div", { hidden: true, children: items });
8131
+ const activeDescendant = isOpen && highlighted !== void 0 ? optionDomId(listboxId, highlighted) : void 0;
8132
+ return /* @__PURE__ */ jsxs25(
8133
+ FloatingPanel,
8134
+ {
8135
+ ...rest,
8136
+ floating,
8137
+ size,
8138
+ className: cx(fieldTierClass, menu_default.tier, menu_default.menu, Select_default.content, className),
8139
+ onKeyDown: handleKeyDown,
8140
+ ...toDataAttributes({ searching: query !== "" || void 0 }),
8141
+ children: [
8142
+ searchable ? (
8143
+ // The permanent focus of the panel: no ring, the caret is the indicator (foundation §7).
8144
+ /* @__PURE__ */ jsxs25("div", { className: cx(menu_default.searchRow, Select_default.search), children: [
8145
+ /* @__PURE__ */ jsx40(Icon, { name: "action.search", size: "s" }),
8146
+ /* @__PURE__ */ jsx40(
8147
+ "input",
8148
+ {
8149
+ type: "text",
8150
+ className: menu_default.searchInput,
8151
+ value: query,
8152
+ placeholder: labels.search,
8153
+ "aria-label": labels.search,
8154
+ "aria-controls": region === "error" ? void 0 : listboxId,
8155
+ "aria-activedescendant": activeDescendant,
8156
+ "aria-autocomplete": "list",
8157
+ autoComplete: "off",
8158
+ spellCheck: false,
8159
+ "data-autofocus": "",
8160
+ onChange: (event) => setQuery(event.target.value)
8161
+ }
8162
+ )
8163
+ ] })
8164
+ ) : null,
8165
+ /* @__PURE__ */ jsx40(RegionSwap, { state: region, fill: true, children: region === "error" ? /* @__PURE__ */ jsxs25(EmptyPage.Root, { layout: "compact", size, role: "alert", children: [
8166
+ /* @__PURE__ */ jsx40(EmptyPage.Title, { as: "p", children: loadError }),
8167
+ onRetry ? /* @__PURE__ */ jsx40(EmptyPage.Actions, { children: /* @__PURE__ */ jsxs25(Button.Root, { variant: "soft", tone: "neutral", onClick: onRetry, children: [
8168
+ /* @__PURE__ */ jsx40(Button.Icon, { children: /* @__PURE__ */ jsx40(Icon, { name: "action.refresh" }) }),
8169
+ labels.retry
8170
+ ] }) }) : null
8171
+ ] }) : /* @__PURE__ */ jsxs25(Fragment16, { children: [
8172
+ /* @__PURE__ */ jsxs25(
8173
+ ScrollContainer,
8174
+ {
8175
+ ref: setListboxRef,
8176
+ id: listboxId,
8177
+ role: "listbox",
8178
+ "aria-multiselectable": multiple || void 0,
8179
+ "aria-labelledby": triggerId,
8180
+ "aria-activedescendant": searchable ? void 0 : activeDescendant,
8181
+ "aria-busy": loading || loadingMore || saving || void 0,
8182
+ "aria-owns": actions.length > 0 ? actionsId : void 0,
8183
+ tabIndex: -1,
8184
+ "data-autofocus": searchable ? void 0 : "",
8185
+ className: Select_default.listbox,
8186
+ children: [
8187
+ items,
8188
+ region === "loading" ? /* @__PURE__ */ jsx40(SkeletonRows, { count: LOADING_ROWS2 }) : null,
8189
+ region === "ready" && hasMore ? /* @__PURE__ */ jsx40("div", { ref: setSentinelRef, "aria-hidden": "true", className: menu_default.loadSentinel }) : null,
8190
+ region === "ready" && loadingMore ? /* @__PURE__ */ jsx40(SkeletonRows, { count: LOADING_MORE_ROWS }) : null
8191
+ ]
8192
+ }
8193
+ ),
8194
+ region === "ready" && isEmpty ? /* @__PURE__ */ jsxs25(EmptyPage.Root, { layout: "compact", size, role: "status", children: [
8195
+ /* @__PURE__ */ jsx40(EmptyPage.Title, { as: "p", children: labels.empty }),
8196
+ query !== "" && labels.emptyHint ? /* @__PURE__ */ jsx40(EmptyPage.Description, { children: labels.emptyHint }) : null
8197
+ ] }) : null,
8198
+ actions.length > 0 ? (
8199
+ // Owned by the listbox (`aria-owns`): its options for assistive tech, pinned under
8200
+ // the scroller and the empty state for the eye.
8201
+ // biome-ignore lint/a11y/useSemanticElements: a group of options inside a listbox, not a form fieldset
8202
+ /* @__PURE__ */ jsx40("div", { id: actionsId, role: "group", className: Select_default.actions, children: actions })
8203
+ ) : null
8204
+ ] }) }),
8205
+ /* @__PURE__ */ jsx40(VisuallyHidden, { live: "polite", children: loading || loadingMore ? labels.loading : "" }),
8206
+ /* @__PURE__ */ jsx40(HighlightOnOpen, {})
8207
+ ]
8208
+ }
8161
8209
  );
8162
- const [isOpen, setOpen] = useOpenState({ open, defaultOpen, onOpenChange, disabled });
8163
- const highlight = useCreateStore(void 0);
8164
- const registry = useListboxRegistry();
8165
- const [query, setQuery] = useControllableState({
8166
- value: search,
8167
- defaultValue: defaultSearch,
8168
- onChange: onSearchChange
8210
+ }
8211
+ SelectContent.displayName = "Select.Content";
8212
+ function HighlightOnOpen() {
8213
+ const { isOpen, query, filter, selected, registry, highlight } = useSelectContext();
8214
+ const view = useListboxView(registry, query, filter);
8215
+ const latest = React62.useRef({ query, filter, selected });
8216
+ latest.current = { query, filter, selected };
8217
+ React62.useLayoutEffect(() => {
8218
+ if (!isOpen) return;
8219
+ const { query: text, filter: filtered, selected: picked } = latest.current;
8220
+ const first = registry.view(text, filtered).navigable.find((id) => picked.includes(id));
8221
+ highlight.set(first);
8222
+ if (first !== void 0) revealHighlighted(registry.nodeOf(first));
8223
+ return () => highlight.set(void 0);
8224
+ }, [isOpen, registry, highlight]);
8225
+ const latestView = React62.useRef(view);
8226
+ latestView.current = view;
8227
+ React62.useLayoutEffect(() => {
8228
+ if (query !== "") highlight.set(latestView.current.navigable[0]);
8229
+ }, [query, highlight]);
8230
+ React62.useLayoutEffect(() => {
8231
+ if (query === "") return;
8232
+ const current = highlight.get();
8233
+ if (current === void 0 || isActionValue(current) || !view.navigable.includes(current)) {
8234
+ highlight.set(view.navigable[0]);
8235
+ }
8236
+ }, [view, query, highlight]);
8237
+ return null;
8238
+ }
8239
+ function SelectGroup({ className, ...rest }) {
8240
+ return /* @__PURE__ */ jsx40(MenuGroup, { ...rest, className: cx(Select_default.group, className) });
8241
+ }
8242
+ SelectGroup.displayName = "Select.Group";
8243
+ function SelectSeparator({ className, ...rest }) {
8244
+ return /* @__PURE__ */ jsx40(Divider, { ...rest, className: cx(menu_default.separator, Select_default.separator, className) });
8245
+ }
8246
+ SelectSeparator.displayName = "Select.Separator";
8247
+ var Select = {
8248
+ Root: SelectRoot,
8249
+ Trigger: SelectTrigger,
8250
+ Value: SelectValue,
8251
+ TriggerIcon: SelectTriggerIcon,
8252
+ Content: SelectContent,
8253
+ Item: SelectItem,
8254
+ ItemIcon: SelectItemIcon,
8255
+ ItemText: SelectItemText,
8256
+ ItemDescription: SelectItemDescription,
8257
+ ItemMeta: SelectItemMeta,
8258
+ Group: SelectGroup,
8259
+ Separator: SelectSeparator,
8260
+ Action: SelectAction
8261
+ };
8262
+
8263
+ // src/internal/swatch.tsx
8264
+ import * as React64 from "react";
8265
+
8266
+ // src/hooks/useElementSize.ts
8267
+ import * as React63 from "react";
8268
+ var rounded = (width, height) => ({
8269
+ width: Math.round(width),
8270
+ height: Math.round(height)
8271
+ });
8272
+ var sizeOf = (element) => {
8273
+ const rect = element.getBoundingClientRect();
8274
+ return rounded(rect.width, rect.height);
8275
+ };
8276
+ var entrySize = (entry) => {
8277
+ const box = entry.borderBoxSize?.[0];
8278
+ return box ? rounded(box.inlineSize, box.blockSize) : rounded(entry.contentRect.width, entry.contentRect.height);
8279
+ };
8280
+ var sameSize = (a, b) => a === b || a !== null && b !== null && a.width === b.width && a.height === b.height;
8281
+ function useRefNode(ref, enabled, subscribe) {
8282
+ const subscribeRef = React63.useRef(subscribe);
8283
+ const active2 = React63.useRef(null);
8284
+ React63.useLayoutEffect(() => {
8285
+ subscribeRef.current = subscribe;
8286
+ const node = enabled ? ref.current : null;
8287
+ if (active2.current?.node === node) return;
8288
+ active2.current?.stop();
8289
+ active2.current = node ? { node, stop: subscribeRef.current(node) } : null;
8169
8290
  });
8170
- const triggerRef = React65.useRef(null);
8171
- const inSegment = React65.useContext(InputSegmentContext);
8172
- const segment = React65.useMemo(
8173
- () => inSegment ? { label: ariaLabel } : null,
8174
- [inSegment, ariaLabel]
8175
- );
8176
- const wasOpenRef = React65.useRef(isOpen);
8177
- React65.useEffect(() => {
8178
- if (wasOpenRef.current && !isOpen) setQuery("");
8179
- wasOpenRef.current = isOpen;
8180
- }, [isOpen, setQuery]);
8181
- const pick = React65.useCallback(
8182
- (optionValue) => {
8183
- if (multiple) {
8184
- const list = Array.isArray(value) ? value : [];
8185
- commitRef.current(
8186
- list.includes(optionValue) ? list.filter((item) => item !== optionValue) : [...list, optionValue]
8187
- );
8188
- return;
8189
- }
8190
- commitRef.current(optionValue);
8191
- setOpen(false);
8291
+ React63.useLayoutEffect(
8292
+ () => () => {
8293
+ active2.current?.stop();
8294
+ active2.current = null;
8192
8295
  },
8193
- [multiple, value, setOpen]
8194
- );
8195
- const clear = React65.useCallback(() => commitRef.current(multiple ? [] : ""), [multiple]);
8196
- const context = React65.useMemo(
8197
- () => ({
8198
- size,
8199
- invalid: ids.invalid,
8200
- focusRing,
8201
- required: ids.required,
8202
- disabled,
8203
- placeholder,
8204
- multiple,
8205
- selected,
8206
- registry,
8207
- pick,
8208
- clear,
8209
- clearable,
8210
- loading,
8211
- saving,
8212
- loadingMore,
8213
- hasMore,
8214
- onLoadMore,
8215
- loadError,
8216
- onRetry,
8217
- filter,
8218
- isOpen,
8219
- setOpen,
8220
- closeOnEscape,
8221
- closeOnOutsideClick,
8222
- highlight,
8223
- query,
8224
- setQuery,
8225
- triggerId: ids.controlId,
8226
- listboxId: `${ids.controlId}-listbox`,
8227
- describedBy: ids.describedBy,
8228
- triggerRef,
8229
- labels,
8230
- segment
8231
- }),
8232
- [
8233
- size,
8234
- ids.invalid,
8235
- ids.controlId,
8236
- ids.describedBy,
8237
- focusRing,
8238
- ids.required,
8239
- disabled,
8240
- placeholder,
8241
- multiple,
8242
- selected,
8243
- registry,
8244
- pick,
8245
- clear,
8246
- clearable,
8247
- loading,
8248
- saving,
8249
- loadingMore,
8250
- hasMore,
8251
- onLoadMore,
8252
- loadError,
8253
- onRetry,
8254
- filter,
8255
- isOpen,
8256
- setOpen,
8257
- closeOnEscape,
8258
- closeOnOutsideClick,
8259
- highlight,
8260
- query,
8261
- setQuery,
8262
- labels,
8263
- segment
8264
- ]
8265
- );
8266
- const body = /* @__PURE__ */ jsxs27(Fragment17, { children: [
8267
- /* @__PURE__ */ jsx42(SelectProvider, { value: context, children }),
8268
- name ? (selected.length > 0 || multiple ? selected : [""]).map((item) => /* @__PURE__ */ jsx42("input", { type: "hidden", name, value: item, disabled }, item)) : null,
8269
- /* @__PURE__ */ jsx42(VisuallyHidden, { live: "polite", children: announcement })
8270
- ] });
8271
- if (segment) {
8272
- return tier.provide(
8273
- /* @__PURE__ */ jsx42(
8274
- "div",
8275
- {
8276
- ...rest,
8277
- className: cx(Select_default.segment, className),
8278
- "data-field-segment": "",
8279
- "data-size": size,
8280
- children: body
8281
- }
8282
- )
8283
- );
8284
- }
8285
- return tier.provide(
8286
- /* @__PURE__ */ jsx42(
8287
- FieldFrame,
8288
- {
8289
- ...rest,
8290
- "aria-label": ariaLabel,
8291
- size,
8292
- ids,
8293
- label,
8294
- required,
8295
- optional,
8296
- hint,
8297
- hintTone,
8298
- error,
8299
- disabled,
8300
- optionalLabel: labels.optional,
8301
- className,
8302
- children: body
8303
- }
8304
- )
8296
+ []
8305
8297
  );
8306
8298
  }
8307
- SelectRoot.displayName = "Select.Root";
8308
- var takeNext = (_current, next) => next;
8309
- function SelectTrigger({
8310
- className,
8311
- children,
8312
- onClick: onClick2,
8313
- onKeyDown: onKeyDown2,
8314
- "aria-describedby": ariaDescribedBy,
8315
- ref,
8316
- ...rest
8317
- }) {
8318
- const {
8319
- isOpen,
8320
- setOpen,
8321
- triggerId,
8322
- listboxId,
8323
- disabled,
8324
- size,
8325
- invalid,
8326
- focusRing,
8327
- required,
8328
- describedBy,
8329
- triggerRef,
8330
- loading,
8331
- saving,
8332
- clearable,
8333
- selected,
8334
- clear,
8335
- labels,
8336
- registry,
8337
- segment
8338
- } = useSelectContext();
8339
- const mergedRef = useMergedRefs(triggerRef, ref);
8340
- useListboxView(registry);
8341
- const valueText = selected.map(registry.labelOf).join(", ");
8342
- const segmentName = segment?.label ? valueText ? `${segment.label}: ${valueText}` : segment.label : void 0;
8343
- const parts = React65.Children.toArray(children);
8344
- const iconOnly = parts.some((node) => React65.isValidElement(node) && node.type === SelectTriggerIcon) && !parts.some((node) => React65.isValidElement(node) && node.type === SelectValue);
8345
- const busy = loading || saving;
8346
- const showClear = clearable && selected.length > 0 && !disabled && !busy;
8347
- const clearPresence = usePartPresence({ present: showClear, axis: "inline" });
8348
- const toggle = floatingTriggerProps({ open: isOpen, setOpen, openOnArrow: true });
8349
- return /* @__PURE__ */ jsxs27(
8350
- "button",
8351
- {
8352
- ...rest,
8353
- ref: mergedRef,
8354
- id: triggerId,
8355
- type: "button",
8356
- role: "combobox",
8357
- "aria-expanded": toggle["aria-expanded"],
8358
- "aria-haspopup": "listbox",
8359
- "aria-controls": isOpen ? listboxId : void 0,
8360
- "aria-invalid": invalid || void 0,
8361
- "aria-required": required || void 0,
8362
- "aria-describedby": [ariaDescribedBy, describedBy].filter(Boolean).join(" ") || void 0,
8363
- "aria-busy": busy || void 0,
8364
- "aria-label": segmentName ?? rest["aria-label"],
8365
- disabled,
8366
- className: cx(
8367
- segment ? Select_default.segmentTrigger : cx(fieldTriggerClass, Select_default.trigger),
8368
- className
8369
- ),
8370
- onClick: (event) => {
8371
- onClick2?.(event);
8372
- if (!event.defaultPrevented) toggle.onClick();
8373
- },
8374
- onKeyDown: (event) => {
8375
- onKeyDown2?.(event);
8376
- if (event.defaultPrevented) return;
8377
- toggle.onKeyDown?.(event);
8378
- if (event.defaultPrevented) return;
8379
- if (event.key === " " || event.key === "Enter") {
8380
- event.preventDefault();
8381
- if (!isOpen) setOpen(true);
8382
- } else if (showClear && (event.key === "Delete" || event.key === "Backspace")) {
8383
- event.preventDefault();
8384
- clear();
8385
- }
8386
- },
8387
- ...toDataAttributes({
8388
- state: toggle["data-state"],
8389
- size,
8390
- invalid: invalid || void 0,
8391
- loading: busy || void 0,
8392
- disabled: disabled || void 0,
8393
- "focus-ring": focusRing,
8394
- "icon-only": iconOnly || void 0,
8395
- segment: segment ? true : void 0
8396
- }),
8397
- children: [
8398
- /* @__PURE__ */ jsxs27("span", { className: Select_default.triggerMain, children: [
8399
- children,
8400
- iconOnly ? /* @__PURE__ */ jsx42(SelectValue, { className: visuallyHiddenClass }) : null
8401
- ] }),
8402
- showClear ? (
8403
- // A segment, not a button: interactive content inside a <button> is invalid. The keyboard
8404
- // clears with Delete / Backspace on the trigger. A touch target in height, like the clear
8405
- // segment of a field (`FieldAction`).
8406
- /* @__PURE__ */ jsx42(
8407
- "span",
8408
- {
8409
- ref: clearPresence.ref,
8410
- className: cx(Select_default.clear, touchTargetBlockClass, clearPresence.className),
8411
- "aria-hidden": "true",
8412
- title: labels.clear,
8413
- "data-select-clear": "",
8414
- onMouseDown: (event) => event.preventDefault(),
8415
- onClick: (event) => {
8416
- event.stopPropagation();
8417
- clear();
8418
- },
8419
- children: /* @__PURE__ */ jsx42(Icon, { name: "action.close" })
8420
- }
8421
- )
8422
- ) : null,
8423
- /* @__PURE__ */ jsx42("span", { className: Select_default.chevron, "aria-hidden": "true", children: /* @__PURE__ */ jsx42(GlyphSwap, { children: busy ? /* @__PURE__ */ jsx42(Spinner, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx42(Icon, { name: "nav.chevronDown" }) }) })
8424
- ]
8425
- }
8299
+ function useElementSize(ref, { enabled = true } = {}) {
8300
+ const [size, setSize] = React63.useState(null);
8301
+ useRefNode(ref, enabled, (node) => {
8302
+ const update = (next) => setSize((prev) => sameSize(prev, next) ? prev : next);
8303
+ update(sizeOf(node));
8304
+ if (typeof ResizeObserver === "undefined") return () => update(null);
8305
+ const observer = new ResizeObserver(([entry]) => update(entry ? entrySize(entry) : null));
8306
+ observer.observe(node);
8307
+ return () => {
8308
+ observer.disconnect();
8309
+ update(null);
8310
+ };
8311
+ });
8312
+ return size;
8313
+ }
8314
+ function useResizeEffect(ref, onResize, { enabled = true, children = false } = {}) {
8315
+ const callback = React63.useRef(onResize);
8316
+ React63.useLayoutEffect(() => {
8317
+ callback.current = onResize;
8318
+ });
8319
+ useRefNode(ref, enabled, (node) => {
8320
+ if (typeof ResizeObserver === "undefined") return () => {
8321
+ };
8322
+ const observer = new ResizeObserver(() => callback.current());
8323
+ const observeAll = () => {
8324
+ observer.observe(node);
8325
+ if (children) for (const child of Array.from(node.children)) observer.observe(child);
8326
+ };
8327
+ observeAll();
8328
+ const mutation = children ? new MutationObserver(observeAll) : null;
8329
+ mutation?.observe(node, { childList: true });
8330
+ return () => {
8331
+ mutation?.disconnect();
8332
+ observer.disconnect();
8333
+ };
8334
+ });
8335
+ }
8336
+
8337
+ // src/internal/swatch.module.css
8338
+ var swatch_default = {
8339
+ fill: "swatch_fill",
8340
+ checker: "swatch_checker",
8341
+ checkerboard: "swatch_checkerboard",
8342
+ hueFill: "swatch_hueFill",
8343
+ tier: "swatch_tier",
8344
+ grid: "swatch_grid",
8345
+ chip: "swatch_chip",
8346
+ swatch: "swatch_swatch",
8347
+ trigger: "swatch_trigger",
8348
+ check: "swatch_check"
8349
+ };
8350
+
8351
+ // src/internal/swatch.tsx
8352
+ import { Fragment as Fragment17, jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
8353
+ var COLOR_PRESETS = [
8354
+ { value: "#ef4444", label: "\u041A\u0440\u0430\u0441\u043D\u044B\u0439" },
8355
+ { value: "#f97316", label: "\u041E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439" },
8356
+ { value: "#eab308", label: "\u0416\u0451\u043B\u0442\u044B\u0439" },
8357
+ { value: "#22c55e", label: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439" },
8358
+ { value: "#14b8a6", label: "\u0411\u0438\u0440\u044E\u0437\u043E\u0432\u044B\u0439" },
8359
+ { value: "#5068f5", label: "\u0421\u0438\u043D\u0438\u0439" },
8360
+ { value: "#a855f7", label: "\u0424\u0438\u043E\u043B\u0435\u0442\u043E\u0432\u044B\u0439" },
8361
+ { value: "#ec4899", label: "\u0420\u043E\u0437\u043E\u0432\u044B\u0439" },
8362
+ { value: "#b91c1c", label: "\u0422\u0451\u043C\u043D\u043E-\u043A\u0440\u0430\u0441\u043D\u044B\u0439" },
8363
+ { value: "#c2410c", label: "\u0422\u0451\u043C\u043D\u043E-\u043E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439" },
8364
+ { value: "#a16207", label: "\u0413\u043E\u0440\u0447\u0438\u0447\u043D\u044B\u0439" },
8365
+ { value: "#15803d", label: "\u0422\u0451\u043C\u043D\u043E-\u0437\u0435\u043B\u0451\u043D\u044B\u0439" },
8366
+ { value: "#0f766e", label: "\u0422\u0451\u043C\u043D\u043E-\u0431\u0438\u0440\u044E\u0437\u043E\u0432\u044B\u0439" },
8367
+ { value: "#2f4ae0", label: "\u0422\u0451\u043C\u043D\u043E-\u0441\u0438\u043D\u0438\u0439" },
8368
+ { value: "#7e22ce", label: "\u0422\u0451\u043C\u043D\u043E-\u0444\u0438\u043E\u043B\u0435\u0442\u043E\u0432\u044B\u0439" },
8369
+ { value: "#be185d", label: "\u0422\u0451\u043C\u043D\u043E-\u0440\u043E\u0437\u043E\u0432\u044B\u0439" }
8370
+ ];
8371
+ var PALETTE_COLOR_NAMES = {
8372
+ gray: "\u0421\u0435\u0440\u044B\u0439",
8373
+ red: "\u041A\u0440\u0430\u0441\u043D\u044B\u0439",
8374
+ orange: "\u041E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439",
8375
+ yellow: "\u0416\u0451\u043B\u0442\u044B\u0439",
8376
+ green: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439",
8377
+ teal: "\u0411\u0438\u0440\u044E\u0437\u043E\u0432\u044B\u0439",
8378
+ sky: "\u0413\u043E\u043B\u0443\u0431\u043E\u0439",
8379
+ blue: "\u0421\u0438\u043D\u0438\u0439",
8380
+ purple: "\u0424\u0438\u043E\u043B\u0435\u0442\u043E\u0432\u044B\u0439",
8381
+ pink: "\u0420\u043E\u0437\u043E\u0432\u044B\u0439"
8382
+ };
8383
+ var PALETTE_ORDER = Object.keys(PALETTE_COLOR_NAMES);
8384
+ function useSwatchOptions(presets, allowEmpty, emptyLabel) {
8385
+ return React64.useMemo(
8386
+ () => [
8387
+ ...presets.map((preset) => ({ ...preset, contrast: markContrast(preset.value) })),
8388
+ ...allowEmpty ? [{ value: null, label: emptyLabel, contrast: "surface" }] : []
8389
+ ],
8390
+ [presets, allowEmpty, emptyLabel]
8426
8391
  );
8427
8392
  }
8428
- SelectTrigger.displayName = "Select.Trigger";
8429
- function SelectValue({ renderValue, className, ...rest }) {
8430
- const { selected, registry, placeholder, multiple, size } = useSelectContext();
8431
- useListboxView(registry);
8432
- const text = selected.map(registry.labelOf).join(", ");
8433
- if (selected.length > 0 && renderValue && !multiple) {
8434
- const value = selected[0] ?? "";
8435
- const parts = splitItemChildren(renderValue({ value, label: text }));
8436
- return /* @__PURE__ */ jsxs27(
8437
- "span",
8438
- {
8439
- ...rest,
8440
- className: cx(Select_default.value, className),
8441
- ...toDataAttributes({
8442
- rich: parts.rich || void 0,
8443
- media: parts.leading.length > 0 || parts.meta.length > 0 || void 0
8444
- }),
8445
- children: [
8446
- sizeMedia(parts.leading, size),
8447
- /* @__PURE__ */ jsx42("span", { className: Select_default.valueBody, children: parts.body }),
8448
- parts.meta
8449
- ]
8450
- }
8451
- );
8452
- }
8453
- return /* @__PURE__ */ jsx42(
8454
- "span",
8455
- {
8456
- ...rest,
8457
- className: cx(Select_default.value, className),
8458
- ...toDataAttributes({ placeholder: selected.length === 0 || void 0 }),
8459
- children: selected.length > 0 ? text : placeholder
8460
- }
8393
+ function usePaletteOptions(palette, allowEmpty, emptyLabel, names) {
8394
+ return React64.useMemo(
8395
+ () => [
8396
+ ...palette.map((hue) => ({ value: hue, label: names[hue], contrast: "hue" })),
8397
+ ...allowEmpty ? [{ value: null, label: emptyLabel, contrast: "surface" }] : []
8398
+ ],
8399
+ [palette, allowEmpty, emptyLabel, names]
8461
8400
  );
8462
8401
  }
8463
- SelectValue.displayName = "Select.Value";
8464
- function SelectTriggerIcon({ className, ...rest }) {
8465
- return /* @__PURE__ */ jsx42("span", { "aria-hidden": "true", className: cx(Select_default.triggerIcon, className), ...rest });
8402
+ var swatchClass = cx(swatch_default.swatch, press_default.press);
8403
+ var swatchTriggerClass = cx(swatch_default.trigger, press_default.press);
8404
+ var swatchTierClass = cx(fieldTierClass, swatch_default.tier);
8405
+ var swatchGridClass = swatch_default.grid;
8406
+ var checkerboardClass = swatch_default.checkerboard;
8407
+ function SwatchFill({ value, hue = false }) {
8408
+ if (value == null) return /* @__PURE__ */ jsx41("span", { "aria-hidden": true, className: swatch_default.checker });
8409
+ if (hue) return /* @__PURE__ */ jsx41("span", { "aria-hidden": true, className: cx(swatch_default.fill, swatch_default.hueFill) });
8410
+ return /* @__PURE__ */ jsx41("svg", { className: swatch_default.fill, "aria-hidden": "true", viewBox: "0 0 1 1", preserveAspectRatio: "none", children: /* @__PURE__ */ jsx41("rect", { width: "1", height: "1", fill: value }) });
8466
8411
  }
8467
- SelectTriggerIcon.displayName = "Select.TriggerIcon";
8468
- var LOADING_ROWS2 = 4;
8469
- var LOADING_MORE_ROWS = 2;
8470
- function SkeletonRows({ count }) {
8471
- return Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsx42(
8472
- "div",
8473
- {
8474
- "aria-hidden": "true",
8475
- className: cx(menu_default.item, menu_default.skeletonRow),
8476
- "data-skeleton": "",
8477
- children: /* @__PURE__ */ jsx42(Skeleton, {})
8478
- },
8479
- index
8480
- ));
8412
+ function SwatchContent({
8413
+ value,
8414
+ selected,
8415
+ hue = false
8416
+ }) {
8417
+ return /* @__PURE__ */ jsxs26(Fragment17, { children: [
8418
+ /* @__PURE__ */ jsx41(SwatchFill, { value, hue }),
8419
+ /* @__PURE__ */ jsx41(CheckMark, { state: selected ? "checked" : "unchecked", className: swatch_default.check })
8420
+ ] });
8481
8421
  }
8482
- function SelectContent({ searchable = false, className, children, ...rest }) {
8483
- const {
8484
- isOpen,
8485
- setOpen,
8486
- closeOnEscape,
8487
- closeOnOutsideClick,
8488
- triggerId,
8489
- listboxId,
8490
- triggerRef,
8491
- highlight,
8492
- multiple,
8493
- size,
8494
- query,
8495
- setQuery,
8496
- loading,
8497
- saving,
8498
- loadingMore,
8499
- hasMore,
8500
- onLoadMore,
8501
- loadError,
8502
- onRetry,
8503
- filter,
8504
- labels,
8505
- registry
8506
- } = useSelectContext();
8507
- const listboxRef = React65.useRef(null);
8508
- const setListboxRef = useMergedRefs(listboxRef);
8509
- const items = [];
8510
- const actions = [];
8511
- for (const child of React65.Children.toArray(children)) {
8512
- (React65.isValidElement(child) && child.type === SelectAction ? actions : items).push(child);
8422
+ function SwatchChip({ value, className, ...rest }) {
8423
+ return /* @__PURE__ */ jsx41("span", { ...rest, "aria-hidden": true, className: cx(swatch_default.chip, className), children: /* @__PURE__ */ jsx41(SwatchFill, { value }) });
8424
+ }
8425
+ function parseHexColor(text) {
8426
+ const hex = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(text.trim())?.[1]?.toLowerCase();
8427
+ if (!hex) return null;
8428
+ return `#${hex.length === 3 ? [...hex].map((c) => c + c).join("") : hex}`;
8429
+ }
8430
+ function sameColor(a, b) {
8431
+ return (a ?? "").trim().toLowerCase() === (b ?? "").trim().toLowerCase();
8432
+ }
8433
+ function colorToRgb(value) {
8434
+ const input = value.trim().toLowerCase();
8435
+ const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(input)?.[1];
8436
+ if (hex) {
8437
+ const full = hex.length <= 4 ? [...hex].map((c) => c + c).join("") : hex;
8438
+ return [0, 2, 4].map((i) => Number.parseInt(full.slice(i, i + 2), 16));
8513
8439
  }
8514
- const actionsId = `${listboxId}-actions`;
8515
- const floating = useFloatingLayer({
8516
- open: isOpen,
8517
- onOpenChange: setOpen,
8518
- triggerRef,
8519
- closeOnEscape,
8520
- closeOnOutsideClick,
8521
- matchAnchorWidth: true,
8522
- focusOnOpen: true,
8523
- tabExit: "always",
8524
- sheet: true
8525
- });
8526
- const highlighted = useStoreSlice(highlight, (value) => value);
8527
- const view = useListboxView(registry, query, filter);
8528
- const isEmpty = view.matchCount === 0;
8529
- const typeahead = useTypeahead();
8530
- const region = hasContent(loadError) ? "error" : loading && isEmpty ? "loading" : "ready";
8531
- const { sentinelRef, request: requestMore } = useLoadMore({
8532
- enabled: region === "ready" && hasMore && Boolean(onLoadMore) && !loading && !loadingMore,
8533
- onLoadMore,
8534
- scrollRef: listboxRef,
8535
- round: view
8536
- });
8537
- const setSentinelRef = useMergedRefs(sentinelRef);
8538
- const lastOption = view.navigable.filter((id) => !isActionValue(id)).at(-1);
8539
- React65.useEffect(() => {
8540
- if (highlighted !== void 0 && highlighted === lastOption) requestMore();
8541
- }, [highlighted, lastOption, requestMore]);
8542
- const handleKeyDown = (event) => {
8543
- if (region === "error") {
8544
- if (event.key === "Enter" && onRetry && !(event.target instanceof HTMLButtonElement)) {
8545
- event.preventDefault();
8546
- onRetry();
8547
- }
8548
- return;
8549
- }
8550
- const inSearch = event.target instanceof HTMLInputElement;
8551
- if (inSearch && [" ", "Home", "End"].includes(event.key)) return;
8552
- const ids = view.navigable;
8553
- const printable = event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
8554
- if (printable && !inSearch && (event.key !== " " || typeahead.isTyping())) {
8555
- event.preventDefault();
8556
- const match = typeahead.find(event.key, ids, highlight.get(), registry.labelOf);
8557
- if (match !== void 0) {
8558
- highlight.set(match);
8559
- revealHighlighted(registry.nodeOf(match));
8560
- }
8561
- return;
8562
- }
8563
- const moved = handleListboxKeyDown(event, {
8564
- ids,
8565
- highlight,
8566
- activate: (value) => registry.activate(value)
8567
- });
8568
- if (moved !== null) revealHighlighted(registry.nodeOf(moved));
8440
+ const fn = /^(rgba?|hsla?)\(([^)]+)\)$/.exec(input);
8441
+ if (!fn) return null;
8442
+ const parts = fn[2].split(/[\s,/]+/).filter(Boolean);
8443
+ if (parts.length < 3) return null;
8444
+ const num = (part, scale) => part.endsWith("%") ? Number.parseFloat(part) / 100 * scale : Number.parseFloat(part);
8445
+ if (fn[1].startsWith("rgb")) {
8446
+ const rgb = parts.slice(0, 3).map((part) => num(part, 255));
8447
+ return rgb.every(Number.isFinite) ? rgb : null;
8448
+ }
8449
+ const h = Number.parseFloat(parts[0]);
8450
+ const s = num(parts[1], 1);
8451
+ const l = num(parts[2], 1);
8452
+ if (![h, s, l].every(Number.isFinite)) return null;
8453
+ const a = s * Math.min(l, 1 - l);
8454
+ const channel = (n) => {
8455
+ const k = (n + h / 30) % 12;
8456
+ return 255 * (l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)));
8569
8457
  };
8570
- if (!floating.mounted) return /* @__PURE__ */ jsx42("div", { hidden: true, children: items });
8571
- const activeDescendant = isOpen && highlighted !== void 0 ? optionDomId(listboxId, highlighted) : void 0;
8572
- return /* @__PURE__ */ jsxs27(
8573
- FloatingPanel,
8458
+ return [channel(0), channel(8), channel(4)];
8459
+ }
8460
+ function markContrast(value) {
8461
+ const rgb = colorToRgb(value);
8462
+ if (!rgb) return "dark";
8463
+ const lin = (c) => {
8464
+ const s = c / 255;
8465
+ return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
8466
+ };
8467
+ const l = 0.2126 * lin(rgb[0]) + 0.7152 * lin(rgb[1]) + 0.0722 * lin(rgb[2]);
8468
+ return l > 0.179 ? "dark" : "light";
8469
+ }
8470
+ function balancedColumns(count, width, cell, gap) {
8471
+ if (count < 1 || width <= 0 || cell <= 0) return Math.max(1, count);
8472
+ const fit = Math.max(1, Math.floor((width + gap) / (cell + gap)));
8473
+ const rows = Math.ceil(count / Math.min(count, fit));
8474
+ return Math.ceil(count / rows);
8475
+ }
8476
+ function useBalancedColumns(gridRef, count, cellSelector) {
8477
+ const [columns, setColumns] = React64.useState();
8478
+ const measure = React64.useCallback(() => {
8479
+ const grid = gridRef.current;
8480
+ if (!grid) return;
8481
+ const cell = grid.querySelector(cellSelector)?.offsetHeight ?? 0;
8482
+ const gap = Number.parseFloat(getComputedStyle(grid).columnGap) || 0;
8483
+ setColumns(cell > 0 ? balancedColumns(count, grid.clientWidth, cell, gap) : void 0);
8484
+ }, [gridRef, count, cellSelector]);
8485
+ React64.useLayoutEffect(measure, [measure]);
8486
+ useResizeEffect(gridRef, measure);
8487
+ return columns;
8488
+ }
8489
+ function firstRowLength(items) {
8490
+ const top = items[0]?.offsetTop;
8491
+ const count = items.findIndex((item) => !item || item.offsetTop !== top);
8492
+ return Math.max(1, count === -1 ? items.length : count);
8493
+ }
8494
+ function useSwatchGrid(count) {
8495
+ const items = React64.useRef([]);
8496
+ const itemRef = React64.useCallback(
8497
+ (index) => (node) => {
8498
+ items.current[index] = node;
8499
+ },
8500
+ []
8501
+ );
8502
+ const move = React64.useCallback(
8503
+ (event, from, columns) => {
8504
+ const focused = document.activeElement;
8505
+ const current = focused instanceof HTMLElement ? items.current.indexOf(focused) : -1;
8506
+ const next = gridIndex(
8507
+ event.key,
8508
+ current === -1 ? from : current,
8509
+ count,
8510
+ columns ?? firstRowLength(items.current)
8511
+ );
8512
+ if (next === null) return null;
8513
+ event.preventDefault();
8514
+ items.current[next]?.focus();
8515
+ return next;
8516
+ },
8517
+ [count]
8518
+ );
8519
+ const focus = React64.useCallback((index) => {
8520
+ items.current[index]?.focus({ preventScroll: true });
8521
+ }, []);
8522
+ return { itemRef, move, focus };
8523
+ }
8524
+
8525
+ // src/components/color-swatches/ColorSwatches.tsx
8526
+ import * as React65 from "react";
8527
+
8528
+ // src/components/color-swatches/ColorSwatches.module.css
8529
+ var ColorSwatches_default = {
8530
+ grid: "ColorSwatches_grid"
8531
+ };
8532
+
8533
+ // src/components/color-swatches/ColorSwatches.tsx
8534
+ import { jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
8535
+ var COLOR_SWATCHES_LABELS = {
8536
+ group: "\u0426\u0432\u0435\u0442",
8537
+ empty: "\u0411\u0435\u0437 \u0446\u0432\u0435\u0442\u0430",
8538
+ optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
8539
+ colorNames: PALETTE_COLOR_NAMES
8540
+ };
8541
+ function ColorSwatches(props) {
8542
+ const {
8543
+ mode,
8544
+ value,
8545
+ defaultValue,
8546
+ onValueChange,
8547
+ presets = COLOR_PRESETS,
8548
+ palette = PALETTE_ORDER,
8549
+ ...rest
8550
+ } = props;
8551
+ return /* @__PURE__ */ jsx42(
8552
+ SwatchGrid,
8574
8553
  {
8575
8554
  ...rest,
8576
- floating,
8577
- size,
8578
- className: cx(fieldTierClass, menu_default.tier, menu_default.menu, Select_default.content, className),
8579
- onKeyDown: handleKeyDown,
8580
- ...toDataAttributes({ searching: query !== "" || void 0 }),
8581
- children: [
8582
- searchable ? (
8583
- // The permanent focus of the panel: no ring, the caret is the indicator (foundation §7).
8584
- /* @__PURE__ */ jsxs27("div", { className: cx(menu_default.searchRow, Select_default.search), children: [
8585
- /* @__PURE__ */ jsx42(Icon, { name: "action.search", size: "s" }),
8586
- /* @__PURE__ */ jsx42(
8587
- "input",
8588
- {
8589
- type: "text",
8590
- className: menu_default.searchInput,
8591
- value: query,
8592
- placeholder: labels.search,
8593
- "aria-label": labels.search,
8594
- "aria-controls": region === "error" ? void 0 : listboxId,
8595
- "aria-activedescendant": activeDescendant,
8596
- "aria-autocomplete": "list",
8597
- autoComplete: "off",
8598
- spellCheck: false,
8599
- "data-autofocus": "",
8600
- onChange: (event) => setQuery(event.target.value)
8601
- }
8602
- )
8603
- ] })
8604
- ) : null,
8605
- /* @__PURE__ */ jsx42(RegionSwap, { state: region, fill: true, children: region === "error" ? /* @__PURE__ */ jsxs27(EmptyPage.Root, { layout: "compact", size, role: "alert", children: [
8606
- /* @__PURE__ */ jsx42(EmptyPage.Title, { as: "p", children: loadError }),
8607
- onRetry ? /* @__PURE__ */ jsx42(EmptyPage.Actions, { children: /* @__PURE__ */ jsxs27(Button.Root, { variant: "soft", tone: "neutral", onClick: onRetry, children: [
8608
- /* @__PURE__ */ jsx42(Button.Icon, { children: /* @__PURE__ */ jsx42(Icon, { name: "action.refresh" }) }),
8609
- labels.retry
8610
- ] }) }) : null
8611
- ] }) : /* @__PURE__ */ jsxs27(Fragment17, { children: [
8612
- /* @__PURE__ */ jsxs27(
8613
- ScrollContainer,
8614
- {
8615
- ref: setListboxRef,
8616
- id: listboxId,
8617
- role: "listbox",
8618
- "aria-multiselectable": multiple || void 0,
8619
- "aria-labelledby": triggerId,
8620
- "aria-activedescendant": searchable ? void 0 : activeDescendant,
8621
- "aria-busy": loading || loadingMore || saving || void 0,
8622
- "aria-owns": actions.length > 0 ? actionsId : void 0,
8623
- tabIndex: -1,
8624
- "data-autofocus": searchable ? void 0 : "",
8625
- className: Select_default.listbox,
8626
- children: [
8627
- items,
8628
- region === "loading" ? /* @__PURE__ */ jsx42(SkeletonRows, { count: LOADING_ROWS2 }) : null,
8629
- region === "ready" && hasMore ? /* @__PURE__ */ jsx42("div", { ref: setSentinelRef, "aria-hidden": "true", className: menu_default.loadSentinel }) : null,
8630
- region === "ready" && loadingMore ? /* @__PURE__ */ jsx42(SkeletonRows, { count: LOADING_MORE_ROWS }) : null
8631
- ]
8632
- }
8633
- ),
8634
- region === "ready" && isEmpty ? /* @__PURE__ */ jsxs27(EmptyPage.Root, { layout: "compact", size, role: "status", children: [
8635
- /* @__PURE__ */ jsx42(EmptyPage.Title, { as: "p", children: labels.empty }),
8636
- query !== "" && labels.emptyHint ? /* @__PURE__ */ jsx42(EmptyPage.Description, { children: labels.emptyHint }) : null
8637
- ] }) : null,
8638
- actions.length > 0 ? (
8639
- // Owned by the listbox (`aria-owns`): its options for assistive tech, pinned under
8640
- // the scroller and the empty state for the eye.
8641
- // biome-ignore lint/a11y/useSemanticElements: a group of options inside a listbox, not a form fieldset
8642
- /* @__PURE__ */ jsx42("div", { id: actionsId, role: "group", className: Select_default.actions, children: actions })
8643
- ) : null
8644
- ] }) }),
8645
- /* @__PURE__ */ jsx42(VisuallyHidden, { live: "polite", children: loading || loadingMore ? labels.loading : "" }),
8646
- /* @__PURE__ */ jsx42(HighlightOnOpen, {})
8647
- ]
8555
+ hues: mode === "palette",
8556
+ presets,
8557
+ palette,
8558
+ value,
8559
+ defaultValue: defaultValue ?? null,
8560
+ onValueChange
8648
8561
  }
8649
8562
  );
8650
8563
  }
8651
- SelectContent.displayName = "Select.Content";
8652
- function HighlightOnOpen() {
8653
- const { isOpen, query, filter, selected, registry, highlight } = useSelectContext();
8654
- const view = useListboxView(registry, query, filter);
8655
- const latest = React65.useRef({ query, filter, selected });
8656
- latest.current = { query, filter, selected };
8657
- React65.useLayoutEffect(() => {
8658
- if (!isOpen) return;
8659
- const { query: text, filter: filtered, selected: picked } = latest.current;
8660
- const first = registry.view(text, filtered).navigable.find((id) => picked.includes(id));
8661
- highlight.set(first);
8662
- if (first !== void 0) revealHighlighted(registry.nodeOf(first));
8663
- return () => highlight.set(void 0);
8664
- }, [isOpen, registry, highlight]);
8665
- const latestView = React65.useRef(view);
8666
- latestView.current = view;
8667
- React65.useLayoutEffect(() => {
8668
- if (query !== "") highlight.set(latestView.current.navigable[0]);
8669
- }, [query, highlight]);
8670
- React65.useLayoutEffect(() => {
8671
- if (query === "") return;
8672
- const current = highlight.get();
8673
- if (current === void 0 || isActionValue(current) || !view.navigable.includes(current)) {
8674
- highlight.set(view.navigable[0]);
8564
+ function SwatchGrid({
8565
+ hues,
8566
+ presets,
8567
+ palette,
8568
+ value: valueProp,
8569
+ defaultValue,
8570
+ onValueChange,
8571
+ size: sizeProp,
8572
+ disabled: disabledProp = false,
8573
+ invalid,
8574
+ allowEmpty = false,
8575
+ name,
8576
+ id,
8577
+ className,
8578
+ label,
8579
+ required,
8580
+ optional,
8581
+ hint,
8582
+ hintTone,
8583
+ error,
8584
+ "aria-label": ariaLabel,
8585
+ "aria-labelledby": ariaLabelledBy,
8586
+ "aria-describedby": ariaDescribedBy,
8587
+ labels: labelsProp,
8588
+ ...rest
8589
+ }) {
8590
+ const size = useControlSize(sizeProp);
8591
+ const disabled = useInheritedDisabled(disabledProp);
8592
+ const frameSize = useControlSize(void 0);
8593
+ const merged = useLabels(COLOR_SWATCHES_LABELS, labelsProp);
8594
+ const labels = React65.useMemo(
8595
+ () => ({
8596
+ ...merged,
8597
+ colorNames: { ...COLOR_SWATCHES_LABELS.colorNames, ...labelsProp?.colorNames }
8598
+ }),
8599
+ [merged, labelsProp?.colorNames]
8600
+ );
8601
+ const [value, setValue] = useControllableState({
8602
+ value: valueProp,
8603
+ defaultValue,
8604
+ onChange: onValueChange
8605
+ });
8606
+ const ids = useFieldFrame(id, { label, hint, error, invalid }, ariaDescribedBy);
8607
+ const colorOptions = useSwatchOptions(presets, allowEmpty, labels.empty);
8608
+ const hueOptions = usePaletteOptions(palette, allowEmpty, labels.empty, labels.colorNames);
8609
+ const options = hues ? hueOptions : colorOptions;
8610
+ const selectedIndex = options.findIndex((option) => sameColor(option.value, value));
8611
+ const focusIndex = Math.max(0, selectedIndex);
8612
+ const grid = useSwatchGrid(options.length);
8613
+ const gridRef = React65.useRef(null);
8614
+ const columns = useBalancedColumns(gridRef, options.length, "[role='radio']");
8615
+ const labelledBy = ariaLabelledBy ?? ids.labelledBy;
8616
+ const onKeyDown2 = (event) => {
8617
+ const next = grid.move(event, focusIndex);
8618
+ if (next !== null) setValue(options[next]?.value ?? null);
8619
+ };
8620
+ return /* @__PURE__ */ jsx42(
8621
+ FieldFrame,
8622
+ {
8623
+ ...rest,
8624
+ size: frameSize,
8625
+ ids,
8626
+ label,
8627
+ required,
8628
+ optional,
8629
+ hint,
8630
+ hintTone,
8631
+ error,
8632
+ disabled,
8633
+ optionalLabel: labels.optional,
8634
+ group: true,
8635
+ className,
8636
+ children: /* @__PURE__ */ jsxs27(
8637
+ "div",
8638
+ {
8639
+ ref: gridRef,
8640
+ id: ids.controlId,
8641
+ role: "radiogroup",
8642
+ "aria-label": labelledBy ? void 0 : ariaLabel ?? labels.group,
8643
+ "aria-labelledby": labelledBy,
8644
+ "aria-describedby": ids.describedBy,
8645
+ "aria-required": required || void 0,
8646
+ "aria-invalid": ids.invalid || void 0,
8647
+ className: cx(swatchTierClass, swatchGridClass, ColorSwatches_default.grid),
8648
+ "data-base": "control",
8649
+ "data-stretch": "true",
8650
+ style: {
8651
+ "--swatch-count": options.length,
8652
+ "--swatch-columns": columns
8653
+ },
8654
+ ...toDataAttributes({
8655
+ size,
8656
+ invalid: ids.invalid || void 0,
8657
+ disabled: disabled || void 0
8658
+ }),
8659
+ onKeyDown: disabled ? void 0 : onKeyDown2,
8660
+ children: [
8661
+ options.map((option, index) => {
8662
+ const selected = index === selectedIndex;
8663
+ return (
8664
+ // biome-ignore lint/a11y/useSemanticElements: a swatch is a styled button in a roving radiogroup; a native radio cannot carry the color fill and check mark
8665
+ /* @__PURE__ */ jsx42(
8666
+ "button",
8667
+ {
8668
+ ref: grid.itemRef(index),
8669
+ type: "button",
8670
+ role: "radio",
8671
+ "aria-checked": selected,
8672
+ "aria-label": option.label,
8673
+ title: option.label,
8674
+ tabIndex: index === focusIndex ? 0 : -1,
8675
+ disabled,
8676
+ className: cx(swatchClass, hues && option.value && palette_default.hue),
8677
+ ...toDataAttributes({
8678
+ state: selected ? "checked" : "unchecked",
8679
+ contrast: option.contrast,
8680
+ color: hues ? option.value ?? void 0 : void 0
8681
+ }),
8682
+ onClick: () => setValue(option.value),
8683
+ children: /* @__PURE__ */ jsx42(SwatchContent, { value: option.value, selected, hue: hues })
8684
+ },
8685
+ option.value ?? "empty"
8686
+ )
8687
+ );
8688
+ }),
8689
+ name ? /* @__PURE__ */ jsx42("input", { type: "hidden", name, value: value ?? "" }) : null
8690
+ ]
8691
+ }
8692
+ )
8675
8693
  }
8676
- }, [view, query, highlight]);
8677
- return null;
8678
- }
8679
- function SelectGroup({ className, ...rest }) {
8680
- return /* @__PURE__ */ jsx42(MenuGroup, { ...rest, className: cx(Select_default.group, className) });
8681
- }
8682
- SelectGroup.displayName = "Select.Group";
8683
- function SelectSeparator({ className, ...rest }) {
8684
- return /* @__PURE__ */ jsx42(Divider, { ...rest, className: cx(menu_default.separator, Select_default.separator, className) });
8694
+ );
8685
8695
  }
8686
- SelectSeparator.displayName = "Select.Separator";
8687
- var Select = {
8688
- Root: SelectRoot,
8689
- Trigger: SelectTrigger,
8690
- Value: SelectValue,
8691
- TriggerIcon: SelectTriggerIcon,
8692
- Content: SelectContent,
8693
- Item: SelectItem,
8694
- ItemIcon: SelectItemIcon,
8695
- ItemText: SelectItemText,
8696
- ItemDescription: SelectItemDescription,
8697
- ItemMeta: SelectItemMeta,
8698
- Group: SelectGroup,
8699
- Separator: SelectSeparator,
8700
- Action: SelectAction
8701
- };
8702
8696
 
8703
8697
  export {
8704
8698
  AnchorRectProvider,
@@ -8841,9 +8835,10 @@ export {
8841
8835
  Thumbnail,
8842
8836
  RegionSwap,
8843
8837
  useSwapIn,
8844
- Popover,
8845
8838
  tooltipSurface_default,
8846
8839
  Tooltip,
8840
+ nodeText,
8841
+ Popover,
8847
8842
  FieldActionButton,
8848
8843
  FieldCopyButton,
8849
8844
  setControlValue,
@@ -8872,7 +8867,8 @@ export {
8872
8867
  getPasswordStrength,
8873
8868
  Input,
8874
8869
  EmptyPage,
8875
- nodeText,
8870
+ useLoadMore,
8871
+ Select,
8876
8872
  COLOR_PRESETS,
8877
8873
  useSwatchOptions,
8878
8874
  swatchClass,
@@ -8887,7 +8883,5 @@ export {
8887
8883
  sameColor,
8888
8884
  useBalancedColumns,
8889
8885
  useSwatchGrid,
8890
- ColorSwatches,
8891
- useLoadMore,
8892
- Select
8886
+ ColorSwatches
8893
8887
  };