@craftzbay/ui 0.10.0 → 0.11.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 (187) hide show
  1. package/README.md +14 -8
  2. package/dist-lib/__tests__/helpers/color.d.ts +9 -0
  3. package/dist-lib/__tests__/helpers/theme.d.ts +18 -0
  4. package/dist-lib/components/ui/Accordion.js +18 -7
  5. package/dist-lib/components/ui/Accordion.js.map +1 -1
  6. package/dist-lib/components/ui/Alert.d.ts +16 -0
  7. package/dist-lib/components/ui/Alert.js +47 -34
  8. package/dist-lib/components/ui/Alert.js.map +1 -1
  9. package/dist-lib/components/ui/Avatar.d.ts +1 -1
  10. package/dist-lib/components/ui/Avatar.js +45 -47
  11. package/dist-lib/components/ui/Avatar.js.map +1 -1
  12. package/dist-lib/components/ui/Badge.d.ts +3 -1
  13. package/dist-lib/components/ui/Badge.js +24 -15
  14. package/dist-lib/components/ui/Badge.js.map +1 -1
  15. package/dist-lib/components/ui/Breadcrumbs.d.ts +2 -0
  16. package/dist-lib/components/ui/Breadcrumbs.js +46 -28
  17. package/dist-lib/components/ui/Breadcrumbs.js.map +1 -1
  18. package/dist-lib/components/ui/Button.d.ts +5 -3
  19. package/dist-lib/components/ui/Button.js +59 -45
  20. package/dist-lib/components/ui/Button.js.map +1 -1
  21. package/dist-lib/components/ui/Calendar.d.ts +1 -1
  22. package/dist-lib/components/ui/Calendar.js +87 -59
  23. package/dist-lib/components/ui/Calendar.js.map +1 -1
  24. package/dist-lib/components/ui/Card.d.ts +2 -0
  25. package/dist-lib/components/ui/Card.js +48 -67
  26. package/dist-lib/components/ui/Card.js.map +1 -1
  27. package/dist-lib/components/ui/Carousel.d.ts +6 -6
  28. package/dist-lib/components/ui/Carousel.js +133 -102
  29. package/dist-lib/components/ui/Carousel.js.map +1 -1
  30. package/dist-lib/components/ui/Chart.d.ts +49 -10
  31. package/dist-lib/components/ui/Chart.js +415 -181
  32. package/dist-lib/components/ui/Chart.js.map +1 -1
  33. package/dist-lib/components/ui/Checkbox.js +42 -28
  34. package/dist-lib/components/ui/Checkbox.js.map +1 -1
  35. package/dist-lib/components/ui/Combobox.d.ts +2 -0
  36. package/dist-lib/components/ui/Combobox.js +142 -111
  37. package/dist-lib/components/ui/Combobox.js.map +1 -1
  38. package/dist-lib/components/ui/CommandPalette.d.ts +6 -3
  39. package/dist-lib/components/ui/CommandPalette.js +92 -87
  40. package/dist-lib/components/ui/CommandPalette.js.map +1 -1
  41. package/dist-lib/components/ui/ContextMenu.d.ts +7 -2
  42. package/dist-lib/components/ui/ContextMenu.js +77 -62
  43. package/dist-lib/components/ui/ContextMenu.js.map +1 -1
  44. package/dist-lib/components/ui/DataGrid.d.ts +17 -4
  45. package/dist-lib/components/ui/DataGrid.js +65 -50
  46. package/dist-lib/components/ui/DataGrid.js.map +1 -1
  47. package/dist-lib/components/ui/DatePicker.js +118 -99
  48. package/dist-lib/components/ui/DatePicker.js.map +1 -1
  49. package/dist-lib/components/ui/DesignSystemProvider.d.ts +94 -40
  50. package/dist-lib/components/ui/DesignSystemProvider.js +111 -55
  51. package/dist-lib/components/ui/DesignSystemProvider.js.map +1 -1
  52. package/dist-lib/components/ui/Dialog.d.ts +18 -3
  53. package/dist-lib/components/ui/Dialog.js +105 -80
  54. package/dist-lib/components/ui/Dialog.js.map +1 -1
  55. package/dist-lib/components/ui/Drawer.d.ts +17 -2
  56. package/dist-lib/components/ui/Drawer.js +89 -55
  57. package/dist-lib/components/ui/Drawer.js.map +1 -1
  58. package/dist-lib/components/ui/DropdownMenu.js +14 -9
  59. package/dist-lib/components/ui/DropdownMenu.js.map +1 -1
  60. package/dist-lib/components/ui/EmptyState.d.ts +2 -0
  61. package/dist-lib/components/ui/EmptyState.js +30 -16
  62. package/dist-lib/components/ui/EmptyState.js.map +1 -1
  63. package/dist-lib/components/ui/ErrorState.d.ts +13 -2
  64. package/dist-lib/components/ui/ErrorState.js +44 -23
  65. package/dist-lib/components/ui/ErrorState.js.map +1 -1
  66. package/dist-lib/components/ui/FileUpload.js +59 -56
  67. package/dist-lib/components/ui/FileUpload.js.map +1 -1
  68. package/dist-lib/components/ui/Form.d.ts +15 -2
  69. package/dist-lib/components/ui/Form.js +97 -71
  70. package/dist-lib/components/ui/Form.js.map +1 -1
  71. package/dist-lib/components/ui/Icon.d.ts +1 -1
  72. package/dist-lib/components/ui/Icon.js +20 -14
  73. package/dist-lib/components/ui/Icon.js.map +1 -1
  74. package/dist-lib/components/ui/IconButton.d.ts +2 -2
  75. package/dist-lib/components/ui/IconButton.js +28 -20
  76. package/dist-lib/components/ui/IconButton.js.map +1 -1
  77. package/dist-lib/components/ui/Input.d.ts +3 -1
  78. package/dist-lib/components/ui/Input.js +92 -78
  79. package/dist-lib/components/ui/Input.js.map +1 -1
  80. package/dist-lib/components/ui/Kbd.js +1 -1
  81. package/dist-lib/components/ui/Kbd.js.map +1 -1
  82. package/dist-lib/components/ui/MultiSelect.js +121 -107
  83. package/dist-lib/components/ui/MultiSelect.js.map +1 -1
  84. package/dist-lib/components/ui/Pagination.js +67 -62
  85. package/dist-lib/components/ui/Pagination.js.map +1 -1
  86. package/dist-lib/components/ui/Popover.js +14 -14
  87. package/dist-lib/components/ui/Popover.js.map +1 -1
  88. package/dist-lib/components/ui/Progress.d.ts +3 -3
  89. package/dist-lib/components/ui/Progress.js +77 -72
  90. package/dist-lib/components/ui/Progress.js.map +1 -1
  91. package/dist-lib/components/ui/RadioGroup.d.ts +1 -1
  92. package/dist-lib/components/ui/RadioGroup.js +69 -52
  93. package/dist-lib/components/ui/RadioGroup.js.map +1 -1
  94. package/dist-lib/components/ui/RelativeTime.d.ts +19 -0
  95. package/dist-lib/components/ui/RelativeTime.js +31 -0
  96. package/dist-lib/components/ui/RelativeTime.js.map +1 -0
  97. package/dist-lib/components/ui/ScrollArea.d.ts +9 -1
  98. package/dist-lib/components/ui/ScrollArea.js +43 -27
  99. package/dist-lib/components/ui/ScrollArea.js.map +1 -1
  100. package/dist-lib/components/ui/Select.d.ts +6 -1
  101. package/dist-lib/components/ui/Select.js +79 -71
  102. package/dist-lib/components/ui/Select.js.map +1 -1
  103. package/dist-lib/components/ui/Separator.js +1 -1
  104. package/dist-lib/components/ui/Separator.js.map +1 -1
  105. package/dist-lib/components/ui/Sheet.d.ts +9 -0
  106. package/dist-lib/components/ui/Sheet.js +69 -46
  107. package/dist-lib/components/ui/Sheet.js.map +1 -1
  108. package/dist-lib/components/ui/Sidebar.d.ts +12 -9
  109. package/dist-lib/components/ui/Sidebar.js +152 -109
  110. package/dist-lib/components/ui/Sidebar.js.map +1 -1
  111. package/dist-lib/components/ui/Skeleton.d.ts +13 -2
  112. package/dist-lib/components/ui/Skeleton.js +15 -14
  113. package/dist-lib/components/ui/Skeleton.js.map +1 -1
  114. package/dist-lib/components/ui/Slider.js +41 -29
  115. package/dist-lib/components/ui/Slider.js.map +1 -1
  116. package/dist-lib/components/ui/Snackbar.js +23 -22
  117. package/dist-lib/components/ui/Snackbar.js.map +1 -1
  118. package/dist-lib/components/ui/Spinner.js +18 -6
  119. package/dist-lib/components/ui/Spinner.js.map +1 -1
  120. package/dist-lib/components/ui/Stepper.d.ts +6 -0
  121. package/dist-lib/components/ui/Stepper.js +71 -48
  122. package/dist-lib/components/ui/Stepper.js.map +1 -1
  123. package/dist-lib/components/ui/Switch.js +46 -43
  124. package/dist-lib/components/ui/Switch.js.map +1 -1
  125. package/dist-lib/components/ui/Table.d.ts +33 -5
  126. package/dist-lib/components/ui/Table.js +141 -119
  127. package/dist-lib/components/ui/Table.js.map +1 -1
  128. package/dist-lib/components/ui/Tabs.js +50 -48
  129. package/dist-lib/components/ui/Tabs.js.map +1 -1
  130. package/dist-lib/components/ui/TagInput.js +45 -45
  131. package/dist-lib/components/ui/TagInput.js.map +1 -1
  132. package/dist-lib/components/ui/Textarea.js +65 -54
  133. package/dist-lib/components/ui/Textarea.js.map +1 -1
  134. package/dist-lib/components/ui/Timeline.js +39 -35
  135. package/dist-lib/components/ui/Timeline.js.map +1 -1
  136. package/dist-lib/components/ui/Toast.js +44 -57
  137. package/dist-lib/components/ui/Toast.js.map +1 -1
  138. package/dist-lib/components/ui/Tooltip.d.ts +4 -1
  139. package/dist-lib/components/ui/Tooltip.js +24 -22
  140. package/dist-lib/components/ui/Tooltip.js.map +1 -1
  141. package/dist-lib/components/ui/TopNav.d.ts +7 -3
  142. package/dist-lib/components/ui/TopNav.js +35 -25
  143. package/dist-lib/components/ui/TopNav.js.map +1 -1
  144. package/dist-lib/components/ui/Tree.d.ts +15 -10
  145. package/dist-lib/components/ui/Tree.js +82 -79
  146. package/dist-lib/components/ui/Tree.js.map +1 -1
  147. package/dist-lib/hooks/use-debounce.d.ts +19 -0
  148. package/dist-lib/hooks/use-debounce.js +36 -0
  149. package/dist-lib/hooks/use-debounce.js.map +1 -0
  150. package/dist-lib/hooks/use-delayed-loading.d.ts +21 -0
  151. package/dist-lib/hooks/use-delayed-loading.js +20 -0
  152. package/dist-lib/hooks/use-delayed-loading.js.map +1 -0
  153. package/dist-lib/hooks/use-field-ids.d.ts +2 -1
  154. package/dist-lib/hooks/use-field-ids.js +9 -9
  155. package/dist-lib/hooks/use-field-ids.js.map +1 -1
  156. package/dist-lib/hooks/use-media-query.d.ts +3 -1
  157. package/dist-lib/hooks/use-media-query.js +16 -12
  158. package/dist-lib/hooks/use-media-query.js.map +1 -1
  159. package/dist-lib/hooks/use-modifier-key.d.ts +13 -0
  160. package/dist-lib/hooks/use-modifier-key.js +19 -0
  161. package/dist-lib/hooks/use-modifier-key.js.map +1 -0
  162. package/dist-lib/hooks/use-toast.d.ts +7 -2
  163. package/dist-lib/hooks/use-toast.js +61 -30
  164. package/dist-lib/hooks/use-toast.js.map +1 -1
  165. package/dist-lib/icons/index.d.ts +9 -0
  166. package/dist-lib/icons/index.js +148 -130
  167. package/dist-lib/icons/index.js.map +1 -1
  168. package/dist-lib/illustrations/index.d.ts +1 -0
  169. package/dist-lib/illustrations/index.js +15 -6
  170. package/dist-lib/illustrations/index.js.map +1 -1
  171. package/dist-lib/index.d.ts +6 -0
  172. package/dist-lib/index.js +280 -260
  173. package/dist-lib/index.js.map +1 -1
  174. package/dist-lib/lib/format.d.ts +65 -0
  175. package/dist-lib/lib/format.js +95 -0
  176. package/dist-lib/lib/format.js.map +1 -0
  177. package/dist-lib/lib/return-focus.d.ts +11 -0
  178. package/dist-lib/lib/return-focus.js +12 -0
  179. package/dist-lib/lib/return-focus.js.map +1 -0
  180. package/dist-lib/lib/strings.d.ts +62 -1
  181. package/dist-lib/lib/strings.js +75 -19
  182. package/dist-lib/lib/strings.js.map +1 -1
  183. package/dist-lib/lib/strings.mn.js +50 -5
  184. package/dist-lib/lib/strings.mn.js.map +1 -1
  185. package/dist-lib/styles.css +1 -1
  186. package/dist-lib/theme.css +141 -78
  187. package/package.json +10 -3
