prime-ui-kit 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +1 -1
  2. package/dist/chunks/{chunk-OAXJWF3L.js → chunk-3PY52JP3.js} +1764 -1764
  3. package/dist/chunks/{chunk-X3JT5CLR.js → chunk-4KONMO7Z.js} +1 -1
  4. package/dist/chunks/{chunk-MB4CXSLL.js → chunk-W6EGTNG6.js} +3772 -2888
  5. package/dist/color-picker.js +2 -2
  6. package/dist/components/data-table/ColumnsMenu.d.ts +39 -17
  7. package/dist/components/data-table/DataTable.d.ts +41 -12
  8. package/dist/components/data-table/DataTableColumnsMenu.d.ts +45 -0
  9. package/dist/components/data-table/Head.d.ts +18 -5
  10. package/dist/components/data-table/Row.d.ts +10 -4
  11. package/dist/components/data-table/StateRows.d.ts +5 -3
  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 +37 -15
  22. package/dist/components/gantt/Gantt.d.ts +1 -1
  23. package/dist/components/index.d.ts +3 -1
  24. package/dist/components/kanban/Kanban.d.ts +4 -0
  25. package/dist/components/list/List.d.ts +9 -4
  26. package/dist/components/scroll-container/ScrollContainer.d.ts +1 -1
  27. package/dist/index.css +1 -1
  28. package/dist/index.js +4 -2
  29. package/dist/internal/ToolRow.d.ts +23 -0
  30. package/dist/internal/leaveGuard.d.ts +6 -0
  31. package/dist/internal/overlay/DialogGuard.d.ts +3 -2
  32. package/dist/internal/overlay/DialogParts.d.ts +14 -5
  33. package/dist/layout/index.d.ts +1 -1
  34. package/dist/layout/page/Page.d.ts +8 -14
  35. package/dist/skill/anti-slop.md +55 -1
  36. package/dist/skill/api-contract.md +2 -2
  37. package/dist/skill/cheatsheet.md +12 -4
  38. package/dist/skill/checklist.md +7 -0
  39. package/dist/skill/choosing.md +1 -0
  40. package/dist/skill/components.md +1 -1
  41. package/dist/skill/composition.md +196 -21
  42. package/dist/skill/layouts.md +1 -1
  43. package/dist/skill/reference/components/confirm-dialog/COMPONENT.md +1 -1
  44. package/dist/skill/reference/components/data-table/COMPONENT.md +110 -49
  45. package/dist/skill/reference/components/data-table/examples/actions-column.tsx +154 -0
  46. package/dist/skill/reference/components/data-table/examples/column-order.tsx +152 -0
  47. package/dist/skill/reference/components/data-table/examples/columns-visibility.tsx +18 -18
  48. package/dist/skill/reference/components/data-table/examples/controlled.tsx +32 -17
  49. package/dist/skill/reference/components/data-table/examples/examples.module.css +14 -36
  50. package/dist/skill/reference/components/data-table/examples/narrow.tsx +25 -19
  51. package/dist/skill/reference/components/data-table/examples/reorder.tsx +24 -2
  52. package/dist/skill/reference/components/data-table/examples/row-link.tsx +18 -22
  53. package/dist/skill/reference/components/data-table/examples/screen.tsx +12 -1
  54. package/dist/skill/reference/components/data-table/examples/selection.tsx +13 -18
  55. package/dist/skill/reference/components/data-table/examples/server.tsx +45 -31
  56. package/dist/skill/reference/components/data-table/examples/toolbar.tsx +22 -35
  57. package/dist/skill/reference/components/datepicker/COMPONENT.md +2 -2
  58. package/dist/skill/reference/components/dnd/COMPONENT.md +13 -7
  59. package/dist/skill/reference/components/dnd/examples/examples.module.css +4 -3
  60. package/dist/skill/reference/components/dnd/examples/handle.tsx +5 -5
  61. package/dist/skill/reference/components/dnd/examples/locked.tsx +1 -1
  62. package/dist/skill/reference/components/dnd/examples/table-columns.tsx +75 -0
  63. package/dist/skill/reference/components/dnd/examples/table.tsx +6 -6
  64. package/dist/skill/reference/components/drawer/COMPONENT.md +26 -10
  65. package/dist/skill/reference/components/drawer/examples/header-actions.tsx +1 -1
  66. package/dist/skill/reference/components/drawer/examples/loading.tsx +58 -0
  67. package/dist/skill/reference/components/field-list/COMPONENT.md +78 -47
  68. package/dist/skill/reference/components/field-list/examples/base-row.tsx +2 -1
  69. package/dist/skill/reference/components/field-list/examples/locked.tsx +11 -11
  70. package/dist/skill/reference/components/field-list/examples/narrow.tsx +108 -33
  71. package/dist/skill/reference/components/field-list/examples/reorder.tsx +1 -1
  72. package/dist/skill/reference/components/field-list/examples/row-menu.tsx +71 -0
  73. package/dist/skill/reference/components/field-list/examples/screen.module.css +1 -1
  74. package/dist/skill/reference/components/field-list/examples/screen.tsx +169 -162
  75. package/dist/skill/reference/components/field-list/examples/totals.tsx +9 -8
  76. package/dist/skill/reference/components/field-list/examples/variants.tsx +51 -0
  77. package/dist/skill/reference/components/gantt/COMPONENT.md +4 -4
  78. package/dist/skill/reference/components/kanban/COMPONENT.md +6 -2
  79. package/dist/skill/reference/components/kanban/examples/states.tsx +7 -5
  80. package/dist/skill/reference/components/list/COMPONENT.md +21 -11
  81. package/dist/skill/reference/components/list/examples/reorder.tsx +42 -7
  82. package/dist/skill/reference/components/modal/COMPONENT.md +23 -10
  83. package/dist/skill/reference/components/scroll-container/COMPONENT.md +1 -1
  84. package/dist/skill/reference/components/segmented-control/COMPONENT.md +3 -2
  85. package/dist/skill/reference/components/sheet/COMPONENT.md +18 -7
  86. package/dist/skill/reference/components/smart-filter/COMPONENT.md +2 -2
  87. package/dist/skill/reference/layout/page/COMPONENT.md +13 -17
  88. package/dist/skill/reference/layout/page/examples/screen.module.css +1 -1
  89. package/dist/skill/reference/layout/page/examples/screen.tsx +93 -104
  90. package/dist/skill/reference/layout/page/examples/sections.tsx +2 -15
  91. package/dist/skill/responsive.md +14 -10
  92. package/dist/tokens/semantic.d.ts +2 -2
  93. package/dist/tokens/themes/dark.d.ts +1 -1
  94. package/package.json +1 -1
  95. package/src/components/confirm-dialog/COMPONENT.md +1 -1
  96. package/src/components/data-table/COMPONENT.md +110 -49
  97. package/src/components/data-table/examples/actions-column.tsx +154 -0
  98. package/src/components/data-table/examples/column-order.tsx +152 -0
  99. package/src/components/data-table/examples/columns-visibility.tsx +18 -18
  100. package/src/components/data-table/examples/controlled.tsx +32 -17
  101. package/src/components/data-table/examples/examples.module.css +14 -36
  102. package/src/components/data-table/examples/narrow.tsx +25 -19
  103. package/src/components/data-table/examples/reorder.tsx +24 -2
  104. package/src/components/data-table/examples/row-link.tsx +18 -22
  105. package/src/components/data-table/examples/screen.tsx +12 -1
  106. package/src/components/data-table/examples/selection.tsx +13 -18
  107. package/src/components/data-table/examples/server.tsx +45 -31
  108. package/src/components/data-table/examples/toolbar.tsx +22 -35
  109. package/src/components/datepicker/COMPONENT.md +2 -2
  110. package/src/components/dnd/COMPONENT.md +13 -7
  111. package/src/components/dnd/examples/examples.module.css +4 -3
  112. package/src/components/dnd/examples/handle.tsx +5 -5
  113. package/src/components/dnd/examples/locked.tsx +1 -1
  114. package/src/components/dnd/examples/table-columns.tsx +75 -0
  115. package/src/components/dnd/examples/table.tsx +6 -6
  116. package/src/components/drawer/COMPONENT.md +26 -10
  117. package/src/components/drawer/examples/header-actions.tsx +1 -1
  118. package/src/components/drawer/examples/loading.tsx +58 -0
  119. package/src/components/field-list/COMPONENT.md +78 -47
  120. package/src/components/field-list/examples/base-row.tsx +2 -1
  121. package/src/components/field-list/examples/locked.tsx +11 -11
  122. package/src/components/field-list/examples/narrow.tsx +108 -33
  123. package/src/components/field-list/examples/reorder.tsx +1 -1
  124. package/src/components/field-list/examples/row-menu.tsx +71 -0
  125. package/src/components/field-list/examples/screen.module.css +1 -1
  126. package/src/components/field-list/examples/screen.tsx +169 -162
  127. package/src/components/field-list/examples/totals.tsx +9 -8
  128. package/src/components/field-list/examples/variants.tsx +51 -0
  129. package/src/components/gantt/COMPONENT.md +4 -4
  130. package/src/components/kanban/COMPONENT.md +6 -2
  131. package/src/components/kanban/examples/states.tsx +7 -5
  132. package/src/components/list/COMPONENT.md +21 -11
  133. package/src/components/list/examples/reorder.tsx +42 -7
  134. package/src/components/modal/COMPONENT.md +23 -10
  135. package/src/components/scroll-container/COMPONENT.md +1 -1
  136. package/src/components/segmented-control/COMPONENT.md +3 -2
  137. package/src/components/sheet/COMPONENT.md +18 -7
  138. package/src/components/smart-filter/COMPONENT.md +2 -2
  139. package/src/layout/page/COMPONENT.md +13 -17
  140. package/src/layout/page/examples/screen.module.css +1 -1
  141. package/src/layout/page/examples/screen.tsx +93 -104
  142. package/src/layout/page/examples/sections.tsx +2 -15
  143. package/src/styles/theme-dark.css +1 -1
  144. package/src/styles/theme-light.css +1 -1
  145. package/dist/components/data-table/context.d.ts +0 -14
@@ -3333,6 +3333,39 @@ var Avatar = {
3333
3333
  Overflow: AvatarOverflow
3334
3334
  };
3335
3335
 
3336
+ // src/components/skeleton/Skeleton.module.css
3337
+ var Skeleton_default = {
3338
+ root: "Skeleton_root",
3339
+ primeSkeletonPulse: "Skeleton_primeSkeletonPulse",
3340
+ line: "Skeleton_line"
3341
+ };
3342
+
3343
+ // src/components/skeleton/Skeleton.tsx
3344
+ import { jsx as jsx17 } from "react/jsx-runtime";
3345
+ function Skeleton({
3346
+ shape = "text",
3347
+ size: sizeProp,
3348
+ lines = 1,
3349
+ className,
3350
+ ...rest
3351
+ }) {
3352
+ const size = useControlSize(sizeProp);
3353
+ const count = shape === "text" ? Math.max(1, Math.floor(lines)) : 0;
3354
+ return /* @__PURE__ */ jsx17(
3355
+ "span",
3356
+ {
3357
+ "aria-hidden": "true",
3358
+ ...rest,
3359
+ className: cx(fieldTierClass, Skeleton_default.root, className),
3360
+ ...toDataAttributes({ shape, size }),
3361
+ children: Array.from({ length: count }, (_, index) => (
3362
+ // biome-ignore lint/suspicious/noArrayIndexKey: identical placeholder lines
3363
+ /* @__PURE__ */ jsx17("span", { className: Skeleton_default.line }, index)
3364
+ ))
3365
+ }
3366
+ );
3367
+ }
3368
+
3336
3369
  // src/components/label/Label.module.css