@@ -1,69 +1,72 @@
1
1
  "use client";
2
2
  import { jsxs as n, jsx as t } from "react/jsx-runtime";
3
- import { forwardRef as Z, useState as w, useRef as y, useEffect as _, useMemo as F, useCallback as O } from "react";
4
- import * as f from "@radix-ui/react-popover";
5
- import { Command as p } from "cmdk";
6
- import { X as P, ChevronsUpDown as $, Check as ee } from "../../icons/index.js";
7
- import { cn as i } from "../../lib/utils.js";
8
- import { useStrings as te } from "../../hooks/use-strings.js";
9
- import { formatString as re } from "../../lib/strings.js";
10
- import { useFieldIds as oe } from "../../hooks/use-field-ids.js";
11
- const ne = Z(function({
3
+ import { forwardRef as Y, useState as N, useRef as O, useCallback as k, useMemo as P } from "react";
4
+ import * as g from "@radix-ui/react-popover";
5
+ import { Command as b } from "cmdk";
6
+ import { X as j, ChevronsUpDown as Z, Check as _ } from "../../icons/index.js";
7
+ import { cn as a } from "../../lib/utils.js";
8
+ import { useStrings as ee } from "../../hooks/use-strings.js";
9
+ import { formatString as te } from "../../lib/strings.js";
10
+ import { useFieldIds as re } from "../../hooks/use-field-ids.js";
11
+ const oe = Y(function({
12
12
  options: l,
13
13
  value: r,
14
14
  onChange: s,
15
- label: N,
15
+ label: d,
16
16
  helperText: h,
17
17
  error: x,
18
18
  placeholder: B,
19
- emptyText: E,
20
- maxVisibleChips: L = 3,
21
- clearable: M = !0,
22
- disabled: d,
23
- id: j,
19
+ emptyText: L,
20
+ maxVisibleChips: M = 3,
21
+ clearable: E = !0,
22
+ disabled: c,
23
+ id: S,
24
24
  className: K
25
25
  }, U) {
26
- const c = te(), q = B ?? c.multiSelect.placeholder, H = E ?? c.multiSelect.empty, g = !!x, { fieldId: k, helperId: Q, errorId: X, describedBy: G } = oe(j, {
26
+ const i = ee(), z = B ?? i.multiSelect.placeholder, $ = L ?? i.multiSelect.empty, v = !!x, { fieldId: u, helperId: q, errorId: H, describedBy: Q } = re(S, {
27
27
  hasHelper: !!h,
28
- hasError: g
29
- }), [a, u] = w(!1), [m, J] = w(""), S = y(null), C = y(null), z = y(null), [T, V] = w(void 0);
30
- _(() => {
31
- var e;
32
- a && V((e = z.current) == null ? void 0 : e.id);
33
- }, [a]);
34
- const b = F(() => l.filter((e) => r.includes(e.value)), [l, r]), I = O(
28
+ hasError: v
29
+ }), [f, m] = N(!1), [p, X] = N(""), C = O(null), I = O(null), [G, J] = N(void 0), T = k((e) => J(e == null ? void 0 : e.id), []), w = P(() => l.filter((e) => r.includes(e.value)), [l, r]), D = k(
35
30
  (e) => {
36
31
  r.includes(e) ? s(r.filter((o) => o !== e)) : s([...r, e]);
37
32
  },
38
33
  [r, s]
39
- ), W = O(() => s([]), [s]), Y = (e) => {
40
- e.key === "Backspace" && m === "" && r.length > 0 ? s(r.slice(0, -1)) : (e.key === "ArrowDown" || e.key === "ArrowUp") && !a && u(!0);
41
- }, D = F(
42
- () => l.filter((e) => e.label.toLowerCase().includes(m.toLowerCase())),
43
- [l, m]
44
- ), v = b.slice(0, L), R = b.length - v.length;
45
- return /* @__PURE__ */ n("div", { ref: U, className: i("flex flex-col gap-1.5", K), children: [
46
- N && /* @__PURE__ */ t("label", { htmlFor: k, className: "text-foreground text-sm font-medium", children: N }),
47
- /* @__PURE__ */ t(p, { shouldFilter: !1, className: "flex w-full flex-col", children: /* @__PURE__ */ n(f.Root, { open: a, onOpenChange: u, children: [
48
- /* @__PURE__ */ t(f.Anchor, { asChild: !0, children: /* @__PURE__ */ n(
34
+ ), V = k(() => s([]), [s]), W = (e) => {
35
+ e.key === "Backspace" && p === "" && r.length > 0 ? s(r.slice(0, -1)) : (e.key === "ArrowDown" || e.key === "ArrowUp") && !f && m(!0);
36
+ }, R = P(
37
+ () => l.filter((e) => e.label.toLowerCase().includes(p.toLowerCase())),
38
+ [l, p]
39
+ ), y = w.slice(0, M), A = w.length - y.length;
40
+ return /* @__PURE__ */ n("div", { ref: U, className: a("flex flex-col gap-1.5", K), children: [
41
+ d && /* @__PURE__ */ t(
42
+ "label",
43
+ {
44
+ id: `${u}-label`,
45
+ htmlFor: u,
46
+ className: "text-foreground text-sm font-medium",
47
+ children: d
48
+ }
49
+ ),
50
+ /* @__PURE__ */ t(b, { shouldFilter: !1, className: "flex w-full flex-col", children: /* @__PURE__ */ n(g.Root, { open: f, onOpenChange: m, children: [
51
+ /* @__PURE__ */ t(g.Anchor, { asChild: !0, children: /* @__PURE__ */ n(
49
52
  "div",
50
53
  {
51
- ref: C,
52
- "aria-disabled": d || void 0,
53
- className: i(
54
+ ref: I,
55
+ "aria-disabled": c || void 0,
56
+ className: a(
54
57
  "bg-card flex h-9 w-full cursor-text items-center gap-1.5 overflow-hidden rounded-md border px-2 py-1 text-sm",
55
58
  "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]",
56
59
  "focus-within:ring-offset-background focus-within:ring-2 focus-within:ring-offset-2",
57
- g ? "border-danger focus-within:border-danger focus-within:ring-danger" : "border-border focus-within:border-accent focus-within:ring-ring",
58
- d && "pointer-events-none opacity-50"
60
+ v ? "border-danger focus-within:border-danger focus-within:ring-danger" : "border-border-input focus-within:border-accent focus-within:ring-ring",
61
+ c && "pointer-events-none opacity-50"
59
62
  ),
60
63
  onClick: () => {
61
64
  var e;
62
- (e = S.current) == null || e.focus(), d || u(!0);
65
+ (e = C.current) == null || e.focus(), c || m(!0);
63
66
  },
64
67
  children: [
65
68
  /* @__PURE__ */ n("div", { className: "flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden", children: [
66
- v.map((e) => /* @__PURE__ */ n(
69
+ y.map((e) => /* @__PURE__ */ n(
67
70
  "span",
68
71
  {
69
72
  className: "bg-accent-soft text-on-accent-soft inline-flex max-w-[10rem] shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-xs font-medium",
@@ -73,70 +76,73 @@ const ne = Z(function({
73
76
  "button",
74
77
  {
75
78
  type: "button",
76
- "aria-label": re(c.multiSelect.remove, { label: e.label }),
77
- className: "text-on-accent-soft hover:text-foreground focus-visible:ring-ring inline-flex items-center rounded-sm outline-none focus-visible:ring-2",
79
+ "aria-label": te(i.multiSelect.remove, { label: e.label }),
80
+ className: "text-on-accent-soft hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background relative inline-flex items-center rounded-sm outline-none before:absolute before:-inset-1.5 before:content-[''] focus-visible:ring-2 focus-visible:ring-offset-1",
78
81
  onClick: (o) => {
79
- o.stopPropagation(), I(e.value);
82
+ o.stopPropagation(), D(e.value);
80
83
  },
81
- children: /* @__PURE__ */ t(P, { className: "size-3", "aria-hidden": !0 })
84
+ children: /* @__PURE__ */ t(j, { className: "size-3", "aria-hidden": !0 })
82
85
  }
83
86
  )
84
87
  ]
85
88
  },
86
89
  e.value
87
90
  )),
88
- R > 0 && /* @__PURE__ */ n("span", { className: "bg-background-muted text-foreground-muted shrink-0 rounded-md px-1.5 py-0.5 text-xs font-medium", children: [
91
+ A > 0 && /* @__PURE__ */ n("span", { className: "bg-background-muted text-foreground-muted shrink-0 rounded-md px-1.5 py-0.5 text-xs font-medium", children: [
89
92
  "+",
90
- R
93
+ A
91
94
  ] }),
92
95
  /* @__PURE__ */ t(
93
96
  "input",
94
97
  {
95
- ref: S,
96
- id: k,
98
+ ref: C,
99
+ id: u,
97
100
  type: "text",
98
101
  autoComplete: "off",
99
- value: m,
100
- onChange: (e) => J(e.target.value),
101
- onFocus: () => u(!0),
102
- onKeyDown: Y,
103
- placeholder: v.length === 0 ? q : void 0,
102
+ value: p,
103
+ onChange: (e) => X(e.target.value),
104
+ onFocus: () => m(!0),
105
+ onKeyDown: W,
106
+ placeholder: y.length === 0 ? z : void 0,
104
107
  role: "combobox",
105
- "aria-expanded": a,
106
- "aria-controls": a ? T : void 0,
108
+ "aria-expanded": f,
109
+ "aria-controls": f ? G : void 0,
107
110
  "aria-haspopup": "listbox",
108
111
  "aria-autocomplete": "list",
109
- "aria-invalid": g || void 0,
110
- "aria-describedby": G,
111
- className: "placeholder:text-foreground-subtle min-w-[6ch] flex-1 bg-transparent text-sm outline-none",
112
- disabled: d
112
+ "aria-labelledby": d ? `${u}-label` : void 0,
113
+ "aria-label": d || S ? void 0 : z,
114
+ "aria-invalid": v || void 0,
115
+ "aria-describedby": Q,
116
+ className: "placeholder:text-foreground-subtle min-w-[6ch] flex-1 bg-transparent text-lg outline-none md:text-sm",
117
+ disabled: c
113
118
  }
114
119
  )
115
120
  ] }),
116
121
  /* @__PURE__ */ n("span", { className: "flex shrink-0 items-center gap-1 pl-1", children: [
117
- M && b.length > 0 && /* @__PURE__ */ t(
122
+ E && w.length > 0 && /* @__PURE__ */ t(
118
123
  "button",
119
124
  {
120
125
  type: "button",
121
- "aria-label": c.multiSelect.clearAll,
126
+ "aria-label": i.multiSelect.clearAll,
122
127
  onClick: (e) => {
123
- e.stopPropagation(), W();
128
+ e.stopPropagation(), V();
124
129
  },
125
- className: "text-foreground-subtle hover:text-foreground focus-visible:ring-ring rounded-sm outline-none focus-visible:ring-2",
126
- children: /* @__PURE__ */ t(P, { className: "size-4", "aria-hidden": !0 })
130
+ className: "text-foreground-subtle hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background inline-flex size-6 shrink-0 items-center justify-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
131
+ children: /* @__PURE__ */ t(j, { className: "size-4", "aria-hidden": !0 })
127
132
  }
128
133
  ),
129
- /* @__PURE__ */ t($, { className: "text-foreground-subtle size-4", "aria-hidden": !0 })
134
+ /* @__PURE__ */ t(Z, { className: "text-foreground-subtle size-4", "aria-hidden": !0 })
130
135
  ] })
131
136
  ]
132
137
  }
133
138
  ) }),
134
- /* @__PURE__ */ t(f.Portal, { children: /* @__PURE__ */ t(
135
- f.Content,
139
+ /* @__PURE__ */ t(g.Portal, { children: /* @__PURE__ */ t(
140
+ g.Content,
136
141
  {
137
142
  align: "start",
138
143
  sideOffset: 4,
139
- className: i(
144
+ "aria-label": i.command.suggestions,
145
+ className: a(
140
146
  "border-border bg-popover text-popover-foreground z-[var(--z-popover)] w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-lg border shadow-md",
141
147
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
142
148
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
@@ -144,53 +150,61 @@ const ne = Z(function({
144
150
  ),
145
151
  onOpenAutoFocus: (e) => e.preventDefault(),
146
152
  onInteractOutside: (e) => {
147
- var A;
153
+ var F;
148
154
  const o = e.target;
149
- o && ((A = C.current) != null && A.contains(o)) && e.preventDefault();
155
+ o && ((F = I.current) != null && F.contains(o)) && e.preventDefault();
150
156
  },
151
- children: /* @__PURE__ */ n(p.List, { ref: z, className: "max-h-64 overflow-y-auto p-1", children: [
152
- D.map((e) => {
153
- const o = r.includes(e.value);
154
- return /* @__PURE__ */ n(
155
- p.Item,
156
- {
157
- value: e.value,
158
- disabled: e.disabled,
159
- onSelect: () => I(e.value),
160
- className: i(
161
- "text-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm",
162
- "data-[selected=true]:bg-background-muted",
163
- "data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50"
164
- ),
165
- children: [
166
- /* @__PURE__ */ t(
167
- "span",
168
- {
169
- "aria-hidden": !0,
170
- className: i(
171
- "flex size-4 items-center justify-center rounded-sm border",
172
- o ? "border-accent bg-accent text-on-accent" : "border-border"
157
+ children: /* @__PURE__ */ n(
158
+ b.List,
159
+ {
160
+ ref: T,
161
+ label: i.command.suggestions,
162
+ className: "max-h-64 overflow-y-auto p-1",
163
+ children: [
164
+ R.map((e) => {
165
+ const o = r.includes(e.value);
166
+ return /* @__PURE__ */ n(
167
+ b.Item,
168
+ {
169
+ value: e.value,
170
+ disabled: e.disabled,
171
+ onSelect: () => D(e.value),
172
+ className: a(
173
+ "text-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm",
174
+ "data-[selected=true]:bg-background-muted",
175
+ "data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50"
176
+ ),
177
+ children: [
178
+ /* @__PURE__ */ t(
179
+ "span",
180
+ {
181
+ "aria-hidden": !0,
182
+ className: a(
183
+ "flex size-4 items-center justify-center rounded-sm border",
184
+ o ? "border-accent bg-accent text-on-accent" : "border-border-input"
185
+ ),
186
+ children: o && /* @__PURE__ */ t(_, { className: "size-3", "aria-hidden": !0 })
187
+ }
173
188
  ),
174
- children: o && /* @__PURE__ */ t(ee, { className: "size-3", "aria-hidden": !0 })
175
- }
176
- ),
177
- /* @__PURE__ */ t("span", { className: "flex-1", children: e.label }),
178
- e.description && /* @__PURE__ */ t("span", { className: "text-foreground-subtle text-xs", children: e.description })
179
- ]
180
- },
181
- e.value
182
- );
183
- }),
184
- D.length === 0 && /* @__PURE__ */ t(p.Empty, { className: "text-foreground-subtle px-2 py-6 text-center text-sm", children: H })
185
- ] })
189
+ /* @__PURE__ */ t("span", { className: "flex-1", children: e.label }),
190
+ e.description && /* @__PURE__ */ t("span", { className: "text-foreground-subtle text-xs", children: e.description })
191
+ ]
192
+ },
193
+ e.value
194
+ );
195
+ }),
196
+ R.length === 0 && /* @__PURE__ */ t(b.Empty, { className: "text-foreground-subtle px-2 py-6 text-center text-sm", children: $ })
197
+ ]
198
+ }
199
+ )
186
200
  }
187
201
  ) })
188
202
  ] }) }),
189
- x ? /* @__PURE__ */ t("p", { id: X, role: "alert", className: "text-danger-text text-xs", children: x }) : h ? /* @__PURE__ */ t("p", { id: Q, className: "text-foreground-subtle text-xs", children: h }) : null
203
+ x ? /* @__PURE__ */ t("p", { id: H, className: "text-danger-text text-xs", children: x }) : h ? /* @__PURE__ */ t("p", { id: q, className: "text-foreground-subtle text-xs", children: h }) : null
190
204
  ] });
191
205
  });
192
- ne.displayName = "MultiSelect";
206
+ oe.displayName = "MultiSelect";
193
207
  export {
194
- ne as MultiSelect
208
+ oe as MultiSelect
195
209
  };
196
210
  //# sourceMappingURL=MultiSelect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MultiSelect.js","sources":["../../../src/components/ui/MultiSelect.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport { Command as CommandPrimitive } from 'cmdk';\nimport { Check, ChevronsUpDown, X } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { formatString } from '@/lib/strings';\nimport { useFieldIds } from '@/hooks/use-field-ids';\n\nexport interface MultiSelectOption {\n /** Stable, unique value submitted in `onChange`. */\n value: string;\n /** Visible label shown both in the menu and in the selected chip. */\n label: string;\n /** Optional secondary text shown after the label in the menu. */\n description?: string;\n /** Disable selecting this option. */\n disabled?: boolean;\n}\n\nexport interface MultiSelectProps {\n /** All possible options. */\n options: MultiSelectOption[];\n /** Currently selected values. Controlled. */\n value: string[];\n /** Called whenever the selection changes. */\n onChange: (next: string[]) => void;\n /** Visible label above the field. */\n label?: ReactNode;\n /** Hint below the field. Hidden when `error` is set. */\n helperText?: ReactNode;\n /** Validation message. */\n error?: ReactNode;\n /** Empty-state placeholder shown when nothing is selected. */\n placeholder?: string;\n /** Text shown when no options match the search. */\n emptyText?: string;\n /** Max number of chips rendered inline; remainder shown as \"+N more\". */\n maxVisibleChips?: number;\n /** Whether the user can clear all selections with a single click. */\n clearable?: boolean;\n /** Disable the entire field. */\n disabled?: boolean;\n /** Consumer-supplied id for the search input (label association). */\n id?: string;\n className?: string;\n}\n\n/**\n * Chip-based multi-select with a searchable menu (cmdk under the hood).\n *\n * Keyboard:\n * - Backspace on the input with empty query removes the last chip\n * - ArrowUp / ArrowDown move the highlight, Enter toggles the highlighted option\n * - Escape closes the menu\n *\n * @example Tag picker\n * <MultiSelect label=\"Tags\"\n * options={tags}\n * value={selected}\n * onChange={setSelected}\n * placeholder=\"Pick tags\" />\n *\n * @example Bounded with overflow chip\n * <MultiSelect options={users}\n * value={value}\n * onChange={setValue}\n * maxVisibleChips={3} />\n *\n * @do Cap `maxVisibleChips` (3–5) on narrow surfaces so the field doesn't\n * reflow as the user adds selections.\n * @dont Use MultiSelect for fewer than ~6 options. CheckboxGroup is clearer.\n */\nexport const MultiSelect = forwardRef<HTMLDivElement, MultiSelectProps>(function MultiSelect(\n {\n options,\n value,\n onChange,\n label,\n helperText,\n error,\n placeholder: placeholderProp,\n emptyText: emptyTextProp,\n maxVisibleChips = 3,\n clearable = true,\n disabled,\n id,\n className,\n },\n ref,\n) {\n const strings = useStrings();\n const placeholder = placeholderProp ?? strings.multiSelect.placeholder;\n const emptyText = emptyTextProp ?? strings.multiSelect.empty;\n const isError = Boolean(error);\n const { fieldId, helperId, errorId, describedBy } = useFieldIds(id, {\n hasHelper: Boolean(helperText),\n hasError: isError,\n });\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n const fieldRef = useRef<HTMLDivElement>(null);\n // cmdk assigns its own id to the list (ours is ignored), so read it back\n // once the portal mounts to keep aria-controls truthful.\n const listRef = useRef<HTMLDivElement>(null);\n const [listId, setListId] = useState<string | undefined>(undefined);\n useEffect(() => {\n if (open) setListId(listRef.current?.id);\n }, [open]);\n\n const selected = useMemo(() => options.filter((o) => value.includes(o.value)), [options, value]);\n\n const toggle = useCallback(\n (v: string) => {\n if (value.includes(v)) onChange(value.filter((x) => x !== v));\n else onChange([...value, v]);\n },\n [value, onChange],\n );\n\n const clear = useCallback(() => onChange([]), [onChange]);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Backspace' && query === '' && value.length > 0) {\n onChange(value.slice(0, -1));\n } else if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && !open) {\n setOpen(true);\n }\n };\n\n const filtered = useMemo(\n () => options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase())),\n [options, query],\n );\n\n const visibleChips = selected.slice(0, maxVisibleChips);\n const overflow = selected.length - visibleChips.length;\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-1.5', className)}>\n {label && (\n <label htmlFor={fieldId} className=\"text-foreground text-sm font-medium\">\n {label}\n </label>\n )}\n\n {/* The Command root wraps the whole field so cmdk's root keydown handler\n (ArrowUp/Down/Enter) sees the input even though the list is portaled.\n A plain <input> is used instead of Command.Input because cmdk forces\n its own id / aria-* on that element, breaking the label association. */}\n <CommandPrimitive shouldFilter={false} className=\"flex w-full flex-col\">\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n <PopoverPrimitive.Anchor asChild>\n {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- click-to-focus wrapper; the <input role=\"combobox\"> inside owns keyboard handling */}\n <div\n ref={fieldRef}\n aria-disabled={disabled || undefined}\n className={cn(\n 'bg-card flex h-9 w-full cursor-text items-center gap-1.5 overflow-hidden rounded-md border px-2 py-1 text-sm',\n 'transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'focus-within:ring-offset-background focus-within:ring-2 focus-within:ring-offset-2',\n isError\n ? 'border-danger focus-within:border-danger focus-within:ring-danger'\n : 'border-border focus-within:border-accent focus-within:ring-ring',\n disabled && 'pointer-events-none opacity-50',\n )}\n onClick={() => {\n inputRef.current?.focus();\n if (!disabled) setOpen(true);\n }}\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden\">\n {visibleChips.map((opt) => (\n <span\n key={opt.value}\n className=\"bg-accent-soft text-on-accent-soft inline-flex max-w-[10rem] shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-xs font-medium\"\n >\n <span className=\"truncate\" title={opt.label}>\n {opt.label}\n </span>\n <button\n type=\"button\"\n aria-label={formatString(strings.multiSelect.remove, { label: opt.label })}\n className=\"text-on-accent-soft hover:text-foreground focus-visible:ring-ring inline-flex items-center rounded-sm outline-none focus-visible:ring-2\"\n onClick={(e) => {\n e.stopPropagation();\n toggle(opt.value);\n }}\n >\n <X className=\"size-3\" aria-hidden />\n </button>\n </span>\n ))}\n {overflow > 0 && (\n <span className=\"bg-background-muted text-foreground-muted shrink-0 rounded-md px-1.5 py-0.5 text-xs font-medium\">\n +{overflow}\n </span>\n )}\n <input\n ref={inputRef}\n id={fieldId}\n type=\"text\"\n autoComplete=\"off\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onFocus={() => setOpen(true)}\n onKeyDown={handleKeyDown}\n placeholder={visibleChips.length === 0 ? placeholder : undefined}\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={open ? listId : undefined}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-invalid={isError || undefined}\n aria-describedby={describedBy}\n className=\"placeholder:text-foreground-subtle min-w-[6ch] flex-1 bg-transparent text-sm outline-none\"\n disabled={disabled}\n />\n </div>\n <span className=\"flex shrink-0 items-center gap-1 pl-1\">\n {clearable && selected.length > 0 && (\n <button\n type=\"button\"\n aria-label={strings.multiSelect.clearAll}\n onClick={(e) => {\n e.stopPropagation();\n clear();\n }}\n className=\"text-foreground-subtle hover:text-foreground focus-visible:ring-ring rounded-sm outline-none focus-visible:ring-2\"\n >\n <X className=\"size-4\" aria-hidden />\n </button>\n )}\n <ChevronsUpDown className=\"text-foreground-subtle size-4\" aria-hidden />\n </span>\n </div>\n </PopoverPrimitive.Anchor>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n align=\"start\"\n sideOffset={4}\n className={cn(\n 'border-border bg-popover text-popover-foreground z-[var(--z-popover)] w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-lg border shadow-md',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',\n )}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onInteractOutside={(e) => {\n // Clicks inside the anchor (chips, clear) must not close the menu.\n const target = e.target as Node | null;\n if (target && fieldRef.current?.contains(target)) e.preventDefault();\n }}\n >\n <CommandPrimitive.List ref={listRef} className=\"max-h-64 overflow-y-auto p-1\">\n {filtered.map((opt) => {\n const isSelected = value.includes(opt.value);\n return (\n <CommandPrimitive.Item\n key={opt.value}\n value={opt.value}\n disabled={opt.disabled}\n onSelect={() => toggle(opt.value)}\n className={cn(\n 'text-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm',\n 'data-[selected=true]:bg-background-muted',\n 'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',\n )}\n >\n <span\n aria-hidden\n className={cn(\n 'flex size-4 items-center justify-center rounded-sm border',\n isSelected ? 'border-accent bg-accent text-on-accent' : 'border-border',\n )}\n >\n {isSelected && <Check className=\"size-3\" aria-hidden />}\n </span>\n <span className=\"flex-1\">{opt.label}</span>\n {opt.description && (\n <span className=\"text-foreground-subtle text-xs\">{opt.description}</span>\n )}\n </CommandPrimitive.Item>\n );\n })}\n {filtered.length === 0 && (\n <CommandPrimitive.Empty className=\"text-foreground-subtle px-2 py-6 text-center text-sm\">\n {emptyText}\n </CommandPrimitive.Empty>\n )}\n </CommandPrimitive.List>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n </CommandPrimitive>\n\n {error ? (\n <p id={errorId} role=\"alert\" className=\"text-danger-text text-xs\">\n {error}\n </p>\n ) : helperText ? (\n <p id={helperId} className=\"text-foreground-subtle text-xs\">\n {helperText}\n </p>\n ) : null}\n </div>\n );\n});\n\nMultiSelect.displayName = 'MultiSelect';\n"],"names":["MultiSelect","forwardRef","options","value","onChange","label","helperText","error","placeholderProp","emptyTextProp","maxVisibleChips","clearable","disabled","id","className","ref","strings","useStrings","placeholder","emptyText","isError","fieldId","helperId","errorId","describedBy","useFieldIds","open","setOpen","useState","query","setQuery","inputRef","useRef","fieldRef","listRef","listId","setListId","useEffect","_a","selected","useMemo","o","toggle","useCallback","v","x","clear","handleKeyDown","filtered","visibleChips","overflow","cn","jsx","CommandPrimitive","jsxs","PopoverPrimitive","opt","formatString","e","X","ChevronsUpDown","target","isSelected","Check"],"mappings":"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"}
1
+ {"version":3,"file":"MultiSelect.js","sources":["../../../src/components/ui/MultiSelect.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport { Command as CommandPrimitive } from 'cmdk';\nimport { Check, ChevronsUpDown, X } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { formatString } from '@/lib/strings';\nimport { useFieldIds } from '@/hooks/use-field-ids';\n\nexport interface MultiSelectOption {\n /** Stable, unique value submitted in `onChange`. */\n value: string;\n /** Visible label shown both in the menu and in the selected chip. */\n label: string;\n /** Optional secondary text shown after the label in the menu. */\n description?: string;\n /** Disable selecting this option. */\n disabled?: boolean;\n}\n\nexport interface MultiSelectProps {\n /** All possible options. */\n options: MultiSelectOption[];\n /** Currently selected values. Controlled. */\n value: string[];\n /** Called whenever the selection changes. */\n onChange: (next: string[]) => void;\n /** Visible label above the field. */\n label?: ReactNode;\n /** Hint below the field. Hidden when `error` is set. */\n helperText?: ReactNode;\n /** Validation message. */\n error?: ReactNode;\n /** Empty-state placeholder shown when nothing is selected. */\n placeholder?: string;\n /** Text shown when no options match the search. */\n emptyText?: string;\n /** Max number of chips rendered inline; remainder shown as \"+N more\". */\n maxVisibleChips?: number;\n /** Whether the user can clear all selections with a single click. */\n clearable?: boolean;\n /** Disable the entire field. */\n disabled?: boolean;\n /** Consumer-supplied id for the search input (label association). */\n id?: string;\n className?: string;\n}\n\n/**\n * Chip-based multi-select with a searchable menu (cmdk under the hood).\n *\n * Keyboard:\n * - Backspace on the input with empty query removes the last chip\n * - ArrowUp / ArrowDown move the highlight, Enter toggles the highlighted option\n * - Escape closes the menu\n *\n * @example Tag picker\n * <MultiSelect label=\"Tags\"\n * options={tags}\n * value={selected}\n * onChange={setSelected}\n * placeholder=\"Pick tags\" />\n *\n * @example Bounded with overflow chip\n * <MultiSelect options={users}\n * value={value}\n * onChange={setValue}\n * maxVisibleChips={3} />\n *\n * @do Cap `maxVisibleChips` (3–5) on narrow surfaces so the field doesn't\n * reflow as the user adds selections.\n * @dont Use MultiSelect for fewer than ~6 options. CheckboxGroup is clearer.\n */\nexport const MultiSelect = forwardRef<HTMLDivElement, MultiSelectProps>(function MultiSelect(\n {\n options,\n value,\n onChange,\n label,\n helperText,\n error,\n placeholder: placeholderProp,\n emptyText: emptyTextProp,\n maxVisibleChips = 3,\n clearable = true,\n disabled,\n id,\n className,\n },\n ref,\n) {\n const strings = useStrings();\n const placeholder = placeholderProp ?? strings.multiSelect.placeholder;\n const emptyText = emptyTextProp ?? strings.multiSelect.empty;\n const isError = Boolean(error);\n const { fieldId, helperId, errorId, describedBy } = useFieldIds(id, {\n hasHelper: Boolean(helperText),\n hasError: isError,\n });\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n const fieldRef = useRef<HTMLDivElement>(null);\n // cmdk assigns its own id to the list (ours is ignored), so read it back\n // from the node once the portal mounts to keep aria-controls truthful.\n const [listId, setListId] = useState<string | undefined>(undefined);\n const listRef = useCallback((el: HTMLDivElement | null) => setListId(el?.id), []);\n\n const selected = useMemo(() => options.filter((o) => value.includes(o.value)), [options, value]);\n\n const toggle = useCallback(\n (v: string) => {\n if (value.includes(v)) onChange(value.filter((x) => x !== v));\n else onChange([...value, v]);\n },\n [value, onChange],\n );\n\n const clear = useCallback(() => onChange([]), [onChange]);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Backspace' && query === '' && value.length > 0) {\n onChange(value.slice(0, -1));\n } else if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && !open) {\n setOpen(true);\n }\n };\n\n const filtered = useMemo(\n () => options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase())),\n [options, query],\n );\n\n const visibleChips = selected.slice(0, maxVisibleChips);\n const overflow = selected.length - visibleChips.length;\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-1.5', className)}>\n {label && (\n <label\n id={`${fieldId}-label`}\n htmlFor={fieldId}\n className=\"text-foreground text-sm font-medium\"\n >\n {label}\n </label>\n )}\n\n {/* The Command root wraps the whole field so cmdk's root keydown handler\n (ArrowUp/Down/Enter) sees the input even though the list is portaled.\n A plain <input> is used instead of Command.Input because cmdk forces\n its own id / aria-* on that element, breaking the label association. */}\n <CommandPrimitive shouldFilter={false} className=\"flex w-full flex-col\">\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n <PopoverPrimitive.Anchor asChild>\n {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- click-to-focus wrapper; the <input role=\"combobox\"> inside owns keyboard handling */}\n <div\n ref={fieldRef}\n aria-disabled={disabled || undefined}\n className={cn(\n 'bg-card flex h-9 w-full cursor-text items-center gap-1.5 overflow-hidden rounded-md border px-2 py-1 text-sm',\n 'transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'focus-within:ring-offset-background focus-within:ring-2 focus-within:ring-offset-2',\n isError\n ? 'border-danger focus-within:border-danger focus-within:ring-danger'\n : 'border-border-input focus-within:border-accent focus-within:ring-ring',\n disabled && 'pointer-events-none opacity-50',\n )}\n onClick={() => {\n inputRef.current?.focus();\n if (!disabled) setOpen(true);\n }}\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden\">\n {visibleChips.map((opt) => (\n <span\n key={opt.value}\n className=\"bg-accent-soft text-on-accent-soft inline-flex max-w-[10rem] shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-xs font-medium\"\n >\n <span className=\"truncate\" title={opt.label}>\n {opt.label}\n </span>\n <button\n type=\"button\"\n aria-label={formatString(strings.multiSelect.remove, { label: opt.label })}\n className=\"text-on-accent-soft hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background relative inline-flex items-center rounded-sm outline-none before:absolute before:-inset-1.5 before:content-[''] focus-visible:ring-2 focus-visible:ring-offset-1\"\n onClick={(e) => {\n e.stopPropagation();\n toggle(opt.value);\n }}\n >\n <X className=\"size-3\" aria-hidden />\n </button>\n </span>\n ))}\n {overflow > 0 && (\n <span className=\"bg-background-muted text-foreground-muted shrink-0 rounded-md px-1.5 py-0.5 text-xs font-medium\">\n +{overflow}\n </span>\n )}\n <input\n ref={inputRef}\n id={fieldId}\n type=\"text\"\n autoComplete=\"off\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onFocus={() => setOpen(true)}\n onKeyDown={handleKeyDown}\n placeholder={visibleChips.length === 0 ? placeholder : undefined}\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={open ? listId : undefined}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n // Unlabelled field: name the input after the placeholder. A\n // consumer `id` implies an external <label htmlFor>.\n aria-labelledby={label ? `${fieldId}-label` : undefined}\n aria-label={label || id ? undefined : placeholder}\n aria-invalid={isError || undefined}\n aria-describedby={describedBy}\n className=\"placeholder:text-foreground-subtle min-w-[6ch] flex-1 bg-transparent text-lg outline-none md:text-sm\"\n disabled={disabled}\n />\n </div>\n <span className=\"flex shrink-0 items-center gap-1 pl-1\">\n {clearable && selected.length > 0 && (\n <button\n type=\"button\"\n aria-label={strings.multiSelect.clearAll}\n onClick={(e) => {\n e.stopPropagation();\n clear();\n }}\n className=\"text-foreground-subtle hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background inline-flex size-6 shrink-0 items-center justify-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-offset-2\"\n >\n <X className=\"size-4\" aria-hidden />\n </button>\n )}\n <ChevronsUpDown className=\"text-foreground-subtle size-4\" aria-hidden />\n </span>\n </div>\n </PopoverPrimitive.Anchor>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n align=\"start\"\n sideOffset={4}\n // Radix gives the content role=\"dialog\"; a dialog needs a name.\n aria-label={strings.command.suggestions}\n className={cn(\n 'border-border bg-popover text-popover-foreground z-[var(--z-popover)] w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-lg border shadow-md',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',\n )}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onInteractOutside={(e) => {\n // Clicks inside the anchor (chips, clear) must not close the menu.\n const target = e.target as Node | null;\n if (target && fieldRef.current?.contains(target)) e.preventDefault();\n }}\n >\n <CommandPrimitive.List\n ref={listRef}\n label={strings.command.suggestions}\n className=\"max-h-64 overflow-y-auto p-1\"\n >\n {filtered.map((opt) => {\n const isSelected = value.includes(opt.value);\n return (\n <CommandPrimitive.Item\n key={opt.value}\n value={opt.value}\n disabled={opt.disabled}\n onSelect={() => toggle(opt.value)}\n className={cn(\n 'text-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm',\n 'data-[selected=true]:bg-background-muted',\n 'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',\n )}\n >\n <span\n aria-hidden\n className={cn(\n 'flex size-4 items-center justify-center rounded-sm border',\n isSelected\n ? 'border-accent bg-accent text-on-accent'\n : 'border-border-input',\n )}\n >\n {isSelected && <Check className=\"size-3\" aria-hidden />}\n </span>\n <span className=\"flex-1\">{opt.label}</span>\n {opt.description && (\n <span className=\"text-foreground-subtle text-xs\">{opt.description}</span>\n )}\n </CommandPrimitive.Item>\n );\n })}\n {filtered.length === 0 && (\n <CommandPrimitive.Empty className=\"text-foreground-subtle px-2 py-6 text-center text-sm\">\n {emptyText}\n </CommandPrimitive.Empty>\n )}\n </CommandPrimitive.List>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n </CommandPrimitive>\n\n {error ? (\n <p id={errorId} className=\"text-danger-text text-xs\">\n {error}\n </p>\n ) : helperText ? (\n <p id={helperId} className=\"text-foreground-subtle text-xs\">\n {helperText}\n </p>\n ) : null}\n </div>\n );\n});\n\nMultiSelect.displayName = 'MultiSelect';\n"],"names":["MultiSelect","forwardRef","options","value","onChange","label","helperText","error","placeholderProp","emptyTextProp","maxVisibleChips","clearable","disabled","id","className","ref","strings","useStrings","placeholder","emptyText","isError","fieldId","helperId","errorId","describedBy","useFieldIds","open","setOpen","useState","query","setQuery","inputRef","useRef","fieldRef","listId","setListId","listRef","useCallback","el","selected","useMemo","o","toggle","v","x","clear","handleKeyDown","filtered","visibleChips","overflow","cn","jsx","CommandPrimitive","jsxs","PopoverPrimitive","_a","opt","formatString","e","X","ChevronsUpDown","target","isSelected","Check"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
1
  "use client";
2
- import { jsxs as f, jsx as i } from "react/jsx-runtime";
3
- import { forwardRef as R, useId as S, useMemo as F } from "react";
4
- import { ChevronsLeft as A, ChevronLeft as B, ChevronRight as T, ChevronsRight as V } from "../../icons/index.js";
2
+ import { jsxs as d, jsx as i } from "react/jsx-runtime";
3
+ import { forwardRef as A, useId as B, useMemo as E } from "react";
4
+ import { ChevronsLeft as T, ChevronLeft as V, ChevronRight as _, ChevronsRight as $ } from "../../icons/index.js";
5
5
  import { cn as g } from "../../lib/utils.js";
6
- import { useStrings as _ } from "../../hooks/use-strings.js";
7
- import { defaultStrings as $, formatString as h } from "../../lib/strings.js";
8
- import { Select as q, SelectTrigger as z, SelectContent as D, SelectItem as E } from "./Select.js";
9
- function p(r) {
6
+ import { useStrings as q } from "../../hooks/use-strings.js";
7
+ import { defaultStrings as z, formatString as h } from "../../lib/strings.js";
8
+ import { Select as D, SelectTrigger as G, SelectContent as H, SelectItem as K } from "./Select.js";
9
+ function y(r) {
10
10
  return {
11
- showing: (e, a, c) => h(r.showing, { from: e, to: a, total: c }),
11
+ showing: (e, t, c) => h(r.showing, { from: e, to: t, total: c }),
12
12
  rowsPerPage: r.rowsPerPage,
13
13
  first: r.first,
14
14
  last: r.last,
@@ -19,61 +19,61 @@ function p(r) {
19
19
  nav: r.nav
20
20
  };
21
21
  }
22
- const Z = p(
23
- $.pagination
22
+ const ee = y(
23
+ z.pagination
24
24
  );
25
- function G(r, e, a = 7) {
26
- if (e <= a) return Array.from({ length: e }, (l, m) => m + 1);
27
- const c = 1, t = [], s = Math.max(2, r - c), d = Math.min(e - 1, r + c);
28
- t.push(1), s > 2 && t.push("gap");
29
- for (let l = s; l <= d; l++) t.push(l);
30
- return d < e - 1 && t.push("gap"), t.push(e), t;
25
+ function Q(r, e, t = 7) {
26
+ if (e <= t) return Array.from({ length: e }, (l, f) => f + 1);
27
+ const c = 1, s = [], a = Math.max(2, r - c), u = Math.min(e - 1, r + c);
28
+ s.push(1), a > 2 && s.push("gap");
29
+ for (let l = a; l <= u; l++) s.push(l);
30
+ return u < e - 1 && s.push("gap"), s.push(e), s;
31
31
  }
32
- const H = R(function({
32
+ const U = A(function({
33
33
  page: e,
34
- pageCount: a,
34
+ pageCount: t,
35
35
  onPageChange: c,
36
- totalItems: t,
37
- pageSize: s,
38
- pageSizeOptions: d,
36
+ totalItems: s,
37
+ pageSize: a,
38
+ pageSizeOptions: u,
39
39
  onPageSizeChange: l,
40
- showJump: m = !0,
41
- labels: w,
42
- className: y,
43
- "aria-label": P,
44
- ...k
45
- }, C) {
46
- const j = _(), o = { ...p(j.pagination), ...w }, v = S(), L = F(() => G(e, a), [e, a]), x = s ? (e - 1) * s + 1 : void 0, N = s && t ? Math.min(e * s, t) : void 0, u = (n) => {
47
- n < 1 || n > a || n === e || c(n);
40
+ showJump: f = !0,
41
+ labels: P,
42
+ className: j,
43
+ "aria-label": C,
44
+ ...L
45
+ }, M) {
46
+ const R = q(), o = { ...y(R.pagination), ...P }, v = B(), S = E(() => Q(e, t), [e, t]), x = !s || t <= 0, N = a === void 0 ? void 0 : x ? 0 : (e - 1) * a + 1, p = a === void 0 || s === void 0 ? void 0 : x ? 0 : Math.min(e * a, s), k = e <= 1 || t <= 0, w = e >= t, m = (n) => {
47
+ n < 1 || n > t || n === e || c(n);
48
48
  };
49
- return /* @__PURE__ */ f(
49
+ return /* @__PURE__ */ d(
50
50
  "nav",
51
51
  {
52
- ref: C,
53
- "aria-label": P ?? o.nav,
54
- className: g("flex flex-wrap items-center justify-between gap-3", y),
55
- ...k,
52
+ ref: M,
53
+ "aria-label": C ?? o.nav,
54
+ className: g("flex flex-wrap items-center justify-between gap-3", j),
55
+ ...L,
56
56
  children: [
57
- /* @__PURE__ */ f("div", { className: "text-foreground-muted flex items-center gap-3 text-sm", children: [
58
- t !== void 0 && s !== void 0 && x !== void 0 && N !== void 0 && /* @__PURE__ */ i("span", { className: "tabular", children: o.showing(x, N, t) }),
59
- d && l && s !== void 0 && /* @__PURE__ */ f("div", { className: "flex items-center gap-2", children: [
57
+ /* @__PURE__ */ d("div", { className: "text-foreground-muted flex items-center gap-3 text-sm", children: [
58
+ s !== void 0 && a !== void 0 && N !== void 0 && p !== void 0 && /* @__PURE__ */ i("span", { className: "tabular", children: o.showing(N, p, s) }),
59
+ u && l && a !== void 0 && /* @__PURE__ */ d("div", { className: "flex items-center gap-2", children: [
60
60
  /* @__PURE__ */ i("label", { htmlFor: v, className: "sr-only", children: o.rowsPerPage }),
61
- /* @__PURE__ */ f(q, { value: String(s), onValueChange: (n) => l(Number(n)), children: [
62
- /* @__PURE__ */ i(z, { id: v, size: "sm", className: "w-[7.5rem] whitespace-nowrap" }),
63
- /* @__PURE__ */ i(D, { children: d.map((n) => /* @__PURE__ */ i(E, { value: String(n), children: o.perPage(n) }, n)) })
61
+ /* @__PURE__ */ d(D, { value: String(a), onValueChange: (n) => l(Number(n)), children: [
62
+ /* @__PURE__ */ i(G, { id: v, size: "sm", className: "w-[7.5rem] whitespace-nowrap" }),
63
+ /* @__PURE__ */ i(H, { children: u.map((n) => /* @__PURE__ */ i(K, { value: String(n), children: o.perPage(n) }, n)) })
64
64
  ] })
65
65
  ] })
66
66
  ] }),
67
- /* @__PURE__ */ f("ul", { className: "flex items-center gap-1", children: [
68
- m && /* @__PURE__ */ i("li", { children: /* @__PURE__ */ i(
67
+ /* @__PURE__ */ d("ul", { className: "flex items-center gap-1", children: [
68
+ f && /* @__PURE__ */ i("li", { className: "hidden sm:block", children: /* @__PURE__ */ i(
69
69
  "button",
70
70
  {
71
71
  type: "button",
72
72
  "aria-label": o.first,
73
- disabled: e === 1,
74
- onClick: () => u(1),
73
+ disabled: k,
74
+ onClick: () => m(1),
75
75
  className: b,
76
- children: /* @__PURE__ */ i(A, { className: "size-4", "aria-hidden": !0 })
76
+ children: /* @__PURE__ */ i(T, { className: "size-4", "aria-hidden": !0 })
77
77
  }
78
78
  ) }),
79
79
  /* @__PURE__ */ i("li", { children: /* @__PURE__ */ i(
@@ -81,20 +81,25 @@ const H = R(function({
81
81
  {
82
82
  type: "button",
83
83
  "aria-label": o.prev,
84
- disabled: e === 1,
85
- onClick: () => u(e - 1),
84
+ disabled: k,
85
+ onClick: () => m(e - 1),
86
86
  className: b,
87
- children: /* @__PURE__ */ i(B, { className: "size-4", "aria-hidden": !0 })
87
+ children: /* @__PURE__ */ i(V, { className: "size-4", "aria-hidden": !0 })
88
88
  }
89
89
  ) }),
90
- L.map(
91
- (n, M) => n === "gap" ? /* @__PURE__ */ i("li", { className: "text-foreground-subtle px-2", children: "…" }, `gap-${M}`) : /* @__PURE__ */ i("li", { children: /* @__PURE__ */ i(
90
+ /* @__PURE__ */ d("li", { className: "tabular text-foreground-muted px-2 text-sm sm:hidden", "aria-current": "page", children: [
91
+ e,
92
+ " / ",
93
+ t
94
+ ] }),
95
+ S.map(
96
+ (n, F) => n === "gap" ? /* @__PURE__ */ i("li", { className: "text-foreground-subtle hidden px-2 sm:block", children: "…" }, `gap-${F}`) : /* @__PURE__ */ i("li", { className: "hidden sm:block", children: /* @__PURE__ */ i(
92
97
  "button",
93
98
  {
94
99
  type: "button",
95
100
  "aria-label": o.page(n),
96
101
  "aria-current": n === e ? "page" : void 0,
97
- onClick: () => u(n),
102
+ onClick: () => m(n),
98
103
  className: g(
99
104
  "tabular inline-flex size-8 items-center justify-center rounded-md text-sm outline-none",
100
105
  "transition-colors duration-[var(--duration-fast)]",
@@ -110,21 +115,21 @@ const H = R(function({
110
115
  {
111
116
  type: "button",
112
117
  "aria-label": o.next,
113
- disabled: e === a,
114
- onClick: () => u(e + 1),
118
+ disabled: w,
119
+ onClick: () => m(e + 1),
115
120
  className: b,
116
- children: /* @__PURE__ */ i(T, { className: "size-4", "aria-hidden": !0 })
121
+ children: /* @__PURE__ */ i(_, { className: "size-4", "aria-hidden": !0 })
117
122
  }
118
123
  ) }),
119
- m && /* @__PURE__ */ i("li", { children: /* @__PURE__ */ i(
124
+ f && /* @__PURE__ */ i("li", { className: "hidden sm:block", children: /* @__PURE__ */ i(
120
125
  "button",
121
126
  {
122
127
  type: "button",
123
128
  "aria-label": o.last,
124
- disabled: e === a,
125
- onClick: () => u(a),
129
+ disabled: w,
130
+ onClick: () => m(t),
126
131
  className: b,
127
- children: /* @__PURE__ */ i(V, { className: "size-4", "aria-hidden": !0 })
132
+ children: /* @__PURE__ */ i($, { className: "size-4", "aria-hidden": !0 })
128
133
  }
129
134
  ) })
130
135
  ] })
@@ -132,7 +137,7 @@ const H = R(function({
132
137
  }
133
138
  );
134
139
  });
135
- H.displayName = "Pagination";
140
+ U.displayName = "Pagination";
136
141
  const b = g(
137
142
  "inline-flex size-8 items-center justify-center rounded-md text-foreground-muted",
138
143
  "transition-colors duration-[var(--duration-fast)]",
@@ -141,8 +146,8 @@ const b = g(
141
146
  "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
142
147
  );
143
148
  export {
144
- H as Pagination,
145
- Z as defaultPaginationLabels,
146
- p as paginationLabelsFromStrings
149
+ U as Pagination,
150
+ ee as defaultPaginationLabels,
151
+ y as paginationLabelsFromStrings
147
152
  };
148
153
  //# sourceMappingURL=Pagination.js.map