3337
3370
  var Label_default = {
3338
3371
  root: "Label_root",
@@ -3343,7 +3376,7 @@ var Label_default = {
3343
3376
  };
3344
3377
 
3345
3378
  // src/components/label/Label.tsx
3346
- import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
3379
+ import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
3347
3380
  var LABEL_LABELS = { optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E" };
3348
3381
  function LabelRoot({
3349
3382
  className,
@@ -3362,7 +3395,7 @@ function LabelRoot({
3362
3395
  const labels = useLabels(LABEL_LABELS, labelsProp);
3363
3396
  return (
3364
3397
  // biome-ignore lint/a11y/noLabelWithoutControl: field label primitive; association via htmlFor or wrapping control is caller responsibility
3365
- /* @__PURE__ */ jsx17(
3398
+ /* @__PURE__ */ jsx18(
3366
3399
  "label",
3367
3400
  {
3368
3401
  ref,
@@ -3377,7 +3410,7 @@ function LabelRoot({
3377
3410
  children: tier.provide(
3378
3411
  /* @__PURE__ */ jsxs8(Fragment5, { children: [
3379
3412
  children,
3380
- /* @__PURE__ */ jsx17(LabelMarks, { required, optional, optionalLabel: labels.optional })
3413
+ /* @__PURE__ */ jsx18(LabelMarks, { required, optional, optionalLabel: labels.optional })
3381
3414
  ] })
3382
3415
  )
3383
3416
  }
@@ -3393,16 +3426,16 @@ function LabelMarks({
3393
3426
  }) {
3394
3427
  const dim = disabled || void 0;
3395
3428
  return /* @__PURE__ */ jsxs8(Fragment5, { children: [
3396
- required ? /* @__PURE__ */ jsx17("span", { className: Label_default.asterisk, "aria-hidden": "true", "data-disabled": dim, children: "*" }) : null,
3397
- optional ? /* @__PURE__ */ jsx17("span", { className: Label_default.optional, "data-disabled": dim, children: optionalLabel }) : null
3429
+ required ? /* @__PURE__ */ jsx18("span", { className: Label_default.asterisk, "aria-hidden": "true", "data-disabled": dim, children: "*" }) : null,
3430
+ optional ? /* @__PURE__ */ jsx18("span", { className: Label_default.optional, "data-disabled": dim, children: optionalLabel }) : null
3398
3431
  ] });
3399
3432
  }
3400
3433
  function LabelIcon({ className, ...rest }) {
3401
- return /* @__PURE__ */ jsx17("span", { className: cx(Label_default.icon, className), "aria-hidden": "true", ...rest });
3434
+ return /* @__PURE__ */ jsx18("span", { className: cx(Label_default.icon, className), "aria-hidden": "true", ...rest });
3402
3435
  }
3403
3436
  LabelIcon.displayName = "Label.Icon";
3404
3437
  function LabelDescription({ className, ...rest }) {
3405
- return /* @__PURE__ */ jsx17("span", { className: cx(Label_default.description, className), ...rest });
3438
+ return /* @__PURE__ */ jsx18("span", { className: cx(Label_default.description, className), ...rest });
3406
3439
  }
3407
3440
  LabelDescription.displayName = "Label.Description";
3408
3441
  var Label = {
@@ -3418,7 +3451,7 @@ var Hint_default = {
3418
3451
  };
3419
3452
 
3420
3453
  // src/components/hint/Hint.tsx
3421
- import { jsx as jsx18 } from "react/jsx-runtime";
3454
+ import { jsx as jsx19 } from "react/jsx-runtime";
3422
3455
  function HintRoot({
3423
3456
  className,
3424
3457
  size: sizeProp,
@@ -3432,7 +3465,7 @@ function HintRoot({
3432
3465
  const disabled = useInheritedDisabled(disabledProp);
3433
3466
  const shownTone = tone === "neutral" || invalid || disabled ? void 0 : tone;
3434
3467
  return tier.provide(
3435
- /* @__PURE__ */ jsx18(
3468
+ /* @__PURE__ */ jsx19(
3436
3469
  "p",
3437
3470
  {
3438
3471
  ...rest,
@@ -3458,7 +3491,7 @@ function HintRoot({
3458
3491
  }
3459
3492
  HintRoot.displayName = "Hint.Root";
3460
3493
  function HintIcon({ className, ...rest }) {
3461
- return /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", className: cx(Hint_default.icon, className), ...rest });
3494
+ return /* @__PURE__ */ jsx19("span", { "aria-hidden": "true", className: cx(Hint_default.icon, className), ...rest });
3462
3495
  }
3463
3496
  HintIcon.displayName = "Hint.Icon";
3464
3497
  var Hint = { Root: HintRoot, Icon: HintIcon };
@@ -3474,7 +3507,7 @@ var CheckMark_default = {
3474
3507
  };
3475
3508
 
3476
3509
  // src/internal/CheckMark.tsx
3477
- import { jsx as jsx19, jsxs as jsxs9 } from "react/jsx-runtime";
3510
+ import { jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
3478
3511
  function CheckMark({ state, className }) {
3479
3512
  return /* @__PURE__ */ jsxs9(
3480
3513
  "svg",
@@ -3485,8 +3518,8 @@ function CheckMark({ state, className }) {
3485
3518
  "aria-hidden": "true",
3486
3519
  focusable: "false",
3487
3520
  children: [
3488
- /* @__PURE__ */ jsx19("path", { d: "M5.5 12.5l4.25 4.25L18.5 8", pathLength: 1, className: CheckMark_default.check }),
3489
- /* @__PURE__ */ jsx19("path", { d: "M7 12h10", pathLength: 1, className: CheckMark_default.bar })
3521
+ /* @__PURE__ */ jsx20("path", { d: "M5.5 12.5l4.25 4.25L18.5 8", pathLength: 1, className: CheckMark_default.check }),
3522
+ /* @__PURE__ */ jsx20("path", { d: "M7 12h10", pathLength: 1, className: CheckMark_default.bar })
3490
3523
  ]
3491
3524
  }
3492
3525
  );
@@ -3528,7 +3561,7 @@ var FieldFrame_default = {
3528
3561
  };
3529
3562
 
3530
3563
  // src/internal/FieldFrame.tsx
3531
- import { jsx as jsx20, jsxs as jsxs10 } from "react/jsx-runtime";
3564
+ import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
3532
3565
  var REQUIRED_ROLES = /* @__PURE__ */ new Set([
3533
3566
  "checkbox",
3534
3567
  "combobox",
@@ -3617,9 +3650,9 @@ function FieldSupport({
3617
3650
  }) {
3618
3651
  let text = null;
3619
3652
  if (ids.showError) {
3620
- text = /* @__PURE__ */ jsx20(Hint.Root, { id: ids.errorId, size, invalid: true, className: textClassName, children: error });
3653
+ text = /* @__PURE__ */ jsx21(Hint.Root, { id: ids.errorId, size, invalid: true, className: textClassName, children: error });
3621
3654
  } else if (leaving) {
3622
- text = /* @__PURE__ */ jsx20(
3655
+ text = /* @__PURE__ */ jsx21(
3623
3656
  Hint.Root,
3624
3657
  {
3625
3658
  size,
@@ -3631,7 +3664,7 @@ function FieldSupport({
3631
3664
  }
3632
3665
  );
3633
3666
  } else if (ids.showHint) {
3634
- text = /* @__PURE__ */ jsx20(
3667
+ text = /* @__PURE__ */ jsx21(
3635
3668
  Hint.Root,
3636
3669
  {
3637
3670
  id: ids.hintId,
@@ -3643,7 +3676,7 @@ function FieldSupport({
3643
3676
  }
3644
3677
  );
3645
3678
  }
3646
- return /* @__PURE__ */ jsx20("div", { className, "aria-live": live ? "polite" : void 0, children: text });
3679
+ return /* @__PURE__ */ jsx21("div", { className, "aria-live": live ? "polite" : void 0, children: text });
3647
3680
  }
3648
3681
  function FieldFrame({
3649
3682
  size,
@@ -3670,7 +3703,7 @@ function FieldFrame({
3670
3703
  const shake = useErrorShake(ids.invalid, error);
3671
3704
  const cell = useFieldCell();
3672
3705
  const shownLabel = hasContent(label) ? label : cell?.label;
3673
- const labelNode = hasContent(shownLabel) ? /* @__PURE__ */ jsx20(
3706
+ const labelNode = hasContent(shownLabel) ? /* @__PURE__ */ jsx21(
3674
3707
  Label.Root,
3675
3708
  {
3676
3709
  id: ids.labelId,
@@ -3702,7 +3735,7 @@ function FieldFrame({
3702
3735
  children: [
3703
3736
  labelEnd != null ? /* @__PURE__ */ jsxs10("div", { className: FieldFrame_default.labelRow, children: [
3704
3737
  labelNode,
3705
- /* @__PURE__ */ jsx20("span", { className: FieldFrame_default.labelEnd, children: labelEnd })
3738
+ /* @__PURE__ */ jsx21("span", { className: FieldFrame_default.labelEnd, children: labelEnd })
3706
3739
  ] }) : labelNode,
3707
3740
  /* @__PURE__ */ jsxs10("div", { className: cx(FieldFrame_default.body, enterMotion_default.shakeParts), "data-shake": shake, children: [
3708
3741
  children,
@@ -3717,7 +3750,7 @@ function FieldFrame({
3717
3750
  empty: !showSupport || void 0
3718
3751
  }),
3719
3752
  children: [
3720
- /* @__PURE__ */ jsx20(
3753
+ /* @__PURE__ */ jsx21(
3721
3754
  FieldSupport,
3722
3755
  {
3723
3756
  ids,
@@ -3736,7 +3769,7 @@ function FieldFrame({
3736
3769
  }
3737
3770
  )
3738
3771
  ] }),
3739
- requiredLabel && ids.required ? /* @__PURE__ */ jsx20(VisuallyHidden, { id: ids.requiredId, children: requiredLabel }) : null
3772
+ requiredLabel && ids.required ? /* @__PURE__ */ jsx21(VisuallyHidden, { id: ids.requiredId, children: requiredLabel }) : null
3740
3773
  ]
3741
3774
  }
3742
3775
  );
@@ -3751,11 +3784,11 @@ function FieldCounter({ current, max, size, label, className, ...rest }) {
3751
3784
  "data-invalid": current > max || void 0,
3752
3785
  children: [
3753
3786
  /* @__PURE__ */ jsxs10("span", { "aria-hidden": "true", children: [
3754
- /* @__PURE__ */ jsx20(RollingNumber, { children: current }),
3787
+ /* @__PURE__ */ jsx21(RollingNumber, { children: current }),
3755
3788
  "/",
3756
3789
  max
3757
3790
  ] }),
3758
- /* @__PURE__ */ jsx20(VisuallyHidden, { live: "polite", children: formatLabel(label, { current, max }) })
3791
+ /* @__PURE__ */ jsx21(VisuallyHidden, { live: "polite", children: formatLabel(label, { current, max }) })
3759
3792
  ]
3760
3793
  }
3761
3794
  );
@@ -3775,7 +3808,7 @@ var ChoiceField_default = {
3775
3808
  };
3776
3809
 
3777
3810
  // src/internal/ChoiceField.tsx
3778
- import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
3811
+ import { Fragment as Fragment6, jsx as jsx22, jsxs as jsxs11 } from "react/jsx-runtime";
3779
3812
  var choiceInputClass = ChoiceField_default.input;
3780
3813
  var choiceVisualClass = cx(ChoiceField_default.visual, press_default.pressPartCompact);
3781
3814
  var choiceBoxClass = ChoiceField_default.box;
@@ -3805,7 +3838,7 @@ function ChoiceField({
3805
3838
  () => ({ required, optional, optionalLabel, disabled }),
3806
3839
  [required, optional, optionalLabel, disabled]
3807
3840
  );
3808
- return /* @__PURE__ */ jsx21(ControlSizeProvider, { value: size, children: /* @__PURE__ */ jsxs11(
3841
+ return /* @__PURE__ */ jsx22(ControlSizeProvider, { value: size, children: /* @__PURE__ */ jsxs11(
3809
3842
  "div",
3810
3843
  {
3811
3844
  className: cx(fieldTierClass, ChoiceField_default.field, className),
@@ -3824,7 +3857,7 @@ function ChoiceField({
3824
3857
  className: cx(ChoiceField_default.row, press_default.pressHost),
3825
3858
  "data-loading": busy || void 0,
3826
3859
  children: [
3827
- /* @__PURE__ */ jsx21(
3860
+ /* @__PURE__ */ jsx22(
3828
3861
  "span",
3829
3862
  {
3830
3863
  className: cx(ChoiceField_default.controlCell, enterMotion_default.shake, touchTargetClass),
@@ -3832,11 +3865,11 @@ function ChoiceField({
3832
3865
  children: control
3833
3866
  }
3834
3867
  ),
3835
- /* @__PURE__ */ jsx21(ChoiceMarksContext, { value: marks, children })
3868
+ /* @__PURE__ */ jsx22(ChoiceMarksContext, { value: marks, children })
3836
3869
  ]
3837
3870
  }
3838
3871
  ),
3839
- /* @__PURE__ */ jsx21(
3872
+ /* @__PURE__ */ jsx22(
3840
3873
  FieldSupport,
3841
3874
  {
3842
3875
  ids,
@@ -3861,7 +3894,7 @@ function ChoiceLabel({ className, children, ...rest }) {
3861
3894
  children,
3862
3895
  marked ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
3863
3896
  " ",
3864
- /* @__PURE__ */ jsx21(
3897
+ /* @__PURE__ */ jsx22(
3865
3898
  LabelMarks,
3866
3899
  {
3867
3900
  required: marks.required,
@@ -3882,7 +3915,7 @@ var Checkbox_default = {
3882
3915
  };
3883
3916
 
3884
3917
  // src/components/checkbox/Checkbox.tsx
3885
- import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
3918
+ import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
3886
3919
  var CHECKBOX_LABELS = { optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E" };
3887
3920
  function CheckboxRoot({
3888
3921
  id,
@@ -3920,7 +3953,7 @@ function CheckboxRoot({
3920
3953
  React33.useLayoutEffect(() => {
3921
3954
  if (internalRef.current) internalRef.current.indeterminate = indeterminate;
3922
3955
  });
3923
- return /* @__PURE__ */ jsx22(
3956
+ return /* @__PURE__ */ jsx23(
3924
3957
  ChoiceField,
3925
3958
  {
3926
3959
  ids,
@@ -3936,7 +3969,7 @@ function CheckboxRoot({
3936
3969
  error,
3937
3970
  className: cx(Checkbox_default.root, className),
3938
3971
  control: /* @__PURE__ */ jsxs12(Fragment7, { children: [
3939
- /* @__PURE__ */ jsx22(
3972
+ /* @__PURE__ */ jsx23(
3940
3973
  "input",
3941
3974
  {
3942
3975
  ...inputRest,
@@ -3955,13 +3988,13 @@ function CheckboxRoot({
3955
3988
  "aria-describedby": ids.describedBy
3956
3989
  }
3957
3990
  ),
3958
- /* @__PURE__ */ jsx22(
3991
+ /* @__PURE__ */ jsx23(
3959
3992
  "span",
3960
3993
  {
3961
3994
  className: cx(choiceVisualClass, choiceBoxClass, Checkbox_default.control),
3962
3995
  "data-shape": shape,
3963
3996
  "aria-hidden": "true",
3964
- children: /* @__PURE__ */ jsx22(
3997
+ children: /* @__PURE__ */ jsx23(
3965
3998
  CheckMark,
3966
3999
  {
3967
4000
  state: indeterminate ? "indeterminate" : checked ? "checked" : "unchecked"
@@ -3976,7 +4009,7 @@ function CheckboxRoot({
3976
4009
  }
3977
4010
  CheckboxRoot.displayName = "Checkbox.Root";
3978
4011
  function CheckboxLabel(props) {
3979
- return /* @__PURE__ */ jsx22(ChoiceLabel, { ...props });
4012
+ return /* @__PURE__ */ jsx23(ChoiceLabel, { ...props });
3980
4013
  }
3981
4014
  CheckboxLabel.displayName = "Checkbox.Label";
3982
4015
  function CheckboxIndicator({
@@ -3989,7 +4022,7 @@ function CheckboxIndicator({
3989
4022
  ...rest
3990
4023
  }) {
3991
4024
  const size = useControlSize(sizeProp);
3992
- return /* @__PURE__ */ jsx22(
4025
+ return /* @__PURE__ */ jsx23(
3993
4026
  "span",
3994
4027
  {
3995
4028
  "aria-hidden": "true",
@@ -4008,7 +4041,7 @@ function CheckboxIndicator({
4008
4041
  disabled: disabled || void 0
4009
4042
  }),
4010
4043
  ...rest,
4011
- children: /* @__PURE__ */ jsx22(CheckMark, { state: indeterminate ? "indeterminate" : checked ? "checked" : "unchecked" })
4044
+ children: /* @__PURE__ */ jsx23(CheckMark, { state: indeterminate ? "indeterminate" : checked ? "checked" : "unchecked" })
4012
4045
  }
4013
4046
  );
4014
4047
  }
@@ -4092,20 +4125,20 @@ var mediaDisk_default = {
4092
4125
  };
4093
4126
 
4094
4127
  // src/internal/mediaDisk.tsx
4095
- import { jsx as jsx23 } from "react/jsx-runtime";
4128
+ import { jsx as jsx24 } from "react/jsx-runtime";
4096
4129
  var mediaDiskClass = cx(fieldTierClass, mediaPill_default.ink, mediaDisk_default.disk);
4097
4130
  function MediaPlayMark({
4098
4131
  shown = true,
4099
4132
  className
4100
4133
  }) {
4101
- return /* @__PURE__ */ jsx23(
4134
+ return /* @__PURE__ */ jsx24(
4102
4135
  "span",
4103
4136
  {
4104
4137
  className: cx(mediaDiskClass, className),
4105
4138
  "data-size": "l",
4106
4139
  "data-shown": shown,
4107
4140
  "aria-hidden": "true",
4108
- children: /* @__PURE__ */ jsx23(Icon, { name: "action.play", fill: "currentColor" })
4141
+ children: /* @__PURE__ */ jsx24(Icon, { name: "action.play", fill: "currentColor" })
4109
4142
  }
4110
4143
  );
4111
4144
  }
@@ -4165,7 +4198,7 @@ var Thumbnail_default = {
4165
4198
  };
4166
4199
 
4167
4200
  // src/components/thumbnail/Thumbnail.tsx
4168
- import { Fragment as Fragment8, jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
4201
+ import { Fragment as Fragment8, jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
4169
4202
  var slot2 = createImageSlot("Thumbnail", { image: Thumbnail_default.image, fallback: Thumbnail_default.fallback });
4170
4203
  function ThumbnailRoot({
4171
4204
  size: sizeProp,
@@ -4207,7 +4240,7 @@ function ThumbnailRoot({
4207
4240
  if (selectable) {
4208
4241
  const { onClick: onClick2 } = rest;
4209
4242
  return provide(
4210
- /* @__PURE__ */ jsx24(slot2.ImageSlotProvider, { children: /* @__PURE__ */ jsxs13(
4243
+ /* @__PURE__ */ jsx25(slot2.ImageSlotProvider, { children: /* @__PURE__ */ jsxs13(
4211
4244
  "button",
4212
4245
  {
4213
4246
  ...rest,
@@ -4222,7 +4255,7 @@ function ThumbnailRoot({
4222
4255
  },
4223
4256
  children: [
4224
4257
  children,
4225
- /* @__PURE__ */ jsx24("span", { className: cx(Thumbnail_default.check, mediaPill_default.choice), "aria-hidden": "true", children: /* @__PURE__ */ jsx24(Checkbox.Indicator, { checked, size: fullWidth ? "s" : compactTier(size) }) })
4258
+ /* @__PURE__ */ jsx25("span", { className: cx(Thumbnail_default.check, mediaPill_default.choice), "aria-hidden": "true", children: /* @__PURE__ */ jsx25(Checkbox.Indicator, { checked, size: fullWidth ? "s" : compactTier(size) }) })
4226
4259
  ]
4227
4260
  }
4228
4261
  ) })
@@ -4230,16 +4263,16 @@ function ThumbnailRoot({
4230
4263
  }
4231
4264
  if (asChild) {
4232
4265
  return provide(
4233
- /* @__PURE__ */ jsx24(slot2.ImageSlotProvider, { children: /* @__PURE__ */ jsx24(Slot, { ...rest, ...frame2, ref, children }) })
4266
+ /* @__PURE__ */ jsx25(slot2.ImageSlotProvider, { children: /* @__PURE__ */ jsx25(Slot, { ...rest, ...frame2, ref, children }) })
4234
4267
  );
4235
4268
  }
4236
4269
  return provide(
4237
- /* @__PURE__ */ jsx24(slot2.ImageSlotProvider, { children: /* @__PURE__ */ jsx24("div", { ref, ...frame2, ...rest, children }) })
4270
+ /* @__PURE__ */ jsx25(slot2.ImageSlotProvider, { children: /* @__PURE__ */ jsx25("div", { ref, ...frame2, ...rest, children }) })
4238
4271
  );
4239
4272
  }
4240
4273
  ThumbnailRoot.displayName = "Thumbnail.Root";
4241
4274
  function ThumbnailImage({ fit = "cover", ...rest }) {
4242
- return /* @__PURE__ */ jsx24(slot2.Image, { ...rest, "data-fit": fit });
4275
+ return /* @__PURE__ */ jsx25(slot2.Image, { ...rest, "data-fit": fit });
4243
4276
  }
4244
4277
  ThumbnailImage.displayName = "Thumbnail.Image";
4245
4278
  function ThumbnailVideoInner({
@@ -4274,7 +4307,7 @@ function ThumbnailVideoInner({
4274
4307
  const [still] = React35.useState(prefersReducedMotion);
4275
4308
  const loops = autoPlay && !still && !controls;
4276
4309
  return /* @__PURE__ */ jsxs13(Fragment8, { children: [
4277
- /* @__PURE__ */ jsx24(
4310
+ /* @__PURE__ */ jsx25(
4278
4311
  "video",
4279
4312
  {
4280
4313
  ...rest,
@@ -4309,12 +4342,12 @@ function ThumbnailVideoInner({
4309
4342
  }
4310
4343
  }
4311
4344
  ),
4312
- !controls && !loops ? /* @__PURE__ */ jsx24(MediaPlayMark, { shown: !playing, className: Thumbnail_default.play }) : null,
4313
- !controls && duration !== null ? /* @__PURE__ */ jsx24("span", { className: cx(textRole_default.caption, mediaPill_default.pill, Thumbnail_default.duration), children: formatDuration(duration) }) : null
4345
+ !controls && !loops ? /* @__PURE__ */ jsx25(MediaPlayMark, { shown: !playing, className: Thumbnail_default.play }) : null,
4346
+ !controls && duration !== null ? /* @__PURE__ */ jsx25("span", { className: cx(textRole_default.caption, mediaPill_default.pill, Thumbnail_default.duration), children: formatDuration(duration) }) : null
4314
4347
  ] });
4315
4348
  }
4316
4349
  function ThumbnailVideo(props) {
4317
- return /* @__PURE__ */ jsx24(ThumbnailVideoInner, { ...props }, props.src);
4350
+ return /* @__PURE__ */ jsx25(ThumbnailVideoInner, { ...props }, props.src);
4318
4351
  }
4319
4352
  ThumbnailVideo.displayName = "Thumbnail.Video";
4320
4353
  var ThumbnailFallback = slot2.Fallback;
@@ -4325,8 +4358,8 @@ var Thumbnail = {
4325
4358
  Fallback: ThumbnailFallback
4326
4359
  };
4327
4360
 
4328
- // src/components/popover/Popover.tsx
4329
- import * as React47 from "react";
4361
+ // src/components/tooltip/Tooltip.tsx
4362
+ import * as React45 from "react";
4330
4363
 
4331
4364
  // src/hooks/useSwipeDismiss.ts
4332
4365
  import * as React36 from "react";
@@ -4776,10 +4809,10 @@ function useLayer(open, options) {
4776
4809
  }
4777
4810
 
4778
4811
  // src/internal/overlay/FloatingPanel.tsx
4779
- import { Fragment as Fragment9, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
4812
+ import { Fragment as Fragment9, jsx as jsx26, jsxs as jsxs14 } from "react/jsx-runtime";
4780
4813
  function SheetHandle({ swipe }) {
4781
4814
  if (!swipe.enabled) return null;
4782
- return /* @__PURE__ */ jsx25("div", { className: sheet_default.handle, ...{ [SWIPE_HANDLE_ATTRIBUTE]: "" }, "aria-hidden": "true" });
4815
+ return /* @__PURE__ */ jsx26("div", { className: sheet_default.handle, ...{ [SWIPE_HANDLE_ATTRIBUTE]: "" }, "aria-hidden": "true" });
4783
4816
  }
4784
4817
  function FloatingPanel({
4785
4818
  floating,
@@ -4817,9 +4850,9 @@ function FloatingPanel({
4817
4850
  }
4818
4851
  };
4819
4852
  const panelRef = sheet ? ref : mergedRef;
4820
- const panel = scroll ? /* @__PURE__ */ jsx25(ScrollContainer, { ...props, edges: "shadow", ref: panelRef, children }) : /* @__PURE__ */ jsx25("div", { ...props, ref: panelRef, children });
4821
- return /* @__PURE__ */ jsx25(Portal, { children: /* @__PURE__ */ jsx25(LayerProvider, { value: floating.layer, children: /* @__PURE__ */ jsx25(SurfaceDepthProvider, { value: "floating", children: /* @__PURE__ */ jsx25(ControlSizeProvider, { value: size, children: sheet ? /* @__PURE__ */ jsxs14(Fragment9, { children: [
4822
- /* @__PURE__ */ jsx25(
4853
+ const panel = scroll ? /* @__PURE__ */ jsx26(ScrollContainer, { ...props, edges: "shadow", ref: panelRef, children }) : /* @__PURE__ */ jsx26("div", { ...props, ref: panelRef, children });
4854
+ return /* @__PURE__ */ jsx26(Portal, { children: /* @__PURE__ */ jsx26(LayerProvider, { value: floating.layer, children: /* @__PURE__ */ jsx26(SurfaceDepthProvider, { value: "floating", children: /* @__PURE__ */ jsx26(ControlSizeProvider, { value: size, children: sheet ? /* @__PURE__ */ jsxs14(Fragment9, { children: [
4855
+ /* @__PURE__ */ jsx26(
4823
4856
  "div",
4824
4857
  {
4825
4858
  role: "presentation",
@@ -4843,7 +4876,7 @@ function FloatingPanel({
4843
4876
  onPointerDown: swipe.onPointerDown,
4844
4877
  ...swipe.panelProps,
4845
4878
  children: [
4846
- /* @__PURE__ */ jsx25(SheetHandle, { swipe }),
4879
+ /* @__PURE__ */ jsx26(SheetHandle, { swipe }),
4847
4880
  panel
4848
4881
  ]
4849
4882
  }
@@ -4851,35 +4884,21 @@ function FloatingPanel({
4851
4884
  ] }) : panel }) }) }) });
4852
4885
  }
4853
4886
  function FloatingTrigger({ triggerProps, children, ...forwarded }) {
4854
- return /* @__PURE__ */ jsx25(Slot, { ...forwarded, children: /* @__PURE__ */ jsx25(Slot, { ...triggerProps, children }) });
4887
+ return /* @__PURE__ */ jsx26(Slot, { ...forwarded, children: /* @__PURE__ */ jsx26(Slot, { ...triggerProps, children }) });
4855
4888
  }
4856
4889
 
4857
- // src/internal/overlay/useAnchorName.ts
4858
- import * as React41 from "react";
4859
- var CONTROL = "button, a[href], input, select, textarea, [tabindex]";
4860
- function useAnchorName(open, named, anchorRef) {
4861
- const [name, setName] = React41.useState({});
4862
- React41.useLayoutEffect(() => {
4863
- if (!open || named) return;
4864
- const anchor = anchorRef.current;
4865
- if (!anchor) return;
4866
- const control = anchor.matches(CONTROL) ? anchor : getFocusable(anchor)[0] ?? anchor;
4867
- const next = control.id ? { id: control.id } : {
4868
- label: control.getAttribute("aria-label") ?? (control.textContent?.trim() || void 0)
4869
- };
4870
- setName((current) => current.id === next.id && current.label === next.label ? current : next);
4871
- }, [open, named, anchorRef]);
4872
- if (named) return {};
4873
- return name.id ? { "aria-labelledby": name.id } : { "aria-label": name.label };
4874
- }
4890
+ // src/internal/overlay/tooltipSurface.module.css
4891
+ var tooltipSurface_default = {
4892
+ chip: "tooltipSurface_chip"
4893
+ };
4875
4894
 
4876
4895
  // src/internal/overlay/useFloatingLayer.ts
4877
- import * as React45 from "react";
4896
+ import * as React44 from "react";
4878
4897
 
4879
4898
  // src/hooks/useMediaQuery.ts
4880
- import * as React42 from "react";
4899
+ import * as React41 from "react";
4881
4900
  function useMediaQuery(query, enabled = true) {
4882
- const subscribe = React42.useCallback(
4901
+ const subscribe = React41.useCallback(
4883
4902
  (onChange) => {
4884
4903
  if (!enabled || typeof window === "undefined" || !window.matchMedia) return () => {
4885
4904
  };
@@ -4890,11 +4909,11 @@ function useMediaQuery(query, enabled = true) {
4890
4909
  [enabled, query]
4891
4910
  );
4892
4911
  const getSnapshot = () => enabled && typeof window !== "undefined" && !!window.matchMedia ? window.matchMedia(query).matches : false;
4893
- return React42.useSyncExternalStore(subscribe, getSnapshot, () => false);
4912
+ return React41.useSyncExternalStore(subscribe, getSnapshot, () => false);
4894
4913
  }
4895
4914
 
4896
4915
  // src/hooks/useScrollLock.ts
4897
- import * as React43 from "react";
4916
+ import * as React42 from "react";
4898
4917
  var lockCount = 0;
4899
4918
  var saved = null;
4900
4919
  function lockScroll() {
@@ -4919,7 +4938,7 @@ function unlockScroll() {
4919
4938
  }
4920
4939
  }
4921
4940
  function useScrollLock(enabled) {
4922
- React43.useEffect(() => {
4941
+ React42.useEffect(() => {
4923
4942
  if (!enabled) return;
4924
4943
  lockScroll();
4925
4944
  return unlockScroll;
@@ -4927,7 +4946,7 @@ function useScrollLock(enabled) {
4927
4946
  }
4928
4947
 
4929
4948
  // src/internal/overlay/useContainScroll.ts
4930
- import * as React44 from "react";
4949
+ import * as React43 from "react";
4931
4950
  function canScroll(el, deltaY) {
4932
4951
  const { overflowY } = getComputedStyle(el);
4933
4952
  if (overflowY !== "auto" && overflowY !== "scroll") return false;
@@ -4935,7 +4954,7 @@ function canScroll(el, deltaY) {
4935
4954
  return deltaY < 0 ? el.scrollTop > 0 : el.scrollTop + el.clientHeight < el.scrollHeight;
4936
4955
  }
4937
4956
  function useContainScroll(panel) {
4938
- React44.useEffect(() => {
4957
+ React43.useEffect(() => {
4939
4958
  if (!panel) return;
4940
4959
  const onWheel = (event) => {
4941
4960
  for (let el = event.target; el; el = el.parentElement) {
@@ -4968,12 +4987,12 @@ function useFloatingLayer({
4968
4987
  const sheet = useMediaQuery(COMPACT_QUERY, sheetOption);
4969
4988
  const presence = usePresence(open, { exitDuration: sheet ? "base" : exitDuration });
4970
4989
  const mounted = presence.mounted && (open || !skipExit);
4971
- const contentRef = React45.useRef(null);
4990
+ const contentRef = React44.useRef(null);
4972
4991
  const position = usePosition(mounted && !sheet, triggerRef, contentRef, positionOptions);
4973
4992
  useScrollLock(open && sheet);
4974
- const [panel, setPanel] = React45.useState(null);
4993
+ const [panel, setPanel] = React44.useState(null);
4975
4994
  const { attachLayer } = position;
4976
- const panelRef = React45.useCallback(
4995
+ const panelRef = React44.useCallback(
4977
4996
  (node) => {
4978
4997
  attachLayer(node);
4979
4998
  setPanel(node);
@@ -4982,12 +5001,12 @@ function useFloatingLayer({
4982
5001
  );
4983
5002
  const passive = dismiss === "none";
4984
5003
  useContainScroll(open && !sheet && !passive ? panel : null);
4985
- const outsideRef = React45.useRef(false);
4986
- const close = React45.useCallback(() => {
5004
+ const outsideRef = React44.useRef(false);
5005
+ const close = React44.useCallback(() => {
4987
5006
  outsideRef.current = false;
4988
5007
  onOpenChange(false);
4989
5008
  }, [onOpenChange]);
4990
- const dismissOutside = React45.useCallback(() => {
5009
+ const dismissOutside = React44.useCallback(() => {
4991
5010
  outsideRef.current = true;
4992
5011
  onOpenChange(false);
4993
5012
  }, [onOpenChange]);
@@ -5008,7 +5027,7 @@ function useFloatingLayer({
5008
5027
  trap,
5009
5028
  onDismiss
5010
5029
  });
5011
- React45.useEffect(() => {
5030
+ React44.useEffect(() => {
5012
5031
  if (!open || !panel || passive) return;
5013
5032
  outsideRef.current = false;
5014
5033
  if (focusOnOpen) {
@@ -5069,361 +5088,147 @@ function floatingTriggerProps({
5069
5088
  };
5070
5089
  }
5071
5090
 
5072
- // src/internal/overlay/useOpenState.ts
5073
- import * as React46 from "react";
5074
- function useOpenState({
5091
+ // src/components/tooltip/Tooltip.module.css
5092
+ var Tooltip_default = {
5093
+ content: "Tooltip_content",
5094
+ arrow: "Tooltip_arrow",
5095
+ focusHost: "Tooltip_focusHost",
5096
+ disabledHost: "Tooltip_disabledHost"
5097
+ };
5098
+
5099
+ // src/components/tooltip/Tooltip.tsx
5100
+ import { jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
5101
+ var DEFAULT_DELAY_MS = 400;
5102
+ var DEFAULT_SKIP_DELAY_MS = 300;
5103
+ var CLOSE_GRACE_MS = 100;
5104
+ function createTooltipGroup(delayDuration, skipDelayDuration) {
5105
+ let current = null;
5106
+ let warmUntil = 0;
5107
+ return {
5108
+ delayDuration,
5109
+ isWarm: () => current !== null || Date.now() < warmUntil,
5110
+ opened: (close) => {
5111
+ if (current && current !== close) current();
5112
+ current = close;
5113
+ },
5114
+ closed: (close) => {
5115
+ if (current === close) current = null;
5116
+ warmUntil = Date.now() + skipDelayDuration;
5117
+ }
5118
+ };
5119
+ }
5120
+ var defaultGroup = createTooltipGroup(DEFAULT_DELAY_MS, DEFAULT_SKIP_DELAY_MS);
5121
+ var TooltipGroupContext = React45.createContext(defaultGroup);
5122
+ function TooltipProvider({
5123
+ delayDuration = DEFAULT_DELAY_MS,
5124
+ skipDelayDuration = DEFAULT_SKIP_DELAY_MS,
5125
+ children
5126
+ }) {
5127
+ const group = React45.useMemo(
5128
+ () => createTooltipGroup(delayDuration, skipDelayDuration),
5129
+ [delayDuration, skipDelayDuration]
5130
+ );
5131
+ return /* @__PURE__ */ jsx27(TooltipGroupContext.Provider, { value: group, children });
5132
+ }
5133
+ var [TooltipRootProvider, useTooltipRootContext] = createComponentContext("Tooltip");
5134
+ function TooltipRoot({
5135
+ children,
5075
5136
  open,
5076
- defaultOpen = false,
5137
+ defaultOpen,
5077
5138
  onOpenChange,
5078
- disabled = false
5139
+ delayDuration: delayProp
5079
5140
  }) {
5141
+ const group = React45.useContext(TooltipGroupContext);
5142
+ const delayDuration = delayProp ?? group.delayDuration;
5080
5143
  const [isOpen, setIsOpen] = useControllableState({
5081
5144
  value: open,
5082
- defaultValue: defaultOpen,
5145
+ defaultValue: defaultOpen ?? false,
5083
5146
  onChange: onOpenChange
5084
5147
  });
5085
- const disabledRef = React46.useRef(disabled);
5086
- disabledRef.current = disabled;
5087
- const setOpen = React46.useCallback(
5088
- (next) => {
5089
- setIsOpen((current) => {
5090
- const value = typeof next === "function" ? next(current && !disabledRef.current) : next;
5091
- return value && disabledRef.current ? current : value;
5092
- });
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(() => {
5154
+ });
5155
+ closeInstantlyRef.current = () => {
5156
+ clearTimeout(timerRef.current);
5157
+ setInstant(true);
5158
+ setIsOpen(false);
5159
+ };
5160
+ const closeInstantly = React45.useCallback(() => closeInstantlyRef.current(), []);
5161
+ const show = React45.useCallback(
5162
+ (asInstant) => {
5163
+ setInstant(asInstant);
5164
+ setIsOpen(true);
5093
5165
  },
5094
5166
  [setIsOpen]
5095
5167
  );
5096
- return [isOpen && !disabled, setOpen];
5097
- }
5098
-
5099
- // src/components/popover/Popover.module.css
5100
- var Popover_default = {
5101
- content: "Popover_content",
5102
- header: "Popover_header",
5103
- title: "Popover_title",
5104
- description: "Popover_description",
5105
- actions: "Popover_actions"
5106
- };
5107
-
5108
- // src/components/popover/Popover.tsx
5109
- import { jsx as jsx26 } from "react/jsx-runtime";
5110
- var [PopoverProvider, usePopoverContext] = createComponentContext("Popover");
5111
- function PopoverRoot({
5112
- open,
5113
- defaultOpen = false,
5114
- onOpenChange,
5115
- closeOnOutsideClick = true,
5116
- closeOnEscape = true,
5117
- openOnArrow = false,
5118
- children
5119
- }) {
5120
- const [isOpen, setOpen] = useOpenState({ open, defaultOpen, onOpenChange });
5121
- const id = React47.useId();
5122
- const triggerRef = React47.useRef(null);
5123
- const anchoredRef = React47.useRef(false);
5124
- const value = React47.useMemo(
5168
+ const scheduleOpen = React45.useCallback(() => {
5169
+ clearTimeout(timerRef.current);
5170
+ if (group.isWarm() || delayDuration <= 0) {
5171
+ show(group.isWarm());
5172
+ return;
5173
+ }
5174
+ timerRef.current = setTimeout(() => show(false), delayDuration);
5175
+ }, [delayDuration, group, show]);
5176
+ const close = React45.useCallback(() => {
5177
+ clearTimeout(timerRef.current);
5178
+ setInstant(false);
5179
+ setIsOpen(false);
5180
+ }, [setIsOpen]);
5181
+ const scheduleClose = React45.useCallback(() => {
5182
+ clearTimeout(timerRef.current);
5183
+ timerRef.current = setTimeout(close, CLOSE_GRACE_MS);
5184
+ }, [close]);
5185
+ React45.useEffect(() => {
5186
+ if (!isOpen) return;
5187
+ group.opened(closeInstantly);
5188
+ return () => group.closed(closeInstantly);
5189
+ }, [isOpen, group, closeInstantly]);
5190
+ React45.useEffect(() => () => clearTimeout(timerRef.current), []);
5191
+ const value = React45.useMemo(
5125
5192
  () => ({
5126
5193
  isOpen,
5127
- setOpen,
5128
- triggerId: `${id}-trigger`,
5129
- contentId: `${id}-content`,
5194
+ instant,
5130
5195
  triggerRef,
5131
- closeOnOutsideClick,
5132
- closeOnEscape,
5133
- openOnArrow,
5134
- anchoredRef
5196
+ contentId,
5197
+ scheduleOpen,
5198
+ scheduleClose,
5199
+ cancelPending,
5200
+ close
5135
5201
  }),
5136
- [isOpen, setOpen, id, closeOnOutsideClick, closeOnEscape, openOnArrow]
5202
+ [isOpen, instant, contentId, scheduleOpen, scheduleClose, cancelPending, close]
5137
5203
  );
5138
- return /* @__PURE__ */ jsx26(PopoverProvider, { value, children });
5204
+ return /* @__PURE__ */ jsx27(TooltipRootProvider, { value, children });
5139
5205
  }
5140
- PopoverRoot.displayName = "Popover.Root";
5141
- function PopoverTrigger(props) {
5142
- const { isOpen, setOpen, triggerId, contentId, triggerRef, openOnArrow } = usePopoverContext("Popover.Trigger");
5143
- return /* @__PURE__ */ jsx26(
5144
- FloatingTrigger,
5145
- {
5146
- ...props,
5147
- triggerProps: {
5148
- ref: triggerRef,
5149
- id: triggerId,
5150
- "aria-haspopup": "dialog",
5151
- "aria-controls": isOpen ? contentId : void 0,
5152
- ...floatingTriggerProps({ open: isOpen, setOpen, openOnArrow })
5153
- }
5154
- }
5155
- );
5156
- }
5157
- PopoverTrigger.displayName = "Popover.Trigger";
5158
- function PopoverAnchor({ children }) {
5159
- const { triggerRef, anchoredRef } = usePopoverContext("Popover.Anchor");
5160
- anchoredRef.current = true;
5161
- return /* @__PURE__ */ jsx26(Slot, { ref: triggerRef, children });
5162
- }
5163
- PopoverAnchor.displayName = "Popover.Anchor";
5164
- function PopoverClose({ children }) {
5165
- const { setOpen } = usePopoverContext("Popover.Close");
5166
- return /* @__PURE__ */ jsx26(Slot, { onClick: () => setOpen(false), children });
5167
- }
5168
- PopoverClose.displayName = "Popover.Close";
5169
- function PopoverContent({
5170
- side = DEFAULT_SIDE,
5171
- align = DEFAULT_ALIGN,
5172
- size = OVERLAY_CONTENT_SIZE,
5173
- width = "auto",
5174
- trapFocus = false,
5175
- initialFocus,
5176
- flush = false,
5177
- className,
5178
- children,
5179
- ...rest
5180
- }) {
5181
- const {
5182
- isOpen,
5183
- setOpen,
5184
- triggerRef,
5185
- contentId,
5186
- closeOnOutsideClick,
5187
- closeOnEscape,
5188
- anchoredRef
5189
- } = usePopoverContext("Popover.Content");
5190
- const floating = useFloatingLayer({
5191
- open: isOpen,
5192
- onOpenChange: setOpen,
5193
- triggerRef,
5194
- side,
5195
- align,
5196
- matchAnchorWidth: width === "trigger" || width === "min-trigger",
5197
- closeOnEscape,
5198
- closeOnOutsideClick,
5199
- focusOnOpen: initialFocus ?? !anchoredRef.current,
5200
- trap: trapFocus,
5201
- tabExit: "edges",
5202
- // A panel driven by typing in its anchor stays next to the field.
5203
- sheet: !anchoredRef.current
5204
- });
5205
- const [titleId, setTitleId] = React47.useState(null);
5206
- const [descriptionId, setDescriptionId] = React47.useState(null);
5207
- const fallbackId = `${contentId}-title`;
5208
- const fallbackDescriptionId = `${contentId}-description`;
5209
- const slots = React47.useMemo(
5210
- () => ({ fallbackId, fallbackDescriptionId, setTitleId, setDescriptionId }),
5211
- [fallbackId, fallbackDescriptionId]
5212
- );
5213
- const anchorName = useAnchorName(isOpen, titleId !== null, triggerRef);
5214
- return /* @__PURE__ */ jsx26(
5215
- FloatingPanel,
5216
- {
5217
- ...rest,
5218
- floating,
5219
- size,
5220
- width,
5221
- scroll: true,
5222
- id: contentId,
5223
- role: "dialog",
5224
- "aria-modal": false,
5225
- ...anchorName,
5226
- "aria-labelledby": titleId ?? anchorName["aria-labelledby"],
5227
- "aria-describedby": descriptionId ?? void 0,
5228
- tabIndex: -1,
5229
- "data-flush": flush || void 0,
5230
- className: cx(fieldTierClass, Popover_default.content, className),
5231
- children: /* @__PURE__ */ jsx26(PopoverSlotsContext.Provider, { value: slots, children })
5232
- }
5233
- );
5234
- }
5235
- PopoverContent.displayName = "Popover.Content";
5236
- var PopoverSlotsContext = React47.createContext(null);
5237
- function useSlotId(id, kind) {
5238
- const slots = React47.useContext(PopoverSlotsContext);
5239
- const resolved = id ?? (kind === "title" ? slots?.fallbackId : slots?.fallbackDescriptionId);
5240
- const register = kind === "title" ? slots?.setTitleId : slots?.setDescriptionId;
5241
- React47.useLayoutEffect(() => {
5242
- if (!register || !resolved) return;
5243
- register(resolved);
5244
- return () => register(null);
5245
- }, [register, resolved]);
5246
- return resolved;
5247
- }
5248
- function PopoverHeader({ className, ...rest }) {
5249
- return /* @__PURE__ */ jsx26("div", { className: cx(Popover_default.header, className), ...rest });
5250
- }
5251
- PopoverHeader.displayName = "Popover.Header";
5252
- function PopoverTitle({ className, id, ...rest }) {
5253
- const resolvedId = useSlotId(id, "title");
5254
- return /* @__PURE__ */ jsx26("h2", { id: resolvedId, className: cx(Popover_default.title, className), ...rest });
5255
- }
5256
- PopoverTitle.displayName = "Popover.Title";
5257
- function PopoverDescription({ className, id, ...rest }) {
5258
- const resolvedId = useSlotId(id, "description");
5259
- return /* @__PURE__ */ jsx26("p", { id: resolvedId, className: cx(Popover_default.description, className), ...rest });
5260
- }
5261
- PopoverDescription.displayName = "Popover.Description";
5262
- function PopoverActions({ className, ...rest }) {
5263
- return /* @__PURE__ */ jsx26("div", { className: cx(Popover_default.actions, className), ...rest });
5264
- }
5265
- PopoverActions.displayName = "Popover.Actions";
5266
- var Popover = {
5267
- Root: PopoverRoot,
5268
- Trigger: PopoverTrigger,
5269
- Anchor: PopoverAnchor,
5270
- Content: PopoverContent,
5271
- Header: PopoverHeader,
5272
- Title: PopoverTitle,
5273
- Description: PopoverDescription,
5274
- Actions: PopoverActions,
5275
- Close: PopoverClose
5276
- };
5277
-
5278
- // src/components/tooltip/Tooltip.tsx
5279
- import * as React48 from "react";
5280
-
5281
- // src/internal/overlay/tooltipSurface.module.css
5282
- var tooltipSurface_default = {
5283
- chip: "tooltipSurface_chip"
5284
- };
5285
-
5286
- // src/components/tooltip/Tooltip.module.css
5287
- var Tooltip_default = {
5288
- content: "Tooltip_content",
5289
- arrow: "Tooltip_arrow",
5290
- focusHost: "Tooltip_focusHost",
5291
- disabledHost: "Tooltip_disabledHost"
5292
- };
5293
-
5294
- // src/components/tooltip/Tooltip.tsx
5295
- import { jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
5296
- var DEFAULT_DELAY_MS = 400;
5297
- var DEFAULT_SKIP_DELAY_MS = 300;
5298
- var CLOSE_GRACE_MS = 100;
5299
- function createTooltipGroup(delayDuration, skipDelayDuration) {
5300
- let current = null;
5301
- let warmUntil = 0;
5302
- return {
5303
- delayDuration,
5304
- isWarm: () => current !== null || Date.now() < warmUntil,
5305
- opened: (close) => {
5306
- if (current && current !== close) current();
5307
- current = close;
5308
- },
5309
- closed: (close) => {
5310
- if (current === close) current = null;
5311
- warmUntil = Date.now() + skipDelayDuration;
5312
- }
5313
- };
5314
- }
5315
- var defaultGroup = createTooltipGroup(DEFAULT_DELAY_MS, DEFAULT_SKIP_DELAY_MS);
5316
- var TooltipGroupContext = React48.createContext(defaultGroup);
5317
- function TooltipProvider({
5318
- delayDuration = DEFAULT_DELAY_MS,
5319
- skipDelayDuration = DEFAULT_SKIP_DELAY_MS,
5320
- children
5321
- }) {
5322
- const group = React48.useMemo(
5323
- () => createTooltipGroup(delayDuration, skipDelayDuration),
5324
- [delayDuration, skipDelayDuration]
5325
- );
5326
- return /* @__PURE__ */ jsx27(TooltipGroupContext.Provider, { value: group, children });
5327
- }
5328
- var [TooltipRootProvider, useTooltipRootContext] = createComponentContext("Tooltip");
5329
- function TooltipRoot({
5330
- children,
5331
- open,
5332
- defaultOpen,
5333
- onOpenChange,
5334
- delayDuration: delayProp
5335
- }) {
5336
- const group = React48.useContext(TooltipGroupContext);
5337
- const delayDuration = delayProp ?? group.delayDuration;
5338
- const [isOpen, setIsOpen] = useControllableState({
5339
- value: open,
5340
- defaultValue: defaultOpen ?? false,
5341
- onChange: onOpenChange
5342
- });
5343
- const [instant, setInstant] = React48.useState(false);
5344
- const triggerRef = React48.useRef(null);
5345
- const timerRef = React48.useRef(void 0);
5346
- const contentId = React48.useId();
5347
- const cancelPending = React48.useCallback(() => clearTimeout(timerRef.current), []);
5348
- const closeInstantlyRef = React48.useRef(() => {
5349
- });
5350
- closeInstantlyRef.current = () => {
5351
- clearTimeout(timerRef.current);
5352
- setInstant(true);
5353
- setIsOpen(false);
5354
- };
5355
- const closeInstantly = React48.useCallback(() => closeInstantlyRef.current(), []);
5356
- const show = React48.useCallback(
5357
- (asInstant) => {
5358
- setInstant(asInstant);
5359
- setIsOpen(true);
5360
- },
5361
- [setIsOpen]
5362
- );
5363
- const scheduleOpen = React48.useCallback(() => {
5364
- clearTimeout(timerRef.current);
5365
- if (group.isWarm() || delayDuration <= 0) {
5366
- show(group.isWarm());
5367
- return;
5368
- }
5369
- timerRef.current = setTimeout(() => show(false), delayDuration);
5370
- }, [delayDuration, group, show]);
5371
- const close = React48.useCallback(() => {
5372
- clearTimeout(timerRef.current);
5373
- setInstant(false);
5374
- setIsOpen(false);
5375
- }, [setIsOpen]);
5376
- const scheduleClose = React48.useCallback(() => {
5377
- clearTimeout(timerRef.current);
5378
- timerRef.current = setTimeout(close, CLOSE_GRACE_MS);
5379
- }, [close]);
5380
- React48.useEffect(() => {
5381
- if (!isOpen) return;
5382
- group.opened(closeInstantly);
5383
- return () => group.closed(closeInstantly);
5384
- }, [isOpen, group, closeInstantly]);
5385
- React48.useEffect(() => () => clearTimeout(timerRef.current), []);
5386
- const value = React48.useMemo(
5387
- () => ({
5388
- isOpen,
5389
- instant,
5390
- triggerRef,
5391
- contentId,
5392
- scheduleOpen,
5393
- scheduleClose,
5394
- cancelPending,
5395
- close
5396
- }),
5397
- [isOpen, instant, contentId, scheduleOpen, scheduleClose, cancelPending, close]
5398
- );
5399
- return /* @__PURE__ */ jsx27(TooltipRootProvider, { value, children });
5400
- }
5401
- var BUTTON = 'button:not([role]), [role="button"]';
5402
- function TooltipTrigger(props) {
5403
- const { children } = props;
5404
- const { isOpen, triggerRef, contentId, scheduleOpen, scheduleClose, close } = useTooltipRootContext("Tooltip.Trigger");
5405
- const pressedRef = React48.useRef(false);
5406
- const childProps = children.props;
5407
- const inheritedDisabled = useInheritedDisabled();
5408
- const [domDisabled, setDomDisabled] = React48.useState(false);
5409
- const disabledChild = childProps.disabled === true || inheritedDisabled && domDisabled;
5410
- const [ownTabStop, setOwnTabStop] = React48.useState(true);
5411
- const [buttonHost, setButtonHost] = React48.useState(false);
5412
- React48.useLayoutEffect(() => {
5413
- const node = triggerRef.current;
5414
- if (!node) return;
5415
- const host = node.hasAttribute("data-disabled-host");
5416
- const control = host ? node.firstElementChild : node;
5417
- setDomDisabled(
5418
- inheritedDisabled && control?.matches(":disabled, [aria-disabled='true']") === true
5419
- );
5420
- setButtonHost(host && control?.matches(BUTTON) === true);
5421
- if (!disabledChild) setOwnTabStop(childProps.tabIndex !== void 0 || hasNativeTabStop(node));
5422
- });
5423
- const madeFocusable = disabledChild || !ownTabStop;
5424
- const generatedId = React48.useId();
5425
- const controlId = typeof childProps.id === "string" ? childProps.id : generatedId;
5426
- return /* @__PURE__ */ jsx27(
5206
+ var BUTTON = 'button:not([role]), [role="button"]';
5207
+ function TooltipTrigger(props) {
5208
+ const { children } = props;
5209
+ const { isOpen, triggerRef, contentId, scheduleOpen, scheduleClose, close } = useTooltipRootContext("Tooltip.Trigger");
5210
+ const pressedRef = React45.useRef(false);
5211
+ const childProps = children.props;
5212
+ const inheritedDisabled = useInheritedDisabled();
5213
+ const [domDisabled, setDomDisabled] = React45.useState(false);
5214
+ const disabledChild = childProps.disabled === true || inheritedDisabled && domDisabled;
5215
+ const [ownTabStop, setOwnTabStop] = React45.useState(true);
5216
+ const [buttonHost, setButtonHost] = React45.useState(false);
5217
+ React45.useLayoutEffect(() => {
5218
+ const node = triggerRef.current;
5219
+ if (!node) return;
5220
+ const host = node.hasAttribute("data-disabled-host");
5221
+ const control = host ? node.firstElementChild : node;
5222
+ setDomDisabled(
5223
+ inheritedDisabled && control?.matches(":disabled, [aria-disabled='true']") === true
5224
+ );
5225
+ setButtonHost(host && control?.matches(BUTTON) === true);
5226
+ if (!disabledChild) setOwnTabStop(childProps.tabIndex !== void 0 || hasNativeTabStop(node));
5227
+ });
5228
+ const madeFocusable = disabledChild || !ownTabStop;
5229
+ const generatedId = React45.useId();
5230
+ const controlId = typeof childProps.id === "string" ? childProps.id : generatedId;
5231
+ return /* @__PURE__ */ jsx27(
5427
5232
  FloatingTrigger,
5428
5233
  {
5429
5234
  ...props,
@@ -5461,7 +5266,7 @@ function TooltipTrigger(props) {
5461
5266
  className: Tooltip_default.disabledHost,
5462
5267
  "data-disabled-host": "",
5463
5268
  ...buttonHost ? { role: "button", "aria-disabled": "true", "aria-labelledby": controlId } : null,
5464
- children: buttonHost ? React48.cloneElement(
5269
+ children: buttonHost ? React45.cloneElement(
5465
5270
  children,
5466
5271
  {
5467
5272
  id: controlId,
@@ -5551,40 +5356,235 @@ var Tooltip = {
5551
5356
  Content: TooltipContent
5552
5357
  };
5553
5358
 
5554
- // src/components/skeleton/Skeleton.module.css
5555
- var Skeleton_default = {
5556
- root: "Skeleton_root",
5557
- primeSkeletonPulse: "Skeleton_primeSkeletonPulse",
5558
- line: "Skeleton_line"
5559
- };
5560
-
5561
- // src/components/skeleton/Skeleton.tsx
5562
- import { jsx as jsx28 } from "react/jsx-runtime";
5563
- function Skeleton({
5564
- shape = "text",
5565
- size: sizeProp,
5566
- lines = 1,
5567
- className,
5568
- ...rest
5569
- }) {
5570
- const size = useControlSize(sizeProp);
5571
- const count = shape === "text" ? Math.max(1, Math.floor(lines)) : 0;
5572
- return /* @__PURE__ */ jsx28(
5573
- "span",
5574
- {
5575
- "aria-hidden": "true",
5576
- ...rest,
5577
- className: cx(fieldTierClass, Skeleton_default.root, className),
5578
- ...toDataAttributes({ shape, size }),
5579
- children: Array.from({ length: count }, (_, index) => (
5580
- // biome-ignore lint/suspicious/noArrayIndexKey: identical placeholder lines
5581
- /* @__PURE__ */ jsx28("span", { className: Skeleton_default.line }, index)
5582
- ))
5583
- }
5584
- );
5585
- }
5359
+ // src/components/popover/Popover.tsx
5360
+ import * as React48 from "react";
5586
5361
 
5587
- // src/components/progress-bar/ProgressBar.tsx
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
5588
  import * as React50 from "react";
5589
5589
 
5590
5590
  // src/internal/ProgressLegend.module.css
@@ -7311,1388 +7311,1388 @@ var EmptyPage = {
7311
7311
  RetryButton: EmptyPageRetryButton
7312
7312
  };
7313
7313
 
7314
- // src/internal/swatch.tsx
7315
- import * as React59 from "react";
7314
+ // src/components/select/Select.tsx
7315
+ import * as React62 from "react";
7316
7316
 
7317
- // src/hooks/useElementSize.ts
7317
+ // src/hooks/useLoadMore.ts
7318
7318
  import * as React58 from "react";
7319
- var rounded = (width, height) => ({
7320
- width: Math.round(width),
7321
- height: Math.round(height)
7322
- });
7323
- var sizeOf = (element) => {
7324
- const rect = element.getBoundingClientRect();
7325
- return rounded(rect.width, rect.height);
7326
- };
7327
- var entrySize = (entry) => {
7328
- const box = entry.borderBoxSize?.[0];
7329
- return box ? rounded(box.inlineSize, box.blockSize) : rounded(entry.contentRect.width, entry.contentRect.height);
7330
- };
7331
- var sameSize = (a, b) => a === b || a !== null && b !== null && a.width === b.width && a.height === b.height;
7332
- function useRefNode(ref, enabled, subscribe) {
7333
- const subscribeRef = React58.useRef(subscribe);
7334
- 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);
7335
7332
  React58.useLayoutEffect(() => {
7336
- subscribeRef.current = subscribe;
7337
- const node = enabled ? ref.current : null;
7338
- if (active2.current?.node === node) return;
7339
- active2.current?.stop();
7340
- active2.current = node ? { node, stop: subscribeRef.current(node) } : null;
7341
- });
7342
- React58.useLayoutEffect(
7343
- () => () => {
7344
- active2.current?.stop();
7345
- active2.current = null;
7346
- },
7347
- []
7348
- );
7349
- }
7350
- function useElementSize(ref, { enabled = true } = {}) {
7351
- const [size, setSize] = React58.useState(null);
7352
- useRefNode(ref, enabled, (node) => {
7353
- const update = (next) => setSize((prev) => sameSize(prev, next) ? prev : next);
7354
- update(sizeOf(node));
7355
- if (typeof ResizeObserver === "undefined") return () => update(null);
7356
- const observer = new ResizeObserver(([entry]) => update(entry ? entrySize(entry) : null));
7357
- observer.observe(node);
7358
- return () => {
7359
- observer.disconnect();
7360
- update(null);
7361
- };
7362
- });
7363
- 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 };
7364
7354
  }
7365
- function useResizeEffect(ref, onResize, { enabled = true, children = false } = {}) {
7366
- const callback = React58.useRef(onResize);
7367
- React58.useLayoutEffect(() => {
7368
- callback.current = onResize;
7369
- });
7370
- useRefNode(ref, enabled, (node) => {
7371
- if (typeof ResizeObserver === "undefined") return () => {
7372
- };
7373
- const observer = new ResizeObserver(() => callback.current());
7374
- const observeAll = () => {
7375
- observer.observe(node);
7376
- if (children) for (const child of Array.from(node.children)) observer.observe(child);
7377
- };
7378
- observeAll();
7379
- const mutation = children ? new MutationObserver(observeAll) : null;
7380
- mutation?.observe(node, { childList: true });
7381
- return () => {
7382
- mutation?.disconnect();
7383
- observer.disconnect();
7384
- };
7385
- });
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
+ );
7386
7377
  }
7387
7378
 
7388
- // src/internal/swatch.module.css
7389
- var swatch_default = {
7390
- fill: "swatch_fill",
7391
- checker: "swatch_checker",
7392
- checkerboard: "swatch_checkerboard",
7393
- hueFill: "swatch_hueFill",
7394
- tier: "swatch_tier",
7395
- grid: "swatch_grid",
7396
- chip: "swatch_chip",
7397
- swatch: "swatch_swatch",
7398
- trigger: "swatch_trigger",
7399
- 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"
7400
7402
  };
7401
7403
 
7402
- // src/internal/swatch.tsx
7403
- import { Fragment as Fragment15, jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
7404
- var COLOR_PRESETS = [
7405
- { value: "#ef4444", label: "\u041A\u0440\u0430\u0441\u043D\u044B\u0439" },
7406
- { value: "#f97316", label: "\u041E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439" },
7407
- { value: "#eab308", label: "\u0416\u0451\u043B\u0442\u044B\u0439" },
7408
- { value: "#22c55e", label: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439" },
7409
- { value: "#14b8a6", label: "\u0411\u0438\u0440\u044E\u0437\u043E\u0432\u044B\u0439" },
7410
- { value: "#5068f5", label: "\u0421\u0438\u043D\u0438\u0439" },
7411
- { value: "#a855f7", label: "\u0424\u0438\u043E\u043B\u0435\u0442\u043E\u0432\u044B\u0439" },
7412
- { value: "#ec4899", label: "\u0420\u043E\u0437\u043E\u0432\u044B\u0439" },
7413
- { value: "#b91c1c", label: "\u0422\u0451\u043C\u043D\u043E-\u043A\u0440\u0430\u0441\u043D\u044B\u0439" },
7414
- { value: "#c2410c", label: "\u0422\u0451\u043C\u043D\u043E-\u043E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439" },
7415
- { value: "#a16207", label: "\u0413\u043E\u0440\u0447\u0438\u0447\u043D\u044B\u0439" },
7416
- { value: "#15803d", label: "\u0422\u0451\u043C\u043D\u043E-\u0437\u0435\u043B\u0451\u043D\u044B\u0439" },
7417
- { value: "#0f766e", label: "\u0422\u0451\u043C\u043D\u043E-\u0431\u0438\u0440\u044E\u0437\u043E\u0432\u044B\u0439" },
7418
- { value: "#2f4ae0", label: "\u0422\u0451\u043C\u043D\u043E-\u0441\u0438\u043D\u0438\u0439" },
7419
- { value: "#7e22ce", label: "\u0422\u0451\u043C\u043D\u043E-\u0444\u0438\u043E\u043B\u0435\u0442\u043E\u0432\u044B\u0439" },
7420
- { value: "#be185d", label: "\u0422\u0451\u043C\u043D\u043E-\u0440\u043E\u0437\u043E\u0432\u044B\u0439" }
7421
- ];
7422
- var PALETTE_COLOR_NAMES = {
7423
- gray: "\u0421\u0435\u0440\u044B\u0439",
7424
- red: "\u041A\u0440\u0430\u0441\u043D\u044B\u0439",
7425
- orange: "\u041E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439",
7426
- yellow: "\u0416\u0451\u043B\u0442\u044B\u0439",
7427
- green: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439",
7428
- teal: "\u0411\u0438\u0440\u044E\u0437\u043E\u0432\u044B\u0439",
7429
- sky: "\u0413\u043E\u043B\u0443\u0431\u043E\u0439",
7430
- blue: "\u0421\u0438\u043D\u0438\u0439",
7431
- purple: "\u0424\u0438\u043E\u043B\u0435\u0442\u043E\u0432\u044B\u0439",
7432
- pink: "\u0420\u043E\u0437\u043E\u0432\u044B\u0439"
7433
- };
7434
- var PALETTE_ORDER = Object.keys(PALETTE_COLOR_NAMES);
7435
- function useSwatchOptions(presets, allowEmpty, emptyLabel) {
7436
- return React59.useMemo(
7437
- () => [
7438
- ...presets.map((preset) => ({ ...preset, contrast: markContrast(preset.value) })),
7439
- ...allowEmpty ? [{ value: null, label: emptyLabel, contrast: "surface" }] : []
7440
- ],
7441
- [presets, allowEmpty, emptyLabel]
7442
- );
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 "";
7443
7416
  }
7444
- function usePaletteOptions(palette, allowEmpty, emptyLabel, names) {
7445
- return React59.useMemo(
7446
- () => [
7447
- ...palette.map((hue) => ({ value: hue, label: names[hue], contrast: "hue" })),
7448
- ...allowEmpty ? [{ value: null, label: emptyLabel, contrast: "surface" }] : []
7449
- ],
7450
- [palette, allowEmpty, emptyLabel, names]
7451
- );
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 });
7452
7426
  }
7453
- var swatchClass = cx(swatch_default.swatch, press_default.press);
7454
- var swatchTriggerClass = cx(swatch_default.trigger, press_default.press);
7455
- var swatchTierClass = cx(fieldTierClass, swatch_default.tier);
7456
- var swatchGridClass = swatch_default.grid;
7457
- var checkerboardClass = swatch_default.checkerboard;
7458
- function SwatchFill({ value, hue = false }) {
7459
- if (value == null) return /* @__PURE__ */ jsx38("span", { "aria-hidden": true, className: swatch_default.checker });
7460
- if (hue) return /* @__PURE__ */ jsx38("span", { "aria-hidden": true, className: cx(swatch_default.fill, swatch_default.hueFill) });
7461
- 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) });
7462
7432
  }
7463
- function SwatchContent({
7464
- value,
7465
- selected,
7466
- hue = false
7433
+ SelectItemText.displayName = "Select.ItemText";
7434
+ function SelectItemDescription({
7435
+ children,
7436
+ className,
7437
+ ...rest
7467
7438
  }) {
7468
- return /* @__PURE__ */ jsxs23(Fragment15, { children: [
7469
- /* @__PURE__ */ jsx38(SwatchFill, { value, hue }),
7470
- /* @__PURE__ */ jsx38(CheckMark, { state: selected ? "checked" : "unchecked", className: swatch_default.check })
7471
- ] });
7472
- }
7473
- function SwatchChip({ value, className, ...rest }) {
7474
- return /* @__PURE__ */ jsx38("span", { ...rest, "aria-hidden": true, className: cx(swatch_default.chip, className), children: /* @__PURE__ */ jsx38(SwatchFill, { value }) });
7439
+ const query = React61.useContext(OptionQueryContext);
7440
+ return /* @__PURE__ */ jsx39("span", { ...rest, className: cx(Select_default.itemDescription, className), children: highlightChildren(children, query) });
7475
7441
  }
7476
- function parseHexColor(text) {
7477
- const hex = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(text.trim())?.[1]?.toLowerCase();
7478
- if (!hex) return null;
7479
- return `#${hex.length === 3 ? [...hex].map((c) => c + c).join("") : hex}`;
7480
- }
7481
- function sameColor(a, b) {
7482
- return (a ?? "").trim().toLowerCase() === (b ?? "").trim().toLowerCase();
7442
+ SelectItemDescription.displayName = "Select.ItemDescription";
7443
+ function SelectItemMeta({ children, className, ...rest }) {
7444
+ return /* @__PURE__ */ jsx39("span", { ...rest, className: cx(Select_default.itemMeta, className), children });
7483
7445
  }
7484
- function colorToRgb(value) {
7485
- const input = value.trim().toLowerCase();
7486
- const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(input)?.[1];
7487
- if (hex) {
7488
- const full = hex.length <= 4 ? [...hex].map((c) => c + c).join("") : hex;
7489
- return [0, 2, 4].map((i) => Number.parseInt(full.slice(i, i + 2), 16));
7490
- }
7491
- const fn = /^(rgba?|hsla?)\(([^)]+)\)$/.exec(input);
7492
- if (!fn) return null;
7493
- const parts = fn[2].split(/[\s,/]+/).filter(Boolean);
7494
- if (parts.length < 3) return null;
7495
- const num = (part, scale) => part.endsWith("%") ? Number.parseFloat(part) / 100 * scale : Number.parseFloat(part);
7496
- if (fn[1].startsWith("rgb")) {
7497
- const rgb = parts.slice(0, 3).map((part) => num(part, 255));
7498
- return rgb.every(Number.isFinite) ? rgb : null;
7499
- }
7500
- const h = Number.parseFloat(parts[0]);
7501
- const s = num(parts[1], 1);
7502
- const l = num(parts[2], 1);
7503
- if (![h, s, l].every(Number.isFinite)) return null;
7504
- const a = s * Math.min(l, 1 - l);
7505
- const channel = (n) => {
7506
- const k = (n + h / 30) % 12;
7507
- return 255 * (l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)));
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: ""
7508
7455
  };
7509
- return [channel(0), channel(8), channel(4)];
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;
7510
7488
  }
7511
- function markContrast(value) {
7512
- const rgb = colorToRgb(value);
7513
- if (!rgb) return "dark";
7514
- const lin = (c) => {
7515
- const s = c / 255;
7516
- return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
7517
- };
7518
- const l = 0.2126 * lin(rgb[0]) + 0.7152 * lin(rgb[1]) + 0.0722 * lin(rgb[2]);
7519
- return l > 0.179 ? "dark" : "light";
7520
- }
7521
- function balancedColumns(count, width, cell, gap) {
7522
- if (count < 1 || width <= 0 || cell <= 0) return Math.max(1, count);
7523
- const fit = Math.max(1, Math.floor((width + gap) / (cell + gap)));
7524
- const rows = Math.ceil(count / Math.min(count, fit));
7525
- return Math.ceil(count / rows);
7526
- }
7527
- function useBalancedColumns(gridRef, count, cellSelector) {
7528
- const [columns, setColumns] = React59.useState();
7529
- const measure = React59.useCallback(() => {
7530
- const grid = gridRef.current;
7531
- if (!grid) return;
7532
- const cell = grid.querySelector(cellSelector)?.offsetHeight ?? 0;
7533
- const gap = Number.parseFloat(getComputedStyle(grid).columnGap) || 0;
7534
- setColumns(cell > 0 ? balancedColumns(count, grid.clientWidth, cell, gap) : void 0);
7535
- }, [gridRef, count, cellSelector]);
7536
- React59.useLayoutEffect(measure, [measure]);
7537
- useResizeEffect(gridRef, measure);
7538
- return columns;
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
+ );
7539
7497
  }
7540
- function firstRowLength(items) {
7541
- const top = items[0]?.offsetTop;
7542
- const count = items.findIndex((item) => !item || item.offsetTop !== top);
7543
- 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
+ );
7544
7564
  }
7545
- function useSwatchGrid(count) {
7546
- const items = React59.useRef([]);
7547
- const itemRef = React59.useCallback(
7548
- (index) => (node) => {
7549
- 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
+ }
7550
7596
  },
7551
- []
7597
+ nodeRef
7552
7598
  );
7553
- const move = React59.useCallback(
7554
- (event, from, columns) => {
7555
- const focused = document.activeElement;
7556
- const current = focused instanceof HTMLElement ? items.current.indexOf(focused) : -1;
7557
- const next = gridIndex(
7558
- event.key,
7559
- current === -1 ? from : current,
7560
- count,
7561
- columns ?? firstRowLength(items.current)
7562
- );
7563
- if (next === null) return null;
7564
- event.preventDefault();
7565
- items.current[next]?.focus();
7566
- return next;
7567
- },
7568
- [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
+ )
7569
7631
  );
7570
- const focus = React59.useCallback((index) => {
7571
- items.current[index]?.focus({ preventScroll: true });
7572
- }, []);
7573
- return { itemRef, move, focus };
7574
7632
  }
7633
+ SelectAction.displayName = "Select.Action";
7575
7634
 
7576
- // src/components/color-swatches/ColorSwatches.tsx
7577
- import * as React60 from "react";
7578
-
7579
- // src/components/color-swatches/ColorSwatches.module.css
7580
- var ColorSwatches_default = {
7581
- grid: "ColorSwatches_grid"
7582
- };
7583
-
7584
- // src/components/color-swatches/ColorSwatches.tsx
7585
- import { jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
7586
- var COLOR_SWATCHES_LABELS = {
7587
- group: "\u0426\u0432\u0435\u0442",
7588
- 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",
7589
7644
  optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
7590
- 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"
7591
7646
  };
7592
- function ColorSwatches(props) {
7647
+ function SelectRoot(props) {
7593
7648
  const {
7594
- mode,
7595
- value,
7596
- defaultValue,
7597
- onValueChange,
7598
- presets = COLOR_PRESETS,
7599
- palette = PALETTE_ORDER,
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,
7600
7686
  ...rest
7601
7687
  } = props;
7602
- return /* @__PURE__ */ jsx39(
7603
- SwatchGrid,
7604
- {
7605
- ...rest,
7606
- hues: mode === "palette",
7607
- presets,
7608
- palette,
7609
- value,
7610
- defaultValue: defaultValue ?? null,
7611
- onValueChange
7688
+ const multiple = props.multiple === true;
7689
+ const tier = useHostTier(sizeProp);
7690
+ const { size } = tier;
7691
+ const disabled = useInheritedDisabled(disabledProp);
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)
7697
+ });
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;
7612
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]
7613
7721
  );
7614
- }
7615
- function SwatchGrid({
7616
- hues,
7617
- presets,
7618
- palette,
7619
- value: valueProp,
7620
- defaultValue,
7621
- onValueChange,
7622
- size: sizeProp,
7623
- disabled: disabledProp = false,
7624
- invalid,
7625
- allowEmpty = false,
7626
- name,
7627
- id,
7628
- className,
7629
- label,
7630
- required,
7631
- optional,
7632
- hint,
7633
- hintTone,
7634
- error,
7635
- "aria-label": ariaLabel,
7636
- "aria-labelledby": ariaLabelledBy,
7637
- "aria-describedby": ariaDescribedBy,
7638
- labels: labelsProp,
7639
- ...rest
7640
- }) {
7641
- const size = useControlSize(sizeProp);
7642
- const disabled = useInheritedDisabled(disabledProp);
7643
- const frameSize = useControlSize(void 0);
7644
- const merged = useLabels(COLOR_SWATCHES_LABELS, labelsProp);
7645
- const labels = React60.useMemo(
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;
7749
+ }
7750
+ commitRef.current(optionValue);
7751
+ setOpen(false);
7752
+ },
7753
+ [multiple, value, setOpen]
7754
+ );
7755
+ const clear = React62.useCallback(() => commitRef.current(multiple ? [] : ""), [multiple]);
7756
+ const context = React62.useMemo(
7646
7757
  () => ({
7647
- ...merged,
7648
- colorNames: { ...COLOR_SWATCHES_LABELS.colorNames, ...labelsProp?.colorNames }
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
7649
7791
  }),
7650
- [merged, labelsProp?.colorNames]
7651
- );
7652
- const [value, setValue] = useControllableState({
7653
- value: valueProp,
7654
- defaultValue,
7655
- onChange: onValueChange
7656
- });
7657
- const ids = useFieldFrame(id, { label, hint, error, invalid }, ariaDescribedBy);
7658
- const colorOptions = useSwatchOptions(presets, allowEmpty, labels.empty);
7659
- const hueOptions = usePaletteOptions(palette, allowEmpty, labels.empty, labels.colorNames);
7660
- const options = hues ? hueOptions : colorOptions;
7661
- const selectedIndex = options.findIndex((option) => sameColor(option.value, value));
7662
- const focusIndex = Math.max(0, selectedIndex);
7663
- const grid = useSwatchGrid(options.length);
7664
- const gridRef = React60.useRef(null);
7665
- const columns = useBalancedColumns(gridRef, options.length, "[role='radio']");
7666
- const labelledBy = ariaLabelledBy ?? ids.labelledBy;
7667
- const onKeyDown2 = (event) => {
7668
- const next = grid.move(event, focusIndex);
7669
- if (next !== null) setValue(options[next]?.value ?? null);
7670
- };
7671
- return /* @__PURE__ */ jsx39(
7672
- FieldFrame,
7673
- {
7674
- ...rest,
7675
- size: frameSize,
7676
- ids,
7677
- label,
7678
- required,
7679
- optional,
7680
- hint,
7681
- hintTone,
7682
- error,
7792
+ [
7793
+ size,
7794
+ ids.invalid,
7795
+ ids.controlId,
7796
+ ids.describedBy,
7797
+ focusRing,
7798
+ ids.required,
7683
7799
  disabled,
7684
- optionalLabel: labels.optional,
7685
- group: true,
7686
- className,
7687
- children: /* @__PURE__ */ jsxs24(
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(
7688
7834
  "div",
7689
7835
  {
7690
- ref: gridRef,
7691
- id: ids.controlId,
7692
- role: "radiogroup",
7693
- "aria-label": labelledBy ? void 0 : ariaLabel ?? labels.group,
7694
- "aria-labelledby": labelledBy,
7695
- "aria-describedby": ids.describedBy,
7696
- "aria-required": required || void 0,
7697
- "aria-invalid": ids.invalid || void 0,
7698
- className: cx(swatchTierClass, swatchGridClass, ColorSwatches_default.grid),
7699
- "data-base": "control",
7700
- "data-stretch": "true",
7701
- style: {
7702
- "--swatch-count": options.length,
7703
- "--swatch-columns": columns
7704
- },
7705
- ...toDataAttributes({
7706
- size,
7707
- invalid: ids.invalid || void 0,
7708
- disabled: disabled || void 0
7709
- }),
7710
- onKeyDown: disabled ? void 0 : onKeyDown2,
7711
- children: [
7712
- options.map((option, index) => {
7713
- const selected = index === selectedIndex;
7714
- return (
7715
- // 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
7716
- /* @__PURE__ */ jsx39(
7717
- "button",
7718
- {
7719
- ref: grid.itemRef(index),
7720
- type: "button",
7721
- role: "radio",
7722
- "aria-checked": selected,
7723
- "aria-label": option.label,
7724
- title: option.label,
7725
- tabIndex: index === focusIndex ? 0 : -1,
7726
- disabled,
7727
- className: cx(swatchClass, hues && option.value && palette_default.hue),
7728
- ...toDataAttributes({
7729
- state: selected ? "checked" : "unchecked",
7730
- contrast: option.contrast,
7731
- color: hues ? option.value ?? void 0 : void 0
7732
- }),
7733
- onClick: () => setValue(option.value),
7734
- children: /* @__PURE__ */ jsx39(SwatchContent, { value: option.value, selected, hue: hues })
7735
- },
7736
- option.value ?? "empty"
7737
- )
7738
- );
7739
- }),
7740
- name ? /* @__PURE__ */ jsx39("input", { type: "hidden", name, value: value ?? "" }) : null
7741
- ]
7836
+ ...rest,
7837
+ className: cx(Select_default.segment, className),
7838
+ "data-field-segment": "",
7839
+ "data-size": size,
7840
+ children: body
7742
7841
  }
7743
7842
  )
7744
- }
7745
- );
7746
- }
7747
-
7748
- // src/components/select/Select.tsx
7749
- import * as React65 from "react";
7750
-
7751
- // src/hooks/useLoadMore.ts
7752
- import * as React61 from "react";
7753
- var LIST_ROOT_MARGIN = "0px 0px 48px 0px";
7754
- var NONE2 = /* @__PURE__ */ Symbol("none");
7755
- function useLoadMore({
7756
- enabled,
7757
- onLoadMore,
7758
- scrollRef,
7759
- round,
7760
- rootMargin = LIST_ROOT_MARGIN
7761
- }) {
7762
- const sentinelRef = React61.useRef(null);
7763
- const handlerRef = React61.useRef(onLoadMore);
7764
- handlerRef.current = onLoadMore;
7765
- const askedIn = React61.useRef(NONE2);
7766
- React61.useLayoutEffect(() => {
7767
- if (!enabled) askedIn.current = NONE2;
7768
- }, [enabled]);
7769
- const request = React61.useCallback(() => {
7770
- if (!enabled || Object.is(askedIn.current, round)) return;
7771
- askedIn.current = round;
7772
- void handlerRef.current?.();
7773
- }, [enabled, round]);
7774
- React61.useEffect(() => {
7775
- const root = scrollRef.current;
7776
- const target = sentinelRef.current;
7777
- if (!enabled || !root || !target || typeof IntersectionObserver === "undefined") return;
7778
- const observer = new IntersectionObserver(
7779
- ([entry]) => {
7780
- if (entry?.isIntersecting) request();
7781
- },
7782
- { root, rootMargin, threshold: 0 }
7783
7843
  );
7784
- observer.observe(target);
7785
- return () => observer.disconnect();
7786
- }, [enabled, request, rootMargin, scrollRef]);
7787
- return { sentinelRef, request };
7788
- }
7789
-
7790
- // src/internal/MenuGroup.tsx
7791
- import * as React62 from "react";
7792
- import { jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
7793
- function MenuGroup({ label, className, children, ...rest }) {
7794
- const labelId = React62.useId();
7795
- return (
7796
- // biome-ignore lint/a11y/useSemanticElements: role="group" inside a menu / listbox; <fieldset> is not allowed there
7797
- /* @__PURE__ */ jsxs25(
7798
- "div",
7799
- {
7800
- ...rest,
7801
- role: "group",
7802
- "aria-labelledby": label != null ? labelId : void 0,
7803
- className: cx(menu_default.group, className),
7804
- children: [
7805
- label != null ? /* @__PURE__ */ jsx40("div", { id: labelId, role: "presentation", className: cx(textRole_default.caption, menu_default.groupLabel), children: label }) : null,
7806
- children
7807
- ]
7808
- }
7809
- )
7810
- );
7811
- }
7812
-
7813
- // src/components/select/Select.module.css
7814
- var Select_default = {
7815
- trigger: "Select_trigger",
7816
- triggerMain: "Select_triggerMain",
7817
- value: "Select_value",
7818
- valueBody: "Select_valueBody",
7819
- triggerIcon: "Select_triggerIcon",
7820
- chevron: "Select_chevron",
7821
- clear: "Select_clear",
7822
- content: "Select_content",
7823
- listbox: "Select_listbox",
7824
- search: "Select_search",
7825
- group: "Select_group",
7826
- separator: "Select_separator",
7827
- actions: "Select_actions",
7828
- item: "Select_item",
7829
- itemText: "Select_itemText",
7830
- itemTitle: "Select_itemTitle",
7831
- itemDescription: "Select_itemDescription",
7832
- itemMeta: "Select_itemMeta",
7833
- media: "Select_media",
7834
- segment: "Select_segment",
7835
- segmentTrigger: "Select_segmentTrigger"
7836
- };
7837
-
7838
- // src/components/select/SelectItem.tsx
7839
- import * as React64 from "react";
7840
-
7841
- // src/internal/nodeText.ts
7842
- import * as React63 from "react";
7843
- function nodeText(node) {
7844
- if (typeof node === "string" || typeof node === "number") return String(node);
7845
- if (Array.isArray(node)) return node.map(nodeText).join("");
7846
- if (React63.isValidElement(node)) {
7847
- return nodeText(node.props.children);
7848
- }
7849
- return "";
7850
- }
7851
-
7852
- // src/components/select/selectContext.ts
7853
- var normalize = (text) => text.trim().toLocaleLowerCase();
7854
- var [SelectProvider, useSelectContext] = createComponentContext("Select");
7855
-
7856
- // src/components/select/SelectItem.tsx
7857
- import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
7858
- function SelectItemIcon({ className, ...rest }) {
7859
- return /* @__PURE__ */ jsx41("span", { "aria-hidden": "true", className: cx(menu_default.itemIcon, iconSlotClass, className), ...rest });
7860
- }
7861
- SelectItemIcon.displayName = "Select.ItemIcon";
7862
- var OptionQueryContext = React64.createContext("");
7863
- function SelectItemText({ children, className, ...rest }) {
7864
- const query = React64.useContext(OptionQueryContext);
7865
- return /* @__PURE__ */ jsx41("span", { ...rest, className: cx(Select_default.itemTitle, className), children: highlightChildren(children, query) });
7866
- }
7867
- SelectItemText.displayName = "Select.ItemText";
7868
- function SelectItemDescription({
7869
- children,
7870
- className,
7871
- ...rest
7872
- }) {
7873
- const query = React64.useContext(OptionQueryContext);
7874
- return /* @__PURE__ */ jsx41("span", { ...rest, className: cx(Select_default.itemDescription, className), children: highlightChildren(children, query) });
7875
- }
7876
- SelectItemDescription.displayName = "Select.ItemDescription";
7877
- function SelectItemMeta({ children, className, ...rest }) {
7878
- return /* @__PURE__ */ jsx41("span", { ...rest, className: cx(Select_default.itemMeta, className), children });
7879
- }
7880
- SelectItemMeta.displayName = "Select.ItemMeta";
7881
- function splitItemChildren(children) {
7882
- const parts = {
7883
- leading: [],
7884
- body: [],
7885
- meta: [],
7886
- rich: false,
7887
- title: "",
7888
- description: ""
7889
- };
7890
- let plain = "";
7891
- for (const child of React64.Children.toArray(children)) {
7892
- if (!React64.isValidElement(child)) {
7893
- plain += nodeText(child);
7894
- parts.body.push(child);
7895
- } else if (child.type === React64.Fragment) {
7896
- const inner = splitItemChildren(child.props.children);
7897
- parts.leading.push(...inner.leading);
7898
- parts.body.push(...inner.body);
7899
- parts.meta.push(...inner.meta);
7900
- parts.rich ||= inner.rich;
7901
- parts.title ||= inner.title;
7902
- parts.description ||= inner.description;
7903
- plain += inner.title;
7904
- } else if (child.type === SelectItemIcon || child.type === Avatar.Root) {
7905
- parts.leading.push(child);
7906
- } else if (child.type === Thumbnail.Root) {
7907
- parts.leading.push(child);
7908
- parts.rich = true;
7909
- } else if (child.type === SelectItemMeta || child.type === Badge.Root) {
7910
- parts.meta.push(child);
7911
- } else {
7912
- if (child.type === SelectItemText) parts.title = nodeText(child.props.children);
7913
- if (child.type === SelectItemDescription) {
7914
- parts.description = nodeText(child.props.children);
7915
- parts.rich = true;
7916
- }
7917
- parts.body.push(child);
7918
- }
7919
7844
  }
7920
- parts.title = (parts.title || plain).trim();
7921
- return parts;
7922
- }
7923
- function sizeMedia(leading, size) {
7924
- return leading.map(
7925
- (node) => React64.isValidElement(node) && (node.type === Thumbnail.Root || node.type === Avatar.Root) ? React64.cloneElement(node, {
7926
- size: node.props.size ?? tierMappings.rowMedia[size],
7927
- className: cx(Select_default.media, node.props.className),
7928
- "aria-hidden": true
7929
- }) : node
7930
- );
7931
- }
7932
- function SelectItem({
7933
- value,
7934
- label,
7935
- keywords,
7936
- disabled = false,
7937
- className,
7938
- children,
7939
- onClick: onClick2,
7940
- onMouseMove,
7941
- ref,
7942
- ...rest
7943
- }) {
7944
- const { multiple, size, selected, highlight, pick, registry, listboxId, query, filter } = useSelectContext();
7945
- const parts = splitItemChildren(children);
7946
- const resolvedLabel = label || parts.title || value;
7947
- const haystack = normalize(`${resolvedLabel} ${parts.description} ${keywords ?? ""}`);
7948
- const isSelected = selected.includes(value);
7949
- const isHighlighted = useStoreSlice(highlight, (current) => current === value);
7950
- const nodeRef = React64.useRef(null);
7951
- const setRefs = useMergedRefs(nodeRef, ref);
7952
- useListboxItem(
7953
- registry,
7954
- value,
7955
- { label: resolvedLabel, haystack, disabled, onActivate: () => pick(value) },
7956
- nodeRef
7957
- );
7958
- const search = normalize(query);
7959
- if (filter && search !== "" && !haystack.includes(search)) return null;
7960
- return (
7961
- // biome-ignore lint/a11y/useFocusableInteractive: focus stays on the listbox / search (aria-activedescendant)
7962
- // biome-ignore lint/a11y/useKeyWithClickEvents: the keyboard is handled on the listbox
7963
- /* @__PURE__ */ jsxs26(
7964
- "div",
7845
+ return tier.provide(
7846
+ /* @__PURE__ */ jsx40(
7847
+ FieldFrame,
7965
7848
  {
7966
7849
  ...rest,
7967
- ref: setRefs,
7968
- id: optionDomId(listboxId, value),
7969
- role: "option",
7970
- "aria-selected": isSelected,
7971
- "aria-disabled": disabled || void 0,
7972
- className: cx(menu_default.item, Select_default.item, className),
7973
- onClick: (event) => {
7974
- onClick2?.(event);
7975
- if (!event.defaultPrevented) registry.activate(value);
7976
- },
7977
- onMouseMove: (event) => {
7978
- onMouseMove?.(event);
7979
- if (!disabled && !isHighlighted) highlight.set(value);
7980
- },
7981
- ...toDataAttributes({
7982
- value,
7983
- selected: isSelected,
7984
- highlighted: isHighlighted,
7985
- disabled,
7986
- rich: parts.rich || void 0
7987
- }),
7988
- children: [
7989
- multiple ? /* @__PURE__ */ jsx41(Checkbox.Indicator, { checked: isSelected, disabled, size: stepDown(size) }) : null,
7990
- sizeMedia(parts.leading, size),
7991
- /* @__PURE__ */ jsx41("span", { className: Select_default.itemText, children: /* @__PURE__ */ jsx41(OptionQueryContext.Provider, { value: query, children: highlightChildren(parts.body, query) }) }),
7992
- parts.meta,
7993
- multiple ? null : /* @__PURE__ */ jsx41("span", { className: menu_default.check, "aria-hidden": "true", children: isSelected ? /* @__PURE__ */ jsx41(Icon, { name: "action.check" }) : null })
7994
- ]
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
7995
7863
  }
7996
7864
  )
7997
7865
  );
7998
7866
  }
7999
- SelectItem.displayName = "Select.Item";
8000
- var ACTION_PREFIX = "__prime_select_action";
8001
- var isActionValue = (value) => value.startsWith(ACTION_PREFIX);
8002
- function SelectAction({
8003
- onSelect,
8004
- disabled = false,
7867
+ SelectRoot.displayName = "Select.Root";
7868
+ var takeNext = (_current, next) => next;
7869
+ function SelectTrigger({
8005
7870
  className,
8006
7871
  children,
8007
7872
  onClick: onClick2,
8008
- onMouseMove,
7873
+ onKeyDown: onKeyDown2,
7874
+ "aria-describedby": ariaDescribedBy,
8009
7875
  ref,
8010
7876
  ...rest
8011
7877
  }) {
8012
- const { highlight, listboxId, setOpen, size, registry } = useSelectContext();
8013
- const value = `${ACTION_PREFIX}${React64.useId()}`;
8014
- const isHighlighted = useStoreSlice(highlight, (current) => current === value);
8015
- const parts = splitItemChildren(children);
8016
- const nodeRef = React64.useRef(null);
8017
- const setRefs = useMergedRefs(nodeRef, ref);
8018
- useListboxItem(
8019
- registry,
8020
- value,
8021
- {
8022
- label: parts.title,
8023
- haystack: "",
8024
- disabled,
8025
- persistent: true,
8026
- onActivate: () => {
8027
- onSelect();
8028
- setOpen(false);
8029
- }
8030
- },
8031
- nodeRef
8032
- );
8033
- return (
8034
- // biome-ignore lint/a11y/useFocusableInteractive: focus stays on the listbox / search (aria-activedescendant)
8035
- // biome-ignore lint/a11y/useKeyWithClickEvents: the keyboard is handled on the listbox
8036
- /* @__PURE__ */ jsxs26(
8037
- "div",
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,
7896
+ registry,
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",
7911
+ {
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"],
7925
+ disabled,
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
+ }
7986
+ );
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",
8038
7998
  {
8039
7999
  ...rest,
8040
- ref: setRefs,
8041
- id: optionDomId(listboxId, value),
8042
- role: "option",
8043
- "aria-disabled": disabled || void 0,
8044
- className: cx(menu_default.item, className),
8045
- onClick: (event) => {
8046
- onClick2?.(event);
8047
- if (!event.defaultPrevented) registry.activate(value);
8048
- },
8049
- onMouseMove: (event) => {
8050
- onMouseMove?.(event);
8051
- if (!disabled && !isHighlighted) highlight.set(value);
8052
- },
8000
+ className: cx(Select_default.value, className),
8053
8001
  ...toDataAttributes({
8054
- value,
8055
- action: true,
8056
- highlighted: isHighlighted,
8057
- disabled
8002
+ rich: parts.rich || void 0,
8003
+ media: parts.leading.length > 0 || parts.meta.length > 0 || void 0
8058
8004
  }),
8059
8005
  children: [
8060
8006
  sizeMedia(parts.leading, size),
8061
- /* @__PURE__ */ jsx41("span", { className: Select_default.itemText, children: parts.body })
8007
+ /* @__PURE__ */ jsx40("span", { className: Select_default.valueBody, children: parts.body }),
8008
+ parts.meta
8062
8009
  ]
8063
8010
  }
8064
- )
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
+ }
8065
8021
  );
8066
8022
  }
8067
- SelectAction.displayName = "Select.Action";
8068
-
8069
- // src/components/select/Select.tsx
8070
- import { Fragment as Fragment17, jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
8071
- var SELECT_LABELS = {
8072
- search: "\u041F\u043E\u0438\u0441\u043A",
8073
- empty: "\u041D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E",
8074
- 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",
8075
- loading: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026",
8076
- retry: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C",
8077
- clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
8078
- optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
8079
- changeFailed: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0432\u044B\u0431\u043E\u0440"
8080
- };
8081
- 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 }) {
8082
8043
  const {
8083
- size: sizeProp,
8084
- label,
8085
- required = false,
8086
- optional,
8087
- hint,
8088
- hintTone,
8089
- error,
8090
- invalid,
8091
- focusRing,
8092
- disabled: disabledProp = false,
8093
- placeholder,
8094
- id,
8095
- open,
8096
- defaultOpen = false,
8097
- onOpenChange,
8098
- closeOnEscape = true,
8099
- closeOnOutsideClick = true,
8100
- clearable = false,
8101
- name,
8102
- search,
8103
- defaultSearch = "",
8104
- onSearchChange,
8105
- filter = true,
8106
- loading = false,
8107
- loadingMore = false,
8108
- 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,
8109
8060
  onLoadMore,
8110
8061
  loadError,
8111
8062
  onRetry,
8112
- labels: labelsProp,
8113
- className,
8114
- children,
8115
- multiple: _multiple,
8116
- value: _value,
8117
- defaultValue: _defaultValue,
8118
- onValueChange: _onValueChange,
8119
- "aria-label": ariaLabel,
8120
- ...rest
8121
- } = props;
8122
- const multiple = props.multiple === true;
8123
- const tier = useHostTier(sizeProp);
8124
- const { size } = tier;
8125
- const disabled = useInheritedDisabled(disabledProp);
8126
- const labels = useLabels(SELECT_LABELS, labelsProp);
8127
- const ids = useFieldFrame(id, { label, hint, error, invalid, required });
8128
- const [stored, setStored] = useControllableState({
8129
- value: props.value,
8130
- defaultValue: props.defaultValue ?? (multiple ? [] : void 0)
8131
- });
8132
- const changes = usePendingChanges(stored, takeNext);
8133
- const value = changes.shown;
8134
- const saving = changes.pending.length > 0;
8135
- const [announcement, setAnnouncement] = React65.useState("");
8136
- const onValueChange = props.onValueChange;
8137
- const commit = (next) => {
8138
- if (saving || Object.is(next, value)) return;
8139
- const outcome = onValueChange?.(next);
8140
- if (!isPromiseLike(outcome)) {
8141
- setStored(next);
8142
- return;
8143
- }
8144
- setAnnouncement("");
8145
- changes.track(next, outcome, {
8146
- onResolve: () => setStored(next),
8147
- onReject: () => setAnnouncement(labels.changeFailed)
8148
- });
8149
- };
8150
- const commitRef = React65.useRef(commit);
8151
- commitRef.current = commit;
8152
- const selected = React65.useMemo(
8153
- () => Array.isArray(value) ? value : value ? [value] : [],
8154
- [value]
8155
- );
8156
- const [isOpen, setOpen] = useOpenState({ open, defaultOpen, onOpenChange, disabled });
8157
- const highlight = useCreateStore(void 0);
8158
- const registry = useListboxRegistry();
8159
- const [query, setQuery] = useControllableState({
8160
- value: search,
8161
- defaultValue: defaultSearch,
8162
- onChange: onSearchChange
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
8163
8085
  });
8164
- const triggerRef = React65.useRef(null);
8165
- const inSegment = React65.useContext(InputSegmentContext);
8166
- const segment = React65.useMemo(
8167
- () => inSegment ? { label: ariaLabel } : null,
8168
- [inSegment, ariaLabel]
8169
- );
8170
- const wasOpenRef = React65.useRef(isOpen);
8171
- React65.useEffect(() => {
8172
- if (wasOpenRef.current && !isOpen) setQuery("");
8173
- wasOpenRef.current = isOpen;
8174
- }, [isOpen, setQuery]);
8175
- const pick = React65.useCallback(
8176
- (optionValue) => {
8177
- if (multiple) {
8178
- const list = Array.isArray(value) ? value : [];
8179
- commitRef.current(
8180
- list.includes(optionValue) ? list.filter((item) => item !== optionValue) : [...list, optionValue]
8181
- );
8182
- return;
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();
8183
8107
  }
8184
- commitRef.current(optionValue);
8185
- setOpen(false);
8186
- },
8187
- [multiple, value, setOpen]
8188
- );
8189
- const clear = React65.useCallback(() => commitRef.current(multiple ? [] : ""), [multiple]);
8190
- const context = React65.useMemo(
8191
- () => ({
8192
- size,
8193
- invalid: ids.invalid,
8194
- focusRing,
8195
- required: ids.required,
8196
- disabled,
8197
- placeholder,
8198
- multiple,
8199
- selected,
8200
- registry,
8201
- pick,
8202
- clear,
8203
- clearable,
8204
- loading,
8205
- saving,
8206
- loadingMore,
8207
- hasMore,
8208
- onLoadMore,
8209
- loadError,
8210
- onRetry,
8211
- filter,
8212
- isOpen,
8213
- setOpen,
8214
- closeOnEscape,
8215
- closeOnOutsideClick,
8216
- highlight,
8217
- query,
8218
- setQuery,
8219
- triggerId: ids.controlId,
8220
- listboxId: `${ids.controlId}-listbox`,
8221
- describedBy: ids.describedBy,
8222
- triggerRef,
8223
- labels,
8224
- segment
8225
- }),
8226
- [
8227
- size,
8228
- ids.invalid,
8229
- ids.controlId,
8230
- ids.describedBy,
8231
- focusRing,
8232
- ids.required,
8233
- disabled,
8234
- placeholder,
8235
- multiple,
8236
- selected,
8237
- registry,
8238
- pick,
8239
- clear,
8240
- clearable,
8241
- loading,
8242
- saving,
8243
- loadingMore,
8244
- hasMore,
8245
- onLoadMore,
8246
- loadError,
8247
- onRetry,
8248
- filter,
8249
- isOpen,
8250
- setOpen,
8251
- closeOnEscape,
8252
- closeOnOutsideClick,
8253
- highlight,
8254
- query,
8255
- setQuery,
8256
- labels,
8257
- segment
8258
- ]
8259
- );
8260
- const body = /* @__PURE__ */ jsxs27(Fragment17, { children: [
8261
- /* @__PURE__ */ jsx42(SelectProvider, { value: context, children }),
8262
- name ? (selected.length > 0 || multiple ? selected : [""]).map((item) => /* @__PURE__ */ jsx42("input", { type: "hidden", name, value: item, disabled }, item)) : null,
8263
- /* @__PURE__ */ jsx42(VisuallyHidden, { live: "polite", children: announcement })
8264
- ] });
8265
- if (segment) {
8266
- return tier.provide(
8267
- /* @__PURE__ */ jsx42(
8268
- "div",
8269
- {
8270
- ...rest,
8271
- className: cx(Select_default.segment, className),
8272
- "data-field-segment": "",
8273
- "data-size": size,
8274
- children: body
8275
- }
8276
- )
8277
- );
8278
- }
8279
- return tier.provide(
8280
- /* @__PURE__ */ jsx42(
8281
- FieldFrame,
8282
- {
8283
- ...rest,
8284
- "aria-label": ariaLabel,
8285
- size,
8286
- ids,
8287
- label,
8288
- required,
8289
- optional,
8290
- hint,
8291
- hintTone,
8292
- error,
8293
- disabled,
8294
- optionalLabel: labels.optional,
8295
- className,
8296
- children: body
8108
+ return;
8109
+ }
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));
8297
8120
  }
8298
- )
8299
- );
8300
- }
8301
- SelectRoot.displayName = "Select.Root";
8302
- var takeNext = (_current, next) => next;
8303
- function SelectTrigger({
8304
- className,
8305
- children,
8306
- onClick: onClick2,
8307
- onKeyDown: onKeyDown2,
8308
- "aria-describedby": ariaDescribedBy,
8309
- ref,
8310
- ...rest
8311
- }) {
8312
- const {
8313
- isOpen,
8314
- setOpen,
8315
- triggerId,
8316
- listboxId,
8317
- disabled,
8318
- size,
8319
- invalid,
8320
- focusRing,
8321
- required,
8322
- describedBy,
8323
- triggerRef,
8324
- loading,
8325
- saving,
8326
- clearable,
8327
- selected,
8328
- clear,
8329
- labels,
8330
- registry,
8331
- segment
8332
- } = useSelectContext();
8333
- const mergedRef = useMergedRefs(triggerRef, ref);
8334
- useListboxView(registry);
8335
- const valueText = selected.map(registry.labelOf).join(", ");
8336
- const segmentName = segment?.label ? valueText ? `${segment.label}: ${valueText}` : segment.label : void 0;
8337
- const parts = React65.Children.toArray(children);
8338
- const iconOnly = parts.some((node) => React65.isValidElement(node) && node.type === SelectTriggerIcon) && !parts.some((node) => React65.isValidElement(node) && node.type === SelectValue);
8339
- const busy = loading || saving;
8340
- const showClear = clearable && selected.length > 0 && !disabled && !busy;
8341
- const clearPresence = usePartPresence({ present: showClear, axis: "inline" });
8342
- const toggle = floatingTriggerProps({ open: isOpen, setOpen, openOnArrow: true });
8343
- return /* @__PURE__ */ jsxs27(
8344
- "button",
8121
+ return;
8122
+ }
8123
+ const moved = handleListboxKeyDown(event, {
8124
+ ids,
8125
+ highlight,
8126
+ activate: (value) => registry.activate(value)
8127
+ });
8128
+ if (moved !== null) revealHighlighted(registry.nodeOf(moved));
8129
+ };
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,
8345
8134
  {
8346
8135
  ...rest,
8347
- ref: mergedRef,
8348
- id: triggerId,
8349
- type: "button",
8350
- role: "combobox",
8351
- "aria-expanded": toggle["aria-expanded"],
8352
- "aria-haspopup": "listbox",
8353
- "aria-controls": isOpen ? listboxId : void 0,
8354
- "aria-invalid": invalid || void 0,
8355
- "aria-required": required || void 0,
8356
- "aria-describedby": [ariaDescribedBy, describedBy].filter(Boolean).join(" ") || void 0,
8357
- "aria-busy": busy || void 0,
8358
- "aria-label": segmentName ?? rest["aria-label"],
8359
- disabled,
8360
- className: cx(
8361
- segment ? Select_default.segmentTrigger : cx(fieldTriggerClass, Select_default.trigger),
8362
- className
8363
- ),
8364
- onClick: (event) => {
8365
- onClick2?.(event);
8366
- if (!event.defaultPrevented) toggle.onClick();
8367
- },
8368
- onKeyDown: (event) => {
8369
- onKeyDown2?.(event);
8370
- if (event.defaultPrevented) return;
8371
- toggle.onKeyDown?.(event);
8372
- if (event.defaultPrevented) return;
8373
- if (event.key === " " || event.key === "Enter") {
8374
- event.preventDefault();
8375
- if (!isOpen) setOpen(true);
8376
- } else if (showClear && (event.key === "Delete" || event.key === "Backspace")) {
8377
- event.preventDefault();
8378
- clear();
8379
- }
8380
- },
8381
- ...toDataAttributes({
8382
- state: toggle["data-state"],
8383
- size,
8384
- invalid: invalid || void 0,
8385
- loading: busy || void 0,
8386
- disabled: disabled || void 0,
8387
- "focus-ring": focusRing,
8388
- "icon-only": iconOnly || void 0,
8389
- segment: segment ? true : void 0
8390
- }),
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 }),
8391
8141
  children: [
8392
- /* @__PURE__ */ jsxs27("span", { className: Select_default.triggerMain, children: [
8393
- children,
8394
- iconOnly ? /* @__PURE__ */ jsx42(SelectValue, { className: visuallyHiddenClass }) : null
8395
- ] }),
8396
- showClear ? (
8397
- // A segment, not a button: interactive content inside a <button> is invalid. The keyboard
8398
- // clears with Delete / Backspace on the trigger. A touch target in height, like the clear
8399
- // segment of a field (`FieldAction`).
8400
- /* @__PURE__ */ jsx42(
8401
- "span",
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,
8402
8174
  {
8403
- ref: clearPresence.ref,
8404
- className: cx(Select_default.clear, touchTargetBlockClass, clearPresence.className),
8405
- "aria-hidden": "true",
8406
- title: labels.clear,
8407
- "data-select-clear": "",
8408
- onMouseDown: (event) => event.preventDefault(),
8409
- onClick: (event) => {
8410
- event.stopPropagation();
8411
- clear();
8412
- },
8413
- children: /* @__PURE__ */ jsx42(Icon, { name: "action.close" })
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
+ ]
8414
8192
  }
8415
- )
8416
- ) : null,
8417
- /* @__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" }) }) })
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, {})
8418
8207
  ]
8419
8208
  }
8420
8209
  );
8421
8210
  }
8422
- SelectTrigger.displayName = "Select.Trigger";
8423
- function SelectValue({ renderValue, className, ...rest }) {
8424
- const { selected, registry, placeholder, multiple, size } = useSelectContext();
8425
- useListboxView(registry);
8426
- const text = selected.map(registry.labelOf).join(", ");
8427
- if (selected.length > 0 && renderValue && !multiple) {
8428
- const value = selected[0] ?? "";
8429
- const parts = splitItemChildren(renderValue({ value, label: text }));
8430
- return /* @__PURE__ */ jsxs27(
8431
- "span",
8432
- {
8433
- ...rest,
8434
- className: cx(Select_default.value, className),
8435
- ...toDataAttributes({
8436
- rich: parts.rich || void 0,
8437
- media: parts.leading.length > 0 || parts.meta.length > 0 || void 0
8438
- }),
8439
- children: [
8440
- sizeMedia(parts.leading, size),
8441
- /* @__PURE__ */ jsx42("span", { className: Select_default.valueBody, children: parts.body }),
8442
- parts.meta
8443
- ]
8444
- }
8445
- );
8446
- }
8447
- return /* @__PURE__ */ jsx42(
8448
- "span",
8449
- {
8450
- ...rest,
8451
- className: cx(Select_default.value, className),
8452
- ...toDataAttributes({ placeholder: selected.length === 0 || void 0 }),
8453
- children: selected.length > 0 ? text : placeholder
8454
- }
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;
8290
+ });
8291
+ React63.useLayoutEffect(
8292
+ () => () => {
8293
+ active2.current?.stop();
8294
+ active2.current = null;
8295
+ },
8296
+ []
8297
+ );
8298
+ }
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]
8391
+ );
8392
+ }
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]
8455
8400
  );
8456
8401
  }
8457
- SelectValue.displayName = "Select.Value";
8458
- function SelectTriggerIcon({ className, ...rest }) {
8459
- 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 }) });
8460
8411
  }
8461
- SelectTriggerIcon.displayName = "Select.TriggerIcon";
8462
- var LOADING_ROWS2 = 4;
8463
- var LOADING_MORE_ROWS = 2;
8464
- function SkeletonRows({ count }) {
8465
- return Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsx42(
8466
- "div",
8467
- {
8468
- "aria-hidden": "true",
8469
- className: cx(menu_default.item, menu_default.skeletonRow),
8470
- "data-skeleton": "",
8471
- children: /* @__PURE__ */ jsx42(Skeleton, {})
8472
- },
8473
- index
8474
- ));
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
+ ] });
8475
8421
  }
8476
- function SelectContent({ searchable = false, className, children, ...rest }) {
8477
- const {
8478
- isOpen,
8479
- setOpen,
8480
- closeOnEscape,
8481
- closeOnOutsideClick,
8482
- triggerId,
8483
- listboxId,
8484
- triggerRef,
8485
- highlight,
8486
- multiple,
8487
- size,
8488
- query,
8489
- setQuery,
8490
- loading,
8491
- saving,
8492
- loadingMore,
8493
- hasMore,
8494
- onLoadMore,
8495
- loadError,
8496
- onRetry,
8497
- filter,
8498
- labels,
8499
- registry
8500
- } = useSelectContext();
8501
- const listboxRef = React65.useRef(null);
8502
- const setListboxRef = useMergedRefs(listboxRef);
8503
- const items = [];
8504
- const actions = [];
8505
- for (const child of React65.Children.toArray(children)) {
8506
- (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));
8507
8439
  }
8508
- const actionsId = `${listboxId}-actions`;
8509
- const floating = useFloatingLayer({
8510
- open: isOpen,
8511
- onOpenChange: setOpen,
8512
- triggerRef,
8513
- closeOnEscape,
8514
- closeOnOutsideClick,
8515
- matchAnchorWidth: true,
8516
- focusOnOpen: true,
8517
- tabExit: "always",
8518
- sheet: true
8519
- });
8520
- const highlighted = useStoreSlice(highlight, (value) => value);
8521
- const view = useListboxView(registry, query, filter);
8522
- const isEmpty = view.matchCount === 0;
8523
- const typeahead = useTypeahead();
8524
- const region = hasContent(loadError) ? "error" : loading && isEmpty ? "loading" : "ready";
8525
- const { sentinelRef, request: requestMore } = useLoadMore({
8526
- enabled: region === "ready" && hasMore && Boolean(onLoadMore) && !loading && !loadingMore,
8527
- onLoadMore,
8528
- scrollRef: listboxRef,
8529
- round: view
8530
- });
8531
- const setSentinelRef = useMergedRefs(sentinelRef);
8532
- const lastOption = view.navigable.filter((id) => !isActionValue(id)).at(-1);
8533
- React65.useEffect(() => {
8534
- if (highlighted !== void 0 && highlighted === lastOption) requestMore();
8535
- }, [highlighted, lastOption, requestMore]);
8536
- const handleKeyDown = (event) => {
8537
- if (region === "error") {
8538
- if (event.key === "Enter" && onRetry && !(event.target instanceof HTMLButtonElement)) {
8539
- event.preventDefault();
8540
- onRetry();
8541
- }
8542
- return;
8543
- }
8544
- const inSearch = event.target instanceof HTMLInputElement;
8545
- if (inSearch && [" ", "Home", "End"].includes(event.key)) return;
8546
- const ids = view.navigable;
8547
- const printable = event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
8548
- if (printable && !inSearch && (event.key !== " " || typeahead.isTyping())) {
8549
- event.preventDefault();
8550
- const match = typeahead.find(event.key, ids, highlight.get(), registry.labelOf);
8551
- if (match !== void 0) {
8552
- highlight.set(match);
8553
- revealHighlighted(registry.nodeOf(match));
8554
- }
8555
- return;
8556
- }
8557
- const moved = handleListboxKeyDown(event, {
8558
- ids,
8559
- highlight,
8560
- activate: (value) => registry.activate(value)
8561
- });
8562
- 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)));
8563
8457
  };
8564
- if (!floating.mounted) return /* @__PURE__ */ jsx42("div", { hidden: true, children: items });
8565
- const activeDescendant = isOpen && highlighted !== void 0 ? optionDomId(listboxId, highlighted) : void 0;
8566
- return /* @__PURE__ */ jsxs27(
8567
- 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,
8568
8553
  {
8569
8554
  ...rest,
8570
- floating,
8571
- size,
8572
- className: cx(fieldTierClass, menu_default.tier, menu_default.menu, Select_default.content, className),
8573
- onKeyDown: handleKeyDown,
8574
- ...toDataAttributes({ searching: query !== "" || void 0 }),
8575
- children: [
8576
- searchable ? (
8577
- // The permanent focus of the panel: no ring, the caret is the indicator (foundation §7).
8578
- /* @__PURE__ */ jsxs27("div", { className: cx(menu_default.searchRow, Select_default.search), children: [
8579
- /* @__PURE__ */ jsx42(Icon, { name: "action.search", size: "s" }),
8580
- /* @__PURE__ */ jsx42(
8581
- "input",
8582
- {
8583
- type: "text",
8584
- className: menu_default.searchInput,
8585
- value: query,
8586
- placeholder: labels.search,
8587
- "aria-label": labels.search,
8588
- "aria-controls": region === "error" ? void 0 : listboxId,
8589
- "aria-activedescendant": activeDescendant,
8590
- "aria-autocomplete": "list",
8591
- autoComplete: "off",
8592
- spellCheck: false,
8593
- "data-autofocus": "",
8594
- onChange: (event) => setQuery(event.target.value)
8595
- }
8596
- )
8597
- ] })
8598
- ) : null,
8599
- /* @__PURE__ */ jsx42(RegionSwap, { state: region, fill: true, children: region === "error" ? /* @__PURE__ */ jsxs27(EmptyPage.Root, { layout: "compact", size, role: "alert", children: [
8600
- /* @__PURE__ */ jsx42(EmptyPage.Title, { as: "p", children: loadError }),
8601
- onRetry ? /* @__PURE__ */ jsx42(EmptyPage.Actions, { children: /* @__PURE__ */ jsxs27(Button.Root, { variant: "soft", tone: "neutral", onClick: onRetry, children: [
8602
- /* @__PURE__ */ jsx42(Button.Icon, { children: /* @__PURE__ */ jsx42(Icon, { name: "action.refresh" }) }),
8603
- labels.retry
8604
- ] }) }) : null
8605
- ] }) : /* @__PURE__ */ jsxs27(Fragment17, { children: [
8606
- /* @__PURE__ */ jsxs27(
8607
- ScrollContainer,
8608
- {
8609
- ref: setListboxRef,
8610
- id: listboxId,
8611
- role: "listbox",
8612
- "aria-multiselectable": multiple || void 0,
8613
- "aria-labelledby": triggerId,
8614
- "aria-activedescendant": searchable ? void 0 : activeDescendant,
8615
- "aria-busy": loading || loadingMore || saving || void 0,
8616
- "aria-owns": actions.length > 0 ? actionsId : void 0,
8617
- tabIndex: -1,
8618
- "data-autofocus": searchable ? void 0 : "",
8619
- className: Select_default.listbox,
8620
- children: [
8621
- items,
8622
- region === "loading" ? /* @__PURE__ */ jsx42(SkeletonRows, { count: LOADING_ROWS2 }) : null,
8623
- region === "ready" && hasMore ? /* @__PURE__ */ jsx42("div", { ref: setSentinelRef, "aria-hidden": "true", className: menu_default.loadSentinel }) : null,
8624
- region === "ready" && loadingMore ? /* @__PURE__ */ jsx42(SkeletonRows, { count: LOADING_MORE_ROWS }) : null
8625
- ]
8626
- }
8627
- ),
8628
- region === "ready" && isEmpty ? /* @__PURE__ */ jsxs27(EmptyPage.Root, { layout: "compact", size, role: "status", children: [
8629
- /* @__PURE__ */ jsx42(EmptyPage.Title, { as: "p", children: labels.empty }),
8630
- query !== "" && labels.emptyHint ? /* @__PURE__ */ jsx42(EmptyPage.Description, { children: labels.emptyHint }) : null
8631
- ] }) : null,
8632
- actions.length > 0 ? (
8633
- // Owned by the listbox (`aria-owns`): its options for assistive tech, pinned under
8634
- // the scroller and the empty state for the eye.
8635
- // biome-ignore lint/a11y/useSemanticElements: a group of options inside a listbox, not a form fieldset
8636
- /* @__PURE__ */ jsx42("div", { id: actionsId, role: "group", className: Select_default.actions, children: actions })
8637
- ) : null
8638
- ] }) }),
8639
- /* @__PURE__ */ jsx42(VisuallyHidden, { live: "polite", children: loading || loadingMore ? labels.loading : "" }),
8640
- /* @__PURE__ */ jsx42(HighlightOnOpen, {})
8641
- ]
8555
+ hues: mode === "palette",
8556
+ presets,
8557
+ palette,
8558
+ value,
8559
+ defaultValue: defaultValue ?? null,
8560
+ onValueChange
8642
8561
  }
8643
8562
  );
8644
8563
  }
8645
- SelectContent.displayName = "Select.Content";
8646
- function HighlightOnOpen() {
8647
- const { isOpen, query, filter, selected, registry, highlight } = useSelectContext();
8648
- const view = useListboxView(registry, query, filter);
8649
- const latest = React65.useRef({ query, filter, selected });
8650
- latest.current = { query, filter, selected };
8651
- React65.useLayoutEffect(() => {
8652
- if (!isOpen) return;
8653
- const { query: text, filter: filtered, selected: picked } = latest.current;
8654
- const first = registry.view(text, filtered).navigable.find((id) => picked.includes(id));
8655
- highlight.set(first);
8656
- if (first !== void 0) revealHighlighted(registry.nodeOf(first));
8657
- return () => highlight.set(void 0);
8658
- }, [isOpen, registry, highlight]);
8659
- const latestView = React65.useRef(view);
8660
- latestView.current = view;
8661
- React65.useLayoutEffect(() => {
8662
- if (query !== "") highlight.set(latestView.current.navigable[0]);
8663
- }, [query, highlight]);
8664
- React65.useLayoutEffect(() => {
8665
- if (query === "") return;
8666
- const current = highlight.get();
8667
- if (current === void 0 || isActionValue(current) || !view.navigable.includes(current)) {
8668
- 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
+ )
8669
8693
  }
8670
- }, [view, query, highlight]);
8671
- return null;
8672
- }
8673
- function SelectGroup({ className, ...rest }) {
8674
- return /* @__PURE__ */ jsx42(MenuGroup, { ...rest, className: cx(Select_default.group, className) });
8675
- }
8676
- SelectGroup.displayName = "Select.Group";
8677
- function SelectSeparator({ className, ...rest }) {
8678
- return /* @__PURE__ */ jsx42(Divider, { ...rest, className: cx(menu_default.separator, Select_default.separator, className) });
8694
+ );
8679
8695
  }
8680
- SelectSeparator.displayName = "Select.Separator";
8681
- var Select = {
8682
- Root: SelectRoot,
8683
- Trigger: SelectTrigger,
8684
- Value: SelectValue,
8685
- TriggerIcon: SelectTriggerIcon,
8686
- Content: SelectContent,
8687
- Item: SelectItem,
8688
- ItemIcon: SelectItemIcon,
8689
- ItemText: SelectItemText,
8690
- ItemDescription: SelectItemDescription,
8691
- ItemMeta: SelectItemMeta,
8692
- Group: SelectGroup,
8693
- Separator: SelectSeparator,
8694
- Action: SelectAction
8695
- };
8696
8696
 
8697
8697
  export {
8698
8698
  AnchorRectProvider,
@@ -8808,6 +8808,7 @@ export {
8808
8808
  rovingIndex,
8809
8809
  useImageStatus,
8810
8810
  Avatar,
8811
+ Skeleton,
8811
8812
  Label,
8812
8813
  Hint,
8813
8814
  FieldCellContext,
@@ -8834,9 +8835,10 @@ export {
8834
8835
  Thumbnail,
8835
8836
  RegionSwap,
8836
8837
  useSwapIn,
8837
- Popover,
8838
8838
  tooltipSurface_default,
8839
8839
  Tooltip,
8840
+ nodeText,
8841
+ Popover,
8840
8842
  FieldActionButton,
8841
8843
  FieldCopyButton,
8842
8844
  setControlValue,
@@ -8851,7 +8853,6 @@ export {
8851
8853
  isComposingKey,
8852
8854
  revealHighlighted,
8853
8855
  handleListboxKeyDown,
8854
- Skeleton,
8855
8856
  resolveValue,
8856
8857
  segmentFill,
8857
8858
  formatProgressValue,
@@ -8866,7 +8867,8 @@ export {
8866
8867
  getPasswordStrength,
8867
8868
  Input,
8868
8869
  EmptyPage,
8869
- nodeText,
8870
+ useLoadMore,
8871
+ Select,
8870
8872
  COLOR_PRESETS,
8871
8873
  useSwatchOptions,
8872
8874
  swatchClass,
@@ -8881,7 +8883,5 @@ export {
8881
8883
  sameColor,
8882
8884
  useBalancedColumns,
8883
8885
  useSwatchGrid,
8884
- ColorSwatches,
8885
- useLoadMore,
8886
- Select
8886
+ ColorSwatches
8887
8887
  };