@nextlyhq/ui 0.0.2-alpha.6 → 0.0.2-alpha.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,55 +1,56 @@
1
- import { Slot } from '@radix-ui/react-slot';
2
- import { cva } from 'class-variance-authority';
3
- import * as React5 from 'react';
4
- import { forwardRef, createContext, useContext } from 'react';
5
- import { clsx } from 'clsx';
6
- import { twMerge } from 'tailwind-merge';
7
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { Root as Root$3 } from '@radix-ui/react-label';
9
- import * as SeparatorPrimitive from '@radix-ui/react-separator';
10
- import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
11
- import { Minus, Check, ChevronDown, X, ChevronRight, Circle, Search, Loader2, ChevronUp, XCircle, AlertTriangle, AlertCircle, CheckCircle2, FileQuestion, ChevronsLeft, ChevronLeft, ChevronsRight } from 'lucide-react';
12
- import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
13
- import { Root as Root$4, Thumb } from '@radix-ui/react-switch';
14
- import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
15
- import * as AccordionPrimitive from '@radix-ui/react-accordion';
16
- import { Root, Image, Fallback } from '@radix-ui/react-avatar';
17
- import { List, Trigger, Content, Root as Root$1 } from '@radix-ui/react-tabs';
18
- import { Content as Content$1, Root as Root$2, Provider, Trigger as Trigger$1 } from '@radix-ui/react-tooltip';
19
- import * as PopoverPrimitive from '@radix-ui/react-popover';
20
- import * as DialogPrimitive from '@radix-ui/react-dialog';
21
- import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
22
- import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
23
- import * as SelectPrimitive from '@radix-ui/react-select';
24
- import { Command as Command$1 } from 'cmdk';
25
- import { Toaster as Toaster$1 } from 'sonner';
26
- export { toast } from 'sonner';
1
+ "use client";
27
2
 
28
3
  // src/components/button.tsx
4
+ import { Slot } from "@radix-ui/react-slot";
5
+ import { cva } from "class-variance-authority";
6
+ import * as React from "react";
7
+ import { forwardRef } from "react";
8
+
9
+ // src/lib/utils.ts
10
+ import { clsx } from "clsx";
11
+ import { twMerge } from "tailwind-merge";
29
12
  function cn(...inputs) {
30
13
  return twMerge(clsx(inputs));
31
14
  }
15
+
16
+ // src/components/button.tsx
17
+ import { jsx } from "react/jsx-runtime";
32
18
  var buttonVariants = cva(
33
- "inline-flex items-center justify-center whitespace-nowrap rounded-none text-sm font-medium cursor-pointer transition-all duration-150 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed active:scale-[0.98] [&_svg]:text-current",
19
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-all duration-150 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed active:scale-[0.98] [&_svg]:text-current",
34
20
  {
35
21
  variants: {
36
22
  variant: {
37
23
  default: "bg-primary text-primary-foreground border border-transparent hover:opacity-90",
38
24
  primary: "bg-primary text-primary-foreground border border-transparent hover:opacity-90",
39
- destructive: "bg-destructive text-destructive-foreground border border-transparent hover:opacity-90",
40
- outline: "border border-primary/10 text-foreground hover-unified bg-background",
41
- secondary: "bg-background border border-primary/10 text-foreground hover:bg-primary/5",
25
+ // Solid fill uses the emphasis token so on-color text stays AA in dark
26
+ // mode (the base token is the readable text color, too light here).
27
+ // Hover darkens to a deeper shade rather than opacity-90, which would
28
+ // composite the fill toward the page and drop the label under 4.5:1.
29
+ // One step, not two: the label is white in light mode and black in
30
+ // dark, so mixing the fill toward black moves it away from the label in
31
+ // one mode and into it in the other. `-600` clears both (5.92:1 light,
32
+ // 5.67:1 dark); `-700` reads at 3.70:1 against the dark label.
33
+ destructive: "bg-destructive-solid text-destructive-foreground border border-transparent hover:bg-destructive-600",
34
+ // border-border is the decorative separator token, and it is the right
35
+ // one here: a button is identified by its label and fill, so its edge
36
+ // carries no meaning on its own, unlike border-input, which is the
37
+ // token for controls identified by their boundary (that token is now
38
+ // below 1.4.11's 3:1 in light mode; see contrast/accepted.ts). It is
39
+ // still used in preference to a faint primary alpha, which reads as a
40
+ // tint of the brand colour rather than as an edge.
41
+ outline: "border border-border text-foreground hover-unified bg-background",
42
+ secondary: "bg-background border border-border text-foreground hover:bg-primary/5",
42
43
  ghost: "text-foreground border border-transparent hover-unified",
43
44
  link: "text-primary border border-transparent underline-offset-4 hover:underline"
44
45
  },
45
46
  size: {
46
- default: "h-10 px-6 py-2",
47
- sm: "h-9 px-4 text-[13px]",
48
- md: "h-10 px-6 text-sm",
49
- lg: "h-11 px-8 text-base",
50
- icon: "h-10 w-10 p-0",
51
- "icon-sm": "h-9 w-9 p-0",
52
- "icon-lg": "h-11 w-11 p-0"
47
+ default: "h-[var(--nx-control-height)] px-6 py-2",
48
+ sm: "h-[var(--nx-control-height-md)] px-4 text-sm",
49
+ md: "h-[var(--nx-control-height)] px-6 text-sm",
50
+ lg: "h-[var(--nx-control-height-lg)] px-8 text-base",
51
+ icon: "h-[var(--nx-control-height)] w-[var(--nx-control-height)] p-0",
52
+ "icon-sm": "h-[var(--nx-control-height-md)] w-[var(--nx-control-height-md)] p-0",
53
+ "icon-lg": "h-[var(--nx-control-height-lg)] w-[var(--nx-control-height-lg)] p-0"
53
54
  }
54
55
  },
55
56
  defaultVariants: {
@@ -68,7 +69,7 @@ var Button = forwardRef(
68
69
  ...props
69
70
  }, ref) => {
70
71
  const Comp = asChild ? Slot : "button";
71
- const hasMultipleChildren = React5.Children.count(children) > 1;
72
+ const hasMultipleChildren = React.Children.count(children) > 1;
72
73
  return /* @__PURE__ */ jsx(
73
74
  Comp,
74
75
  {
@@ -85,14 +86,30 @@ var Button = forwardRef(
85
86
  }
86
87
  );
87
88
  Button.displayName = "Button";
88
- var inputVariants = cva(
89
- "file:text-foreground placeholder:text-muted-foreground placeholder:opacity-50 selection:bg-primary selection:text-primary-foreground w-full min-w-0 rounded-none border border-input bg-background text-sm transition-all duration-150 outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus:ring-0 focus:ring-offset-0 focus:outline-none focus:!border-primary focus-visible:!border-primary aria-invalid:border-destructive aria-invalid:focus:!border-destructive data-[invalid=true]:border-destructive data-[invalid=true]:focus:!border-destructive",
89
+
90
+ // src/components/input.tsx
91
+ import { cva as cva2 } from "class-variance-authority";
92
+ import { forwardRef as forwardRef2 } from "react";
93
+ import { jsx as jsx2 } from "react/jsx-runtime";
94
+ var inputVariants = cva2(
95
+ // `text-foreground` is explicit rather than inherited. Tailwind's preflight
96
+ // sets `color: inherit` on form controls, so without it the typed value takes
97
+ // whatever colour an ancestor happens to carry -- muted inside a
98
+ // `text-muted-foreground` block, red inside a `text-destructive` one. Select
99
+ // and Textarea have always pinned it; Input was the one control that did not,
100
+ // and callers were compensating by putting the token on a wrapper.
101
+ "file:text-foreground text-foreground placeholder:text-muted-foreground placeholder:opacity-50 selection:bg-primary selection:text-primary-foreground w-full min-w-0 rounded-md border border-input bg-background text-sm transition-all duration-150 outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus:ring-0 focus:ring-offset-0 focus:outline-none focus:border-primary! focus-visible:border-primary! aria-invalid:border-destructive aria-invalid:focus:border-destructive! data-[invalid=true]:border-destructive data-[invalid=true]:focus:border-destructive!",
90
102
  {
91
103
  variants: {
92
104
  size: {
93
- sm: "h-8 px-2.5 py-2 text-sm",
94
- default: "h-10 px-3 py-2.5 text-sm",
95
- lg: "h-11 px-4 py-3 text-base"
105
+ // `-md` rather than `-sm`, so that a small input is the same height as
106
+ // a small button standing beside it in a toolbar or a filter row.
107
+ // Button's `sm` has always used this step; an input reading `-sm` made
108
+ // `size="sm"` mean 36px on one control and 32px on another, and a form
109
+ // row mixing them sat 4px out of line.
110
+ sm: "h-[var(--nx-control-height-md)] px-2.5 py-2 text-sm",
111
+ default: "h-[var(--nx-control-height)] px-3 py-2.5 text-sm",
112
+ lg: "h-[var(--nx-control-height-lg)] px-4 py-3 text-base"
96
113
  }
97
114
  },
98
115
  defaultVariants: {
@@ -100,9 +117,9 @@ var inputVariants = cva(
100
117
  }
101
118
  }
102
119
  );
103
- var Input = forwardRef(
120
+ var Input = forwardRef2(
104
121
  ({ className, type, size, ...props }, ref) => {
105
- return /* @__PURE__ */ jsx(
122
+ return /* @__PURE__ */ jsx2(
106
123
  "input",
107
124
  {
108
125
  type,
@@ -115,14 +132,20 @@ var Input = forwardRef(
115
132
  }
116
133
  );
117
134
  Input.displayName = "Input";
118
- var Textarea = forwardRef(({ className, ...props }, ref) => {
119
- return /* @__PURE__ */ jsx(
135
+
136
+ // src/components/textarea.tsx
137
+ import { forwardRef as forwardRef3 } from "react";
138
+ import { jsx as jsx3 } from "react/jsx-runtime";
139
+ var Textarea = forwardRef3(({ className, ...props }, ref) => {
140
+ return /* @__PURE__ */ jsx3(
120
141
  "textarea",
121
142
  {
122
143
  "data-slot": "textarea",
123
144
  className: cn(
124
- "flex min-h-[80px] w-full rounded-none border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground placeholder:opacity-50 transition-all duration-200 focus:!border-primary focus-visible:!border-primary focus:outline-none hover:border-primary/30 disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-primary/5 resize-y",
125
- "aria-invalid:border-destructive aria-invalid:focus:!border-destructive",
145
+ // hover:border-primary (full strength) keeps the hover boundary more
146
+ // visible than the resting border-input, not a fainter alpha of it.
147
+ "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground placeholder:opacity-50 transition-all duration-200 focus:border-primary! focus-visible:border-primary! focus:outline-none hover:border-primary disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-primary/5 resize-y",
148
+ "aria-invalid:border-destructive aria-invalid:focus:border-destructive!",
126
149
  className
127
150
  ),
128
151
  ref,
@@ -131,9 +154,13 @@ var Textarea = forwardRef(({ className, ...props }, ref) => {
131
154
  );
132
155
  });
133
156
  Textarea.displayName = "Textarea";
157
+
158
+ // src/components/label.tsx
159
+ import { Root as LabelRoot } from "@radix-ui/react-label";
160
+ import { jsx as jsx4 } from "react/jsx-runtime";
134
161
  function Label({ className, ...props }) {
135
- return /* @__PURE__ */ jsx(
136
- Root$3,
162
+ return /* @__PURE__ */ jsx4(
163
+ LabelRoot,
137
164
  {
138
165
  "data-slot": "label",
139
166
  className: cn(
@@ -144,17 +171,135 @@ function Label({ className, ...props }) {
144
171
  }
145
172
  );
146
173
  }
147
- var badgeVariants = cva(
148
- "inline-flex items-center rounded-none px-2.5 py-0.5 h-[22px] text-xs font-medium transition-colors",
174
+
175
+ // src/components/form-label-with-tooltip.tsx
176
+ import { Info } from "lucide-react";
177
+ import * as React2 from "react";
178
+
179
+ // src/components/tooltip.tsx
180
+ import {
181
+ Provider,
182
+ Root,
183
+ Trigger,
184
+ Portal,
185
+ Content
186
+ } from "@radix-ui/react-tooltip";
187
+ import { forwardRef as forwardRef4 } from "react";
188
+
189
+ // src/providers/portal-provider.tsx
190
+ import { createContext, useContext } from "react";
191
+ import { jsx as jsx5 } from "react/jsx-runtime";
192
+ var PortalContext = createContext({ container: null });
193
+ function PortalProvider({ container, children }) {
194
+ return /* @__PURE__ */ jsx5(PortalContext.Provider, { value: { container }, children });
195
+ }
196
+ function usePortalContainer() {
197
+ const { container } = useContext(PortalContext);
198
+ return container ?? void 0;
199
+ }
200
+
201
+ // src/components/tooltip.tsx
202
+ import { jsx as jsx6 } from "react/jsx-runtime";
203
+ var TooltipProvider = Provider;
204
+ var Tooltip = Root;
205
+ var TooltipTrigger = Trigger;
206
+ var TooltipContent = forwardRef4(({ className, sideOffset = 4, ...props }, ref) => {
207
+ const portalContainer = usePortalContainer();
208
+ return (
209
+ // Portalled for the same reason as every other overlay here, plus one
210
+ // specific to the tooltip: the positioner measures against the nearest
211
+ // containing block, and it counts `container-type` as one while the
212
+ // browser does not. Left inline under a `@container` element, the content
213
+ // is offset by that element's own position. Portalling lifts it out of any
214
+ // such ancestor, so the two agree again.
215
+ /* @__PURE__ */ jsx6(Portal, { container: portalContainer, children: /* @__PURE__ */ jsx6(
216
+ Content,
217
+ {
218
+ ref,
219
+ sideOffset,
220
+ "data-slot": "tooltip-content",
221
+ className: cn(
222
+ "z-50 overflow-hidden rounded-lg px-3 py-1.5 text-xs shadow-lg border border-border bg-popover text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
223
+ className
224
+ ),
225
+ ...props
226
+ }
227
+ ) })
228
+ );
229
+ });
230
+ TooltipContent.displayName = Content.displayName;
231
+
232
+ // src/components/form-label-with-tooltip.tsx
233
+ import { jsx as jsx7, jsxs } from "react/jsx-runtime";
234
+ var FormLabelWithTooltip = React2.forwardRef(
235
+ ({
236
+ className,
237
+ labelClassName,
238
+ tooltipClassName,
239
+ label,
240
+ description,
241
+ required,
242
+ ...props
243
+ }, ref) => {
244
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", className), children: [
245
+ /* @__PURE__ */ jsxs(Label, { ref, className: labelClassName, ...props, children: [
246
+ label,
247
+ required && /* @__PURE__ */ jsx7("span", { className: "text-destructive ml-1", children: "*" })
248
+ ] }),
249
+ description && /* @__PURE__ */ jsx7(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { delayDuration: 200, children: [
250
+ /* @__PURE__ */ jsxs(
251
+ TooltipTrigger,
252
+ {
253
+ type: "button",
254
+ tabIndex: -1,
255
+ className: "shrink-0 text-muted-foreground hover:text-foreground focus:outline-none focus:text-foreground transition-colors cursor-help",
256
+ children: [
257
+ /* @__PURE__ */ jsx7(Info, { className: "h-3.5 w-3.5" }),
258
+ /* @__PURE__ */ jsx7("span", { className: "sr-only", children: "Toggle description" })
259
+ ]
260
+ }
261
+ ),
262
+ /* @__PURE__ */ jsx7(
263
+ TooltipContent,
264
+ {
265
+ side: "right",
266
+ className: cn(
267
+ "max-w-[250px] text-xs break-words relative z-[100] shadow-md border border-border bg-primary text-primary-foreground px-3 py-2 rounded-lg",
268
+ tooltipClassName
269
+ ),
270
+ children: description
271
+ }
272
+ )
273
+ ] }) })
274
+ ] });
275
+ }
276
+ );
277
+ FormLabelWithTooltip.displayName = "FormLabelWithTooltip";
278
+
279
+ // src/components/badge.tsx
280
+ import { cva as cva3 } from "class-variance-authority";
281
+ import { jsx as jsx8 } from "react/jsx-runtime";
282
+ var badgeVariants = cva3(
283
+ "inline-flex items-center rounded-sm px-2.5 py-0.5 h-[22px] text-xs font-medium transition-colors",
149
284
  {
150
285
  variants: {
151
286
  variant: {
152
- default: "bg-primary/5 text-slate-900 dark:bg-slate-800 dark:text-slate-100",
153
- primary: "bg-primary/5 text-primary dark:bg-primary/20 dark:text-primary-foreground/90",
154
- success: "bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-100",
155
- warning: "bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-100",
156
- destructive: "bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-100",
157
- outline: "border !border-primary/5 bg-transparent text-slate-700 dark:text-slate-300 dark:!border-primary/5"
287
+ // Clear, legible chip in both modes (was bg-primary/5 at ~5% opacity,
288
+ // which was nearly invisible on dark backgrounds).
289
+ default: "bg-muted text-foreground",
290
+ primary: "bg-primary/10 text-primary dark:bg-primary/20",
291
+ success: "bg-success-100 text-success-700 dark:bg-success-900 dark:text-success-100",
292
+ warning: "bg-warning-100 text-warning-700 dark:bg-warning-900 dark:text-warning-100",
293
+ destructive: "bg-destructive-100 text-destructive-700 dark:bg-destructive-900 dark:text-destructive-100",
294
+ /*
295
+ * The border colour is NOT important-marked. The base sets no border
296
+ * colour, so nothing inside this component competes for it — the only
297
+ * thing a mark could win against is the caller's own class. Seven
298
+ * outline badges pass one, including a status pill whose comment gives
299
+ * a 3:1 contrast reason for the colour it asks for, and every one of
300
+ * them was being overridden without any sign that it had been.
301
+ */
302
+ outline: "border border-border bg-transparent text-foreground dark:text-muted-foreground dark:border-border"
158
303
  }
159
304
  },
160
305
  defaultVariants: {
@@ -163,7 +308,7 @@ var badgeVariants = cva(
163
308
  }
164
309
  );
165
310
  function Badge({ className, variant = "default", ...props }) {
166
- return /* @__PURE__ */ jsx(
311
+ return /* @__PURE__ */ jsx8(
167
312
  "div",
168
313
  {
169
314
  "data-slot": `badge.${variant}`,
@@ -172,8 +317,13 @@ function Badge({ className, variant = "default", ...props }) {
172
317
  }
173
318
  );
174
319
  }
175
- var cardVariants = cva(
176
- "bg-card text-foreground rounded-none border border-primary/5 transition-all duration-200",
320
+
321
+ // src/components/card.tsx
322
+ import { cva as cva4 } from "class-variance-authority";
323
+ import { forwardRef as forwardRef6 } from "react";
324
+ import { jsx as jsx9 } from "react/jsx-runtime";
325
+ var cardVariants = cva4(
326
+ "bg-card text-foreground rounded-lg border border-border transition-all duration-200",
177
327
  {
178
328
  variants: {
179
329
  variant: {
@@ -187,9 +337,9 @@ var cardVariants = cva(
187
337
  }
188
338
  }
189
339
  );
190
- var Card = forwardRef(
340
+ var Card = forwardRef6(
191
341
  ({ className, variant, ...props }, ref) => {
192
- return /* @__PURE__ */ jsx(
342
+ return /* @__PURE__ */ jsx9(
193
343
  "div",
194
344
  {
195
345
  ref,
@@ -201,16 +351,23 @@ var Card = forwardRef(
201
351
  }
202
352
  );
203
353
  Card.displayName = "Card";
204
- var CardHeader = forwardRef(
354
+ var CardHeader = forwardRef6(
205
355
  ({ className, noBorder = false, ...props }, ref) => {
206
- return /* @__PURE__ */ jsx(
356
+ return /* @__PURE__ */ jsx9(
207
357
  "div",
208
358
  {
209
359
  ref,
210
360
  "data-slot": "card-header",
211
361
  className: cn(
212
- "flex flex-col p-4",
213
- !noBorder && "border-b border-primary/5",
362
+ // Mirrors CardFooter: a header that carries its own tint runs the full
363
+ // width of the card, so at a nonzero --radius it would paint square
364
+ // across the card's curved top corners. `inherit` takes the parent's
365
+ // computed radius rather than restating a step. It only helps when the
366
+ // header is a direct child of the card; a header nested inside another
367
+ // wrapper inherits that wrapper's radius instead, and such a card needs
368
+ // `overflow-hidden` to clip the fill.
369
+ "flex flex-col rounded-t-[inherit] p-4",
370
+ !noBorder && "border-b border-border",
214
371
  className
215
372
  ),
216
373
  ...props
@@ -219,9 +376,9 @@ var CardHeader = forwardRef(
219
376
  }
220
377
  );
221
378
  CardHeader.displayName = "CardHeader";
222
- var CardTitle = forwardRef(
379
+ var CardTitle = forwardRef6(
223
380
  ({ className, ...props }, ref) => {
224
- return /* @__PURE__ */ jsx(
381
+ return /* @__PURE__ */ jsx9(
225
382
  "h3",
226
383
  {
227
384
  ref,
@@ -233,9 +390,9 @@ var CardTitle = forwardRef(
233
390
  }
234
391
  );
235
392
  CardTitle.displayName = "CardTitle";
236
- var CardDescription = forwardRef(
393
+ var CardDescription = forwardRef6(
237
394
  ({ className, ...props }, ref) => {
238
- return /* @__PURE__ */ jsx(
395
+ return /* @__PURE__ */ jsx9(
239
396
  "p",
240
397
  {
241
398
  ref,
@@ -247,9 +404,9 @@ var CardDescription = forwardRef(
247
404
  }
248
405
  );
249
406
  CardDescription.displayName = "CardDescription";
250
- var CardAction = forwardRef(
407
+ var CardAction = forwardRef6(
251
408
  ({ className, ...props }, ref) => {
252
- return /* @__PURE__ */ jsx(
409
+ return /* @__PURE__ */ jsx9(
253
410
  "div",
254
411
  {
255
412
  ref,
@@ -261,9 +418,9 @@ var CardAction = forwardRef(
261
418
  }
262
419
  );
263
420
  CardAction.displayName = "CardAction";
264
- var CardContent = forwardRef(
421
+ var CardContent = forwardRef6(
265
422
  ({ className, ...props }, ref) => {
266
- return /* @__PURE__ */ jsx(
423
+ return /* @__PURE__ */ jsx9(
267
424
  "div",
268
425
  {
269
426
  ref,
@@ -275,15 +432,21 @@ var CardContent = forwardRef(
275
432
  }
276
433
  );
277
434
  CardContent.displayName = "CardContent";
278
- var CardFooter = forwardRef(
435
+ var CardFooter = forwardRef6(
279
436
  ({ className, ...props }, ref) => {
280
- return /* @__PURE__ */ jsx(
437
+ return /* @__PURE__ */ jsx9(
281
438
  "div",
282
439
  {
283
440
  ref,
284
441
  "data-slot": "card-footer",
285
442
  className: cn(
286
- "flex items-center px-6 py-4 border-t border-primary/5 bg-primary/5",
443
+ // The footer's tint runs the full width of the card, so at a nonzero
444
+ // --radius it would paint square across the card's curved bottom
445
+ // corners. `inherit` takes the card's own computed radius rather than
446
+ // restating a step, so a card whose radius is overridden stays
447
+ // matched, and it can never disagree with the card at any --radius,
448
+ // including the shipped 0 where `rounded-lg` is 0.
449
+ "flex items-center px-6 py-4 border-t border-border bg-primary/5 rounded-b-[inherit]",
287
450
  className
288
451
  ),
289
452
  ...props
@@ -292,15 +455,93 @@ var CardFooter = forwardRef(
292
455
  }
293
456
  );
294
457
  CardFooter.displayName = "CardFooter";
295
- var alertVariants = cva(
296
- "relative flex items-start gap-3 rounded-none border border-primary/5 p-4 text-sm transition-colors duration-150",
458
+
459
+ // src/components/layout.tsx
460
+ import { forwardRef as forwardRef7 } from "react";
461
+ import { jsx as jsx10, jsxs as jsxs2 } from "react/jsx-runtime";
462
+ var GAP = {
463
+ 0: "gap-0",
464
+ 1: "gap-1",
465
+ 2: "gap-2",
466
+ 3: "gap-3",
467
+ 4: "gap-4",
468
+ 6: "gap-6",
469
+ 8: "gap-8"
470
+ };
471
+ var COLS = {
472
+ 1: "grid-cols-1",
473
+ 2: "grid-cols-2",
474
+ 3: "grid-cols-3",
475
+ 4: "grid-cols-4",
476
+ 6: "grid-cols-6"
477
+ };
478
+ var RESPONSIVE_COLS = {
479
+ 1: "grid-cols-1",
480
+ 2: "grid-cols-1 @2xl:grid-cols-2",
481
+ 3: "grid-cols-1 @2xl:grid-cols-3",
482
+ 4: "grid-cols-1 @2xl:grid-cols-4",
483
+ 6: "grid-cols-1 @2xl:grid-cols-6"
484
+ };
485
+ var Stack = forwardRef7(
486
+ ({ direction = "col", gap = 4, className, ...props }, ref) => /* @__PURE__ */ jsx10(
487
+ "div",
488
+ {
489
+ ref,
490
+ className: cn(
491
+ "flex",
492
+ direction === "col" ? "flex-col" : "flex-row",
493
+ GAP[gap],
494
+ className
495
+ ),
496
+ ...props
497
+ }
498
+ )
499
+ );
500
+ Stack.displayName = "Stack";
501
+ var Grid = forwardRef7(
502
+ ({ cols = 2, gap = 4, responsive = false, className, children, ...rest }, ref) => {
503
+ if (!responsive) {
504
+ return /* @__PURE__ */ jsx10(
505
+ "div",
506
+ {
507
+ ref,
508
+ className: cn("grid", COLS[cols], GAP[gap], className),
509
+ ...rest,
510
+ children
511
+ }
512
+ );
513
+ }
514
+ return /* @__PURE__ */ jsx10("div", { ref, className: cn("@container", className), ...rest, children: /* @__PURE__ */ jsx10("div", { className: cn("grid", RESPONSIVE_COLS[cols], GAP[gap]), children }) });
515
+ }
516
+ );
517
+ Grid.displayName = "Grid";
518
+ var Stat = forwardRef7(
519
+ ({ label, value, className, ...props }, ref) => /* @__PURE__ */ jsxs2("div", { ref, className: cn("flex flex-col gap-1", className), ...props, children: [
520
+ /* @__PURE__ */ jsx10("span", { className: "text-sm text-muted-foreground", children: label }),
521
+ /* @__PURE__ */ jsx10("span", { className: "text-2xl font-semibold text-foreground", children: value })
522
+ ] })
523
+ );
524
+ Stat.displayName = "Stat";
525
+
526
+ // src/components/alert.tsx
527
+ import { cva as cva5 } from "class-variance-authority";
528
+ import { forwardRef as forwardRef8 } from "react";
529
+ import { jsx as jsx11 } from "react/jsx-runtime";
530
+ var alertVariants = cva5(
531
+ "relative flex items-start gap-3 rounded-md border border-border p-4 text-sm transition-colors duration-150",
297
532
  {
298
533
  variants: {
299
534
  variant: {
300
- info: "border-primary/5 bg-primary/5 text-primary dark:border-primary/30 dark:bg-primary/5 dark:text-primary-foreground/90",
301
- success: "border-green-200 bg-green-50 text-green-900 dark:border-green-900 dark:bg-green-950 dark:text-green-100",
302
- warning: "border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-900 dark:bg-amber-950 dark:text-amber-100",
303
- destructive: "border-red-200 bg-red-50 text-red-900 dark:border-red-900 dark:bg-red-950 dark:text-red-100"
535
+ // text-primary is mode-correct (dark ink on light in light mode, light
536
+ // ink on dark in dark mode); the previous dark text override rendered
537
+ // dark slate on the dark tint at about 1:1.
538
+ info: "bg-primary/5 text-primary",
539
+ // dark:border-l-* re-asserts the strong base accent on the left after
540
+ // the dark:border-*-900 all-sides rule, so the meaningful accent stays
541
+ // visible in dark mode instead of collapsing to the faint -900 shade.
542
+ success: "border-success-200 bg-success-50 text-success-900 border-l-4 border-l-success dark:border-success-900 dark:border-l-success dark:bg-success-950 dark:text-success-100",
543
+ warning: "border-warning-200 bg-warning-50 text-warning-900 border-l-4 border-l-warning dark:border-warning-900 dark:border-l-warning dark:bg-warning-950 dark:text-warning-100",
544
+ destructive: "border-destructive-200 bg-destructive-50 text-destructive-900 border-l-4 border-l-destructive dark:border-destructive-900 dark:border-l-destructive dark:bg-destructive-950 dark:text-destructive-100"
304
545
  }
305
546
  },
306
547
  defaultVariants: {
@@ -308,9 +549,9 @@ var alertVariants = cva(
308
549
  }
309
550
  }
310
551
  );
311
- var Alert = forwardRef(
552
+ var Alert = forwardRef8(
312
553
  ({ className, variant = "info", role = "alert", ...props }, ref) => {
313
- return /* @__PURE__ */ jsx(
554
+ return /* @__PURE__ */ jsx11(
314
555
  "div",
315
556
  {
316
557
  ref,
@@ -323,9 +564,9 @@ var Alert = forwardRef(
323
564
  }
324
565
  );
325
566
  Alert.displayName = "Alert";
326
- var AlertTitle = forwardRef(
567
+ var AlertTitle = forwardRef8(
327
568
  ({ className, ...props }, ref) => {
328
- return /* @__PURE__ */ jsx(
569
+ return /* @__PURE__ */ jsx11(
329
570
  "h5",
330
571
  {
331
572
  ref,
@@ -340,9 +581,9 @@ var AlertTitle = forwardRef(
340
581
  }
341
582
  );
342
583
  AlertTitle.displayName = "AlertTitle";
343
- var AlertDescription = forwardRef(
584
+ var AlertDescription = forwardRef8(
344
585
  ({ className, ...props }, ref) => {
345
- return /* @__PURE__ */ jsx(
586
+ return /* @__PURE__ */ jsx11(
346
587
  "div",
347
588
  {
348
589
  ref,
@@ -354,13 +595,17 @@ var AlertDescription = forwardRef(
354
595
  }
355
596
  );
356
597
  AlertDescription.displayName = "AlertDescription";
598
+
599
+ // src/components/separator.tsx
600
+ import * as SeparatorPrimitive from "@radix-ui/react-separator";
601
+ import { jsx as jsx12 } from "react/jsx-runtime";
357
602
  function Separator({
358
603
  className,
359
604
  orientation = "horizontal",
360
605
  decorative = true,
361
606
  ...props
362
607
  }) {
363
- return /* @__PURE__ */ jsx(
608
+ return /* @__PURE__ */ jsx12(
364
609
  SeparatorPrimitive.Root,
365
610
  {
366
611
  "data-slot": "separator",
@@ -374,16 +619,20 @@ function Separator({
374
619
  }
375
620
  );
376
621
  }
377
- var Skeleton = React5.forwardRef(
622
+
623
+ // src/components/skeleton.tsx
624
+ import * as React3 from "react";
625
+ import { jsx as jsx13 } from "react/jsx-runtime";
626
+ var Skeleton = React3.forwardRef(
378
627
  ({ className, ...props }, ref) => {
379
- return /* @__PURE__ */ jsx(
628
+ return /* @__PURE__ */ jsx13(
380
629
  "div",
381
630
  {
382
631
  ref,
383
632
  "data-slot": "skeleton",
384
633
  "aria-hidden": "true",
385
634
  className: cn(
386
- "bg-primary/5 animate-pulse rounded-none motion-reduce:animate-none",
635
+ "bg-primary/5 animate-pulse rounded-md motion-reduce:animate-none",
387
636
  className
388
637
  ),
389
638
  ...props
@@ -392,11 +641,16 @@ var Skeleton = React5.forwardRef(
392
641
  }
393
642
  );
394
643
  Skeleton.displayName = "Skeleton";
395
- var progressVariants = cva("h-full rounded-none transition-all", {
644
+
645
+ // src/components/progress.tsx
646
+ import { cva as cva6 } from "class-variance-authority";
647
+ import * as React4 from "react";
648
+ import { jsx as jsx14 } from "react/jsx-runtime";
649
+ var progressVariants = cva6("h-full rounded-none transition-all", {
396
650
  variants: {
397
651
  variant: {
398
652
  default: "bg-primary-500",
399
- success: "bg-green-500",
653
+ success: "bg-success-500",
400
654
  error: "bg-destructive"
401
655
  }
402
656
  },
@@ -404,7 +658,7 @@ var progressVariants = cva("h-full rounded-none transition-all", {
404
658
  variant: "default"
405
659
  }
406
660
  });
407
- var Progress = React5.forwardRef(
661
+ var Progress = React4.forwardRef(
408
662
  ({
409
663
  value,
410
664
  max = 100,
@@ -415,7 +669,7 @@ var Progress = React5.forwardRef(
415
669
  }, ref) => {
416
670
  const clampedValue = Math.min(Math.max(0, value), max);
417
671
  const percentage = clampedValue / max * 100;
418
- return /* @__PURE__ */ jsx(
672
+ return /* @__PURE__ */ jsx14(
419
673
  "div",
420
674
  {
421
675
  ref,
@@ -425,11 +679,11 @@ var Progress = React5.forwardRef(
425
679
  "aria-valuemax": max,
426
680
  "aria-label": ariaLabel || `Progress: ${Math.round(percentage)}%`,
427
681
  className: cn(
428
- "relative h-2 w-full overflow-hidden rounded-none bg-accent",
682
+ "relative h-2 w-full overflow-hidden rounded-full bg-accent",
429
683
  className
430
684
  ),
431
685
  ...props,
432
- children: /* @__PURE__ */ jsx(
686
+ children: /* @__PURE__ */ jsx14(
433
687
  "div",
434
688
  {
435
689
  className: cn(progressVariants({ variant })),
@@ -444,28 +698,44 @@ var Progress = React5.forwardRef(
444
698
  }
445
699
  );
446
700
  Progress.displayName = "Progress";
447
- var Checkbox = forwardRef(({ className, indeterminate, ...props }, ref) => /* @__PURE__ */ jsx(
701
+
702
+ // src/components/checkbox.tsx
703
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
704
+ import { Check, Minus } from "lucide-react";
705
+ import { forwardRef as forwardRef11 } from "react";
706
+ import { jsx as jsx15 } from "react/jsx-runtime";
707
+ var Checkbox = forwardRef11(({ className, indeterminate, ...props }, ref) => /* @__PURE__ */ jsx15(
448
708
  CheckboxPrimitive.Root,
449
709
  {
450
710
  ref,
451
711
  "data-slot": "checkbox",
452
712
  className: cn(
453
- "peer h-4 w-4 shrink-0 rounded-none border border-primary/5 ring-offset-background focus:!border-primary focus-visible:!border-primary focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:!border-destructive aria-invalid:focus-visible:!border-destructive disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary transition-all duration-200",
713
+ // Resting border uses border-control-border, NOT border-input. An
714
+ // unchecked box has no label, value or focus ring to identify it -- the
715
+ // border is the whole control -- so it is held to 1.4.11's 3:1, which
716
+ // border-input deliberately no longer meets. The checked state switches
717
+ // to border-primary below, keeping the two states distinct.
718
+ "peer relative h-4 w-4 shrink-0 rounded-sm border border-control-border ring-offset-background before:absolute before:left-1/2 before:top-1/2 before:h-6 before:w-6 before:-translate-x-1/2 before:-translate-y-1/2 before:content-[''] focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground data-[state=indeterminate]:border-primary transition-all duration-200",
454
719
  className
455
720
  ),
456
721
  ...props,
457
- children: /* @__PURE__ */ jsx(
722
+ children: /* @__PURE__ */ jsx15(
458
723
  CheckboxPrimitive.Indicator,
459
724
  {
460
725
  className: cn("flex items-center justify-center text-current"),
461
- children: indeterminate ? /* @__PURE__ */ jsx(Minus, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" })
726
+ children: indeterminate ? /* @__PURE__ */ jsx15(Minus, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx15(Check, { className: "h-3 w-3" })
462
727
  }
463
728
  )
464
729
  }
465
730
  ));
466
731
  Checkbox.displayName = "Checkbox";
467
- var RadioGroup = forwardRef(({ className, ...props }, ref) => {
468
- return /* @__PURE__ */ jsx(
732
+
733
+ // src/components/radio-group.tsx
734
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
735
+ import { forwardRef as forwardRef12 } from "react";
736
+ import { jsx as jsx16 } from "react/jsx-runtime";
737
+ var RadioGroup = forwardRef12(({ className, ...props }, ref) => {
738
+ return /* @__PURE__ */ jsx16(
469
739
  RadioGroupPrimitive.Root,
470
740
  {
471
741
  className: cn("grid gap-2", className),
@@ -476,52 +746,92 @@ var RadioGroup = forwardRef(({ className, ...props }, ref) => {
476
746
  );
477
747
  });
478
748
  RadioGroup.displayName = "RadioGroup";
479
- var RadioGroupItem = forwardRef(({ className, ...props }, ref) => {
480
- return /* @__PURE__ */ jsx(
749
+ var RadioGroupItem = forwardRef12(({ className, ...props }, ref) => {
750
+ return /* @__PURE__ */ jsx16(
481
751
  RadioGroupPrimitive.Item,
482
752
  {
483
753
  ref,
484
754
  "data-slot": "radio-group-item",
485
755
  className: cn(
486
- "peer h-4 w-4 shrink-0 rounded-none border border-primary/5 bg-background cursor-pointer transition-all duration-150 focus:!border-primary focus-visible:!border-primary focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:!border-destructive aria-invalid:focus-visible:!border-destructive disabled:cursor-not-allowed disabled:opacity-50 hover:border-primary/30 data-[state=checked]:border-primary data-[state=checked]:border-[5px]",
756
+ // Unchecked outline uses primary/40 (clearly visible) instead of primary/5
757
+ // (~5% opacity, effectively invisible); hover strengthens above the resting state.
758
+ // Resting border uses border-control-border, NOT border-input. An
759
+ // unchecked radio is only its ring, with nothing else to identify it,
760
+ // so it is held to 1.4.11's 3:1 -- which border-input deliberately no
761
+ // longer meets. The checked state switches to border-primary below.
762
+ // rounded-full is fixed rather than derived from --radius: the circle is
763
+ // what tells the user only one option can be chosen. The thick checked
764
+ // border leaves a background-coloured core, and because the border's
765
+ // inner edge is curved too that core reads as a round dot.
766
+ "peer h-4 w-4 shrink-0 rounded-full border border-control-border bg-background cursor-pointer transition-all duration-150 focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 hover:border-primary/70 data-[state=checked]:border-primary data-[state=checked]:border-[5px]",
487
767
  className
488
768
  ),
489
769
  ...props,
490
- children: /* @__PURE__ */ jsx(RadioGroupPrimitive.Indicator, {})
770
+ children: /* @__PURE__ */ jsx16(RadioGroupPrimitive.Indicator, { className: "block size-full rounded-full" })
491
771
  }
492
772
  );
493
773
  });
494
774
  RadioGroupItem.displayName = "RadioGroupItem";
775
+
776
+ // src/components/switch.tsx
777
+ import {
778
+ Root as SwitchRoot,
779
+ Thumb as SwitchThumb
780
+ } from "@radix-ui/react-switch";
781
+ import { jsx as jsx17 } from "react/jsx-runtime";
495
782
  function Switch({ className, ...props }) {
496
- return /* @__PURE__ */ jsx(
497
- Root$4,
783
+ return /* @__PURE__ */ jsx17(
784
+ SwitchRoot,
498
785
  {
499
786
  "data-slot": "switch",
500
787
  className: cn(
501
- "peer inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-none border border-primary/5 transition-all outline-none focus-visible:border-primary aria-invalid:border-destructive aria-invalid:focus-visible:!border-destructive disabled:cursor-not-allowed disabled:opacity-50",
502
- "data-[state=checked]:bg-primary data-[state=checked]:!border-primary",
503
- "data-[state=unchecked]:bg-input data-[state=unchecked]:border-primary/5 dark:data-[state=unchecked]:bg-input/80",
788
+ "peer inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-border transition-all outline-none focus-visible:border-primary aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50",
789
+ "data-[state=checked]:bg-primary data-[state=checked]:border-primary!",
790
+ // An unchecked switch is a track and a thumb and nothing else -- no
791
+ // label inside it, no value, no glyph -- so 1.4.11 applies to both the
792
+ // track against the page and the thumb against the track. `bg-input`
793
+ // cannot serve here: it is the FIELD border weight, deliberately below
794
+ // the minimum, and at that value the pill and its thumb both vanish
795
+ // into a light page. The control token is the same answer used for the
796
+ // checkbox and radio boundary, for the same reason.
797
+ // At full strength in both modes. A `/80` here read as a softening of
798
+ // the dark track and was in fact a removal of the guarantee the token
799
+ // carries: composited over the surfaces the switch renders on it
800
+ // measures 3.02 on the page, 2.94 on a card, 2.85 on a popover or the
801
+ // sidebar and 2.65 on muted, so three of the four fall under the 3:1
802
+ // this token exists to hold. Opaque, the same four are 4.23, 4.01,
803
+ // 3.79 and 3.40.
804
+ "data-[state=unchecked]:bg-control-border data-[state=unchecked]:border-control-border",
504
805
  className
505
806
  ),
506
807
  ...props,
507
- children: /* @__PURE__ */ jsx(
508
- Thumb,
808
+ children: /* @__PURE__ */ jsx17(
809
+ SwitchThumb,
509
810
  {
510
811
  "data-slot": "switch-thumb",
511
812
  className: cn(
512
- "bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-none ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
813
+ "bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
513
814
  )
514
815
  }
515
816
  )
516
817
  }
517
818
  );
518
819
  }
820
+
821
+ // src/components/collapsible.tsx
822
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
519
823
  var Collapsible = CollapsiblePrimitive.Root;
520
824
  var CollapsibleTrigger2 = CollapsiblePrimitive.CollapsibleTrigger;
521
825
  var CollapsibleContent2 = CollapsiblePrimitive.CollapsibleContent;
826
+
827
+ // src/components/accordion.tsx
828
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
829
+ import { ChevronDown } from "lucide-react";
830
+ import { forwardRef as forwardRef13 } from "react";
831
+ import { jsx as jsx18, jsxs as jsxs3 } from "react/jsx-runtime";
522
832
  var Accordion = AccordionPrimitive.Root;
523
- var AccordionItem = forwardRef(
524
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
833
+ var AccordionItem = forwardRef13(
834
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx18(
525
835
  AccordionPrimitive.Item,
526
836
  {
527
837
  ref,
@@ -532,8 +842,8 @@ var AccordionItem = forwardRef(
532
842
  )
533
843
  );
534
844
  AccordionItem.displayName = "AccordionItem";
535
- var AccordionTrigger = forwardRef(
536
- ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(AccordionPrimitive.Header, { className: "flex", "data-slot": "accordion-header", children: /* @__PURE__ */ jsxs(
845
+ var AccordionTrigger = forwardRef13(
846
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx18(AccordionPrimitive.Header, { className: "flex", "data-slot": "accordion-header", children: /* @__PURE__ */ jsxs3(
537
847
  AccordionPrimitive.Trigger,
538
848
  {
539
849
  ref,
@@ -545,27 +855,37 @@ var AccordionTrigger = forwardRef(
545
855
  ...props,
546
856
  children: [
547
857
  children,
548
- /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 shrink-0 transition-transform duration-150" })
858
+ /* @__PURE__ */ jsx18(ChevronDown, { className: "h-4 w-4 shrink-0 transition-transform duration-150 will-change-transform" })
549
859
  ]
550
860
  }
551
861
  ) })
552
862
  );
553
863
  AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
554
- var AccordionContent = forwardRef(
555
- ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
864
+ var AccordionContent = forwardRef13(
865
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx18(
556
866
  AccordionPrimitive.Content,
557
867
  {
558
868
  ref,
559
869
  "data-slot": "accordion-content",
560
- className: "overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",
870
+ className: "overflow-hidden text-sm transition-all will-change-[height] transform-[translateZ(0)] data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",
561
871
  ...props,
562
- children: /* @__PURE__ */ jsx("div", { className: cn("pb-4 pt-0", className), children })
872
+ children: /* @__PURE__ */ jsx18("div", { className: cn("pb-4 pt-0", className), children })
563
873
  }
564
874
  )
565
875
  );
566
876
  AccordionContent.displayName = AccordionPrimitive.Content.displayName;
567
- var avatarVariants = cva(
568
- "relative inline-flex shrink-0 overflow-hidden rounded-none items-center justify-center bg-primary/5 text-muted-foreground",
877
+
878
+ // src/components/avatar.tsx
879
+ import {
880
+ Root as AvatarRoot,
881
+ Image as AvatarImagePrimitive,
882
+ Fallback as AvatarFallbackPrimitive
883
+ } from "@radix-ui/react-avatar";
884
+ import { cva as cva7 } from "class-variance-authority";
885
+ import { createContext as createContext2, forwardRef as forwardRef14, useContext as useContext2 } from "react";
886
+ import { jsx as jsx19 } from "react/jsx-runtime";
887
+ var avatarVariants = cva7(
888
+ "relative inline-flex shrink-0 overflow-hidden rounded-full items-center justify-center bg-primary/5 text-muted-foreground",
569
889
  {
570
890
  variants: {
571
891
  size: {
@@ -593,11 +913,11 @@ var fallbackTextSizeMap = {
593
913
  "2xl": "text-2xl"
594
914
  // 24px for 80px avatar
595
915
  };
596
- var AvatarSizeContext = createContext("md");
597
- var Avatar = forwardRef(
916
+ var AvatarSizeContext = createContext2("md");
917
+ var Avatar = forwardRef14(
598
918
  ({ className, size = "md", ...props }, ref) => {
599
- return /* @__PURE__ */ jsx(AvatarSizeContext.Provider, { value: size, children: /* @__PURE__ */ jsx(
600
- Root,
919
+ return /* @__PURE__ */ jsx19(AvatarSizeContext.Provider, { value: size, children: /* @__PURE__ */ jsx19(
920
+ AvatarRoot,
601
921
  {
602
922
  ref,
603
923
  "data-slot": "avatar",
@@ -608,10 +928,10 @@ var Avatar = forwardRef(
608
928
  }
609
929
  );
610
930
  Avatar.displayName = "Avatar";
611
- var AvatarImage = forwardRef(
931
+ var AvatarImage = forwardRef14(
612
932
  ({ className, ...props }, ref) => {
613
- return /* @__PURE__ */ jsx(
614
- Image,
933
+ return /* @__PURE__ */ jsx19(
934
+ AvatarImagePrimitive,
615
935
  {
616
936
  ref,
617
937
  "data-slot": "avatar-image",
@@ -622,17 +942,17 @@ var AvatarImage = forwardRef(
622
942
  }
623
943
  );
624
944
  AvatarImage.displayName = "AvatarImage";
625
- var AvatarFallback = forwardRef(
945
+ var AvatarFallback = forwardRef14(
626
946
  ({ className, children, ...props }, ref) => {
627
- const size = useContext(AvatarSizeContext) || "md";
947
+ const size = useContext2(AvatarSizeContext) || "md";
628
948
  const textSize = fallbackTextSizeMap[size];
629
- return /* @__PURE__ */ jsx(
630
- Fallback,
949
+ return /* @__PURE__ */ jsx19(
950
+ AvatarFallbackPrimitive,
631
951
  {
632
952
  ref,
633
953
  "data-slot": "avatar-fallback",
634
954
  className: cn(
635
- "bg-primary/5 text-muted-foreground flex size-full items-center justify-center rounded-none font-medium",
955
+ "bg-primary/5 text-muted-foreground flex size-full items-center justify-center rounded-full font-medium",
636
956
  textSize,
637
957
  className
638
958
  ),
@@ -643,83 +963,113 @@ var AvatarFallback = forwardRef(
643
963
  }
644
964
  );
645
965
  AvatarFallback.displayName = "AvatarFallback";
646
- var Tabs = Root$1;
647
- var TabsList = forwardRef(
648
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
649
- List,
650
- {
651
- ref,
652
- "data-slot": "tabs-list",
653
- className: cn(
654
- "inline-flex h-10 items-center justify-center gap-1 rounded-none p-0 text-muted-foreground",
655
- className
656
- ),
657
- ...props
658
- }
659
- )
966
+
967
+ // src/components/tabs.tsx
968
+ import { Root as Root7, List, Trigger as Trigger3, Content as Content3 } from "@radix-ui/react-tabs";
969
+ import { cva as cva8 } from "class-variance-authority";
970
+ import { forwardRef as forwardRef15 } from "react";
971
+ import { jsx as jsx20 } from "react/jsx-runtime";
972
+ var Tabs = Root7;
973
+ var TABS_LIST_VARIANTS = {
974
+ default: "h-10",
975
+ ghost: "h-8 bg-transparent"
976
+ };
977
+ var tabsListVariants = cva8(
978
+ // Square corners: underline tabs, so the list never draws a rounded surface.
979
+ // `gap-1` and `p-0` are invariant across the variants, so they belong here —
980
+ // repeating them in each arm gives any future adjustment two sites to change
981
+ // and one to forget.
982
+ //
983
+ // The rail the triggers sit on, and it is load-bearing rather than
984
+ // decoration. Each trigger draws a 2px border on its trailing edge and pulls
985
+ // itself half a step onto this one: with no rail here, that pull put a 2px
986
+ // line onto whatever followed the strip in the document, and above a rounded
987
+ // panel that is the corner curve — a straight bar crossing an 8px arc. The
988
+ // rail also gives an inactive tab somewhere to be inactive, which is what
989
+ // makes the active one read as selected rather than as the only tab.
990
+ //
991
+ // Which edge is the trailing one depends on orientation, so the rail follows
992
+ // it. Radix stamps `data-orientation` on the list and on every trigger, so
993
+ // both halves read the same source and cannot disagree about the axis. A
994
+ // fixed bottom rail draws a horizontal line beneath a vertical list.
995
+ "inline-flex items-center justify-center gap-1 rounded-none border-b border-border p-0 text-muted-foreground data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:border-r",
996
+ {
997
+ variants: { variant: TABS_LIST_VARIANTS },
998
+ defaultVariants: { variant: "default" }
999
+ }
660
1000
  );
1001
+ var TabsList = forwardRef15(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx20(
1002
+ List,
1003
+ {
1004
+ ref,
1005
+ "data-slot": "tabs-list",
1006
+ className: cn(tabsListVariants({ variant }), className),
1007
+ ...props
1008
+ }
1009
+ ));
661
1010
  TabsList.displayName = List.displayName;
662
- var TabsTrigger = forwardRef(
663
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
664
- Trigger,
665
- {
666
- ref,
667
- "data-slot": "tabs-trigger",
668
- className: cn(
669
- "inline-flex items-center justify-center whitespace-nowrap rounded-none bg-transparent px-4 py-2 text-sm font-medium cursor-pointer transition-all duration-200 border-b-2 relative -mb-0.5 data-[state=active]:!border-b-primary data-[state=active]:text-primary data-[state=inactive]:border-transparent data-[state=inactive]:text-muted-foreground hover:text-primary hover:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/20 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed",
670
- className
671
- ),
672
- ...props
673
- }
674
- )
1011
+ var TABS_TRIGGER_SIZES = {
1012
+ default: "text-sm",
1013
+ sm: "text-xs"
1014
+ };
1015
+ var tabsTriggerVariants = cva8(
1016
+ // Square corners: the active state is a 2px border on the trailing edge that
1017
+ // has to run the full length of the trigger and stay flush with its ends.
1018
+ //
1019
+ // The active colour is NOT important-marked. Nothing inside this component
1020
+ // competes for it — the inactive arm is mutually exclusive with the active
1021
+ // one — so the only thing an `!` could win against is a caller's class, which
1022
+ // is precisely what a theme supplies. Marking it made the one line under
1023
+ // every selected tab the one line a theme could not restyle, and the failure
1024
+ // read as "the theme did not apply here" rather than as an opt-out.
1025
+ //
1026
+ // The trailing edge is the bottom when the strip is horizontal and the right
1027
+ // when it is vertical, so the indicator, the half-step pull onto the rail and
1028
+ // the active colour all switch axis together off the same `data-orientation`
1029
+ // the list reads. Switching only some of them puts the selection affordance
1030
+ // on one axis and the line it sits on the other.
1031
+ "inline-flex items-center justify-center whitespace-nowrap rounded-none bg-transparent px-4 py-2 font-medium cursor-pointer transition-all duration-200 border-b-2 relative -mb-0.5 data-[state=active]:border-b-primary data-[state=active]:text-primary data-[state=inactive]:border-transparent data-[state=inactive]:text-muted-foreground hover:text-primary hover:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:mb-0 data-[orientation=vertical]:border-r-2 data-[orientation=vertical]:-mr-0.5 data-[orientation=vertical]:data-[state=active]:border-r-primary",
1032
+ {
1033
+ variants: { size: TABS_TRIGGER_SIZES },
1034
+ defaultVariants: { size: "default" }
1035
+ }
675
1036
  );
676
- TabsTrigger.displayName = Trigger.displayName;
677
- var TabsContent = forwardRef(
678
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
679
- Content,
1037
+ var TabsTrigger = forwardRef15(({ className, size, ...props }, ref) => /* @__PURE__ */ jsx20(
1038
+ Trigger3,
1039
+ {
1040
+ ref,
1041
+ "data-slot": "tabs-trigger",
1042
+ className: cn(tabsTriggerVariants({ size }), className),
1043
+ ...props
1044
+ }
1045
+ ));
1046
+ TabsTrigger.displayName = Trigger3.displayName;
1047
+ var TabsContent = forwardRef15(
1048
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
1049
+ Content3,
680
1050
  {
681
1051
  ref,
682
1052
  "data-slot": "tabs-content",
683
1053
  className: cn(
684
- "mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/20 focus-visible:ring-offset-2",
1054
+ "mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
685
1055
  className
686
1056
  ),
687
1057
  ...props
688
1058
  }
689
1059
  )
690
1060
  );
691
- TabsContent.displayName = Content.displayName;
692
- var TooltipProvider = Provider;
693
- var Tooltip = Root$2;
694
- var TooltipTrigger = Trigger$1;
695
- var TooltipContent = forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
696
- Content$1,
697
- {
698
- ref,
699
- sideOffset,
700
- "data-slot": "tooltip-content",
701
- className: cn(
702
- "z-50 overflow-hidden rounded-none px-3 py-1.5 text-xs shadow-lg border border-primary/5 bg-popover text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
703
- className
704
- ),
705
- ...props
706
- }
707
- ));
708
- TooltipContent.displayName = Content$1.displayName;
709
- var PortalContext = createContext({ container: null });
710
- function PortalProvider({ container, children }) {
711
- return /* @__PURE__ */ jsx(PortalContext.Provider, { value: { container }, children });
712
- }
713
- function usePortalContainer() {
714
- const { container } = useContext(PortalContext);
715
- return container ?? void 0;
716
- }
1061
+ TabsContent.displayName = Content3.displayName;
1062
+
1063
+ // src/components/popover.tsx
1064
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
1065
+ import * as React5 from "react";
1066
+ import { jsx as jsx21 } from "react/jsx-runtime";
717
1067
  var Popover = PopoverPrimitive.Root;
718
1068
  var PopoverTrigger = PopoverPrimitive.Trigger;
719
1069
  var PopoverAnchor = PopoverPrimitive.Anchor;
720
1070
  var PopoverContent = React5.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => {
721
1071
  const portalContainer = usePortalContainer();
722
- return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
1072
+ return /* @__PURE__ */ jsx21(PopoverPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx21(
723
1073
  PopoverPrimitive.Content,
724
1074
  {
725
1075
  ref,
@@ -727,7 +1077,7 @@ var PopoverContent = React5.forwardRef(({ className, align = "center", sideOffse
727
1077
  sideOffset,
728
1078
  "data-slot": "popover-content",
729
1079
  className: cn(
730
- "z-[100] w-72 rounded-none border border-primary/5 bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",
1080
+ "z-[100] w-72 rounded-lg border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",
731
1081
  className
732
1082
  ),
733
1083
  ...props
@@ -735,24 +1085,36 @@ var PopoverContent = React5.forwardRef(({ className, align = "center", sideOffse
735
1085
  ) });
736
1086
  });
737
1087
  PopoverContent.displayName = PopoverPrimitive.Content.displayName;
1088
+
1089
+ // src/components/dialog.tsx
1090
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
1091
+ import { cva as cva9 } from "class-variance-authority";
1092
+ import { X } from "lucide-react";
1093
+ import { forwardRef as forwardRef17 } from "react";
1094
+ import { jsx as jsx22, jsxs as jsxs4 } from "react/jsx-runtime";
738
1095
  var Dialog = DialogPrimitive.Root;
739
1096
  var DialogTrigger = DialogPrimitive.Trigger;
740
1097
  var DialogPortal = DialogPrimitive.Portal;
741
1098
  var DialogClose = DialogPrimitive.Close;
742
- var DialogOverlay = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1099
+ var DialogOverlay = forwardRef17(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
743
1100
  DialogPrimitive.Overlay,
744
1101
  {
745
1102
  ref,
746
1103
  "data-slot": "dialog-overlay",
747
1104
  className: cn(
748
- "fixed inset-0 z-50 bg-black/80 backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1105
+ // A modal scrim, from the `--nx-overlay` token rather than a surface
1106
+ // token. A black wash is the point — painting it from `background` would
1107
+ // make it a white veil in light mode — but the alpha still has to differ
1108
+ // per mode, because what it composites over is white in one and mid-tone
1109
+ // in the other.
1110
+ "fixed inset-0 z-50 bg-overlay backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
749
1111
  className
750
1112
  ),
751
1113
  ...props
752
1114
  }
753
1115
  ));
754
1116
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
755
- var dialogContentVariants = cva("", {
1117
+ var dialogContentVariants = cva9("", {
756
1118
  variants: {
757
1119
  size: {
758
1120
  sm: "max-w-sm",
@@ -766,31 +1128,31 @@ var dialogContentVariants = cva("", {
766
1128
  size: "md"
767
1129
  }
768
1130
  });
769
- var DialogContent = forwardRef(({ className, children, size, ...props }, ref) => {
1131
+ var DialogContent = forwardRef17(({ className, children, size, ...props }, ref) => {
770
1132
  const portalContainer = usePortalContainer();
771
- return /* @__PURE__ */ jsxs(DialogPortal, { container: portalContainer, children: [
772
- /* @__PURE__ */ jsx(DialogOverlay, {}),
773
- /* @__PURE__ */ jsxs(
1133
+ return /* @__PURE__ */ jsxs4(DialogPortal, { container: portalContainer, children: [
1134
+ /* @__PURE__ */ jsx22(DialogOverlay, {}),
1135
+ /* @__PURE__ */ jsxs4(
774
1136
  DialogPrimitive.Content,
775
1137
  {
776
1138
  ref,
777
1139
  "data-slot": "dialog-content",
778
1140
  className: cn(
779
- "fixed left-[50%] top-[50%] z-[51] grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 border border-primary/5 bg-background p-6 shadow-xl rounded-none duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
1141
+ "fixed left-[50%] top-[50%] z-[51] grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-xl rounded-lg duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
780
1142
  dialogContentVariants({ size }),
781
1143
  className
782
1144
  ),
783
1145
  ...props,
784
1146
  children: [
785
1147
  children,
786
- /* @__PURE__ */ jsxs(
1148
+ /* @__PURE__ */ jsxs4(
787
1149
  DialogPrimitive.Close,
788
1150
  {
789
1151
  "data-slot": "dialog-close",
790
- className: "absolute right-4 top-4 rounded-none p-1 text-muted-foreground cursor-pointer transition-colors duration-150 hover-unified focus:outline-none focus:ring-2 focus:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed",
1152
+ className: "absolute right-4 top-4 rounded-md p-1 text-muted-foreground cursor-pointer transition-colors duration-150 hover-unified focus:outline-none focus:ring-2 focus:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed",
791
1153
  children: [
792
- /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
793
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
1154
+ /* @__PURE__ */ jsx22(X, { className: "h-4 w-4" }),
1155
+ /* @__PURE__ */ jsx22("span", { className: "sr-only", children: "Close" })
794
1156
  ]
795
1157
  }
796
1158
  )
@@ -800,8 +1162,8 @@ var DialogContent = forwardRef(({ className, children, size, ...props }, ref) =>
800
1162
  ] });
801
1163
  });
802
1164
  DialogContent.displayName = DialogPrimitive.Content.displayName;
803
- var DialogHeader = forwardRef(
804
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1165
+ var DialogHeader = forwardRef17(
1166
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
805
1167
  "div",
806
1168
  {
807
1169
  ref,
@@ -814,8 +1176,8 @@ var DialogHeader = forwardRef(
814
1176
  )
815
1177
  );
816
1178
  DialogHeader.displayName = "DialogHeader";
817
- var DialogFooter = forwardRef(
818
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1179
+ var DialogFooter = forwardRef17(
1180
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
819
1181
  "div",
820
1182
  {
821
1183
  ref,
@@ -828,7 +1190,7 @@ var DialogFooter = forwardRef(
828
1190
  )
829
1191
  );
830
1192
  DialogFooter.displayName = "DialogFooter";
831
- var DialogTitle = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1193
+ var DialogTitle = forwardRef17(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
832
1194
  DialogPrimitive.Title,
833
1195
  {
834
1196
  ref,
@@ -840,7 +1202,7 @@ var DialogTitle = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ j
840
1202
  }
841
1203
  ));
842
1204
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
843
- var DialogDescription = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1205
+ var DialogDescription = forwardRef17(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
844
1206
  DialogPrimitive.Description,
845
1207
  {
846
1208
  ref,
@@ -849,31 +1211,43 @@ var DialogDescription = forwardRef(({ className, ...props }, ref) => /* @__PURE_
849
1211
  }
850
1212
  ));
851
1213
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
1214
+
1215
+ // src/components/alert-dialog.tsx
1216
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
1217
+ import {
1218
+ forwardRef as forwardRef18
1219
+ } from "react";
1220
+ import { jsx as jsx23, jsxs as jsxs5 } from "react/jsx-runtime";
852
1221
  var AlertDialog = AlertDialogPrimitive.Root;
853
1222
  var AlertDialogTrigger = AlertDialogPrimitive.Trigger;
854
1223
  var AlertDialogPortal = AlertDialogPrimitive.Portal;
855
- var AlertDialogOverlay = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1224
+ var AlertDialogOverlay = forwardRef18(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
856
1225
  AlertDialogPrimitive.Overlay,
857
1226
  {
858
1227
  ref,
859
1228
  className: cn(
860
- "fixed inset-0 z-50 bg-black/80 backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1229
+ // A modal scrim, from the `--nx-overlay` token rather than a surface
1230
+ // token. A black wash is the point — painting it from `background` would
1231
+ // make it a white veil in light mode — but the alpha still has to differ
1232
+ // per mode, because what it composites over is white in one and mid-tone
1233
+ // in the other.
1234
+ "fixed inset-0 z-50 bg-overlay backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
861
1235
  className
862
1236
  ),
863
1237
  ...props
864
1238
  }
865
1239
  ));
866
1240
  AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
867
- var AlertDialogContent = forwardRef(({ className, ...props }, ref) => {
1241
+ var AlertDialogContent = forwardRef18(({ className, ...props }, ref) => {
868
1242
  const portalContainer = usePortalContainer();
869
- return /* @__PURE__ */ jsxs(AlertDialogPortal, { container: portalContainer, children: [
870
- /* @__PURE__ */ jsx(AlertDialogOverlay, {}),
871
- /* @__PURE__ */ jsx(
1243
+ return /* @__PURE__ */ jsxs5(AlertDialogPortal, { container: portalContainer, children: [
1244
+ /* @__PURE__ */ jsx23(AlertDialogOverlay, {}),
1245
+ /* @__PURE__ */ jsx23(
872
1246
  AlertDialogPrimitive.Content,
873
1247
  {
874
1248
  ref,
875
1249
  className: cn(
876
- "fixed left-[50%] top-[50%] z-[51] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-primary/5 bg-background p-6 shadow-xl rounded-none duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
1250
+ "fixed left-[50%] top-[50%] z-[51] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-xl rounded-lg duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
877
1251
  className
878
1252
  ),
879
1253
  ...props
@@ -882,8 +1256,8 @@ var AlertDialogContent = forwardRef(({ className, ...props }, ref) => {
882
1256
  ] });
883
1257
  });
884
1258
  AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
885
- var AlertDialogHeader = forwardRef(
886
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1259
+ var AlertDialogHeader = forwardRef18(
1260
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
887
1261
  "div",
888
1262
  {
889
1263
  ref,
@@ -896,8 +1270,8 @@ var AlertDialogHeader = forwardRef(
896
1270
  )
897
1271
  );
898
1272
  AlertDialogHeader.displayName = "AlertDialogHeader";
899
- var AlertDialogFooter = forwardRef(
900
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1273
+ var AlertDialogFooter = forwardRef18(
1274
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
901
1275
  "div",
902
1276
  {
903
1277
  ref,
@@ -910,7 +1284,7 @@ var AlertDialogFooter = forwardRef(
910
1284
  )
911
1285
  );
912
1286
  AlertDialogFooter.displayName = "AlertDialogFooter";
913
- var AlertDialogTitle = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1287
+ var AlertDialogTitle = forwardRef18(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
914
1288
  AlertDialogPrimitive.Title,
915
1289
  {
916
1290
  ref,
@@ -922,7 +1296,7 @@ var AlertDialogTitle = forwardRef(({ className, ...props }, ref) => /* @__PURE__
922
1296
  }
923
1297
  ));
924
1298
  AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
925
- var AlertDialogDescription = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1299
+ var AlertDialogDescription = forwardRef18(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
926
1300
  AlertDialogPrimitive.Description,
927
1301
  {
928
1302
  ref,
@@ -931,7 +1305,7 @@ var AlertDialogDescription = forwardRef(({ className, ...props }, ref) => /* @__
931
1305
  }
932
1306
  ));
933
1307
  AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
934
- var AlertDialogAction = forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
1308
+ var AlertDialogAction = forwardRef18(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx23(
935
1309
  AlertDialogPrimitive.Action,
936
1310
  {
937
1311
  ref,
@@ -941,7 +1315,7 @@ var AlertDialogAction = forwardRef(({ className, children, ...props }, ref) => /
941
1315
  }
942
1316
  ));
943
1317
  AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
944
- var AlertDialogCancel = forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
1318
+ var AlertDialogCancel = forwardRef18(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx23(
945
1319
  AlertDialogPrimitive.Cancel,
946
1320
  {
947
1321
  ref,
@@ -955,50 +1329,58 @@ var AlertDialogCancel = forwardRef(({ className, children, ...props }, ref) => /
955
1329
  }
956
1330
  ));
957
1331
  AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
1332
+
1333
+ // src/components/dropdown-menu.tsx
1334
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
1335
+ import { Check as Check2, ChevronRight, Circle } from "lucide-react";
1336
+ import * as React6 from "react";
1337
+ import { jsx as jsx24, jsxs as jsxs6 } from "react/jsx-runtime";
958
1338
  var DropdownMenu = DropdownMenuPrimitive.Root;
959
1339
  var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
960
1340
  var DropdownMenuGroup = DropdownMenuPrimitive.Group;
961
1341
  var DropdownMenuPortal = DropdownMenuPrimitive.Portal;
962
1342
  var DropdownMenuSub = DropdownMenuPrimitive.Sub;
963
1343
  var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
964
- var DropdownMenuSubTrigger = React5.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1344
+ var menuItemBase = "cursor-pointer transition-colors data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
1345
+ var DropdownMenuSubTrigger = React6.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs6(
965
1346
  DropdownMenuPrimitive.SubTrigger,
966
1347
  {
967
1348
  ref,
968
1349
  className: cn(
969
- "flex cursor-default select-none items-center gap-2 rounded-none px-2 py-1.5 text-sm outline-none hover-unified focus:bg-primary/5 focus:text-primary data-[state=open]:bg-primary/5 data-[state=open]:text-primary [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1350
+ "flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-muted data-[state=open]:text-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1351
+ menuItemBase,
970
1352
  inset && "pl-8",
971
1353
  className
972
1354
  ),
973
1355
  ...props,
974
1356
  children: [
975
1357
  children,
976
- /* @__PURE__ */ jsx(ChevronRight, { className: "ml-auto" })
1358
+ /* @__PURE__ */ jsx24(ChevronRight, { className: "ml-auto" })
977
1359
  ]
978
1360
  }
979
1361
  ));
980
1362
  DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
981
- var DropdownMenuSubContent = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1363
+ var DropdownMenuSubContent = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
982
1364
  DropdownMenuPrimitive.SubContent,
983
1365
  {
984
1366
  ref,
985
1367
  className: cn(
986
- "z-50 min-w-[8rem] overflow-hidden rounded-none border border-primary/5 bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
1368
+ "z-50 min-w-[8rem] overflow-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
987
1369
  className
988
1370
  ),
989
1371
  ...props
990
1372
  }
991
1373
  ));
992
1374
  DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
993
- var DropdownMenuContent = React5.forwardRef(({ className, sideOffset = 4, ...props }, ref) => {
1375
+ var DropdownMenuContent = React6.forwardRef(({ className, sideOffset = 4, ...props }, ref) => {
994
1376
  const portalContainer = usePortalContainer();
995
- return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
1377
+ return /* @__PURE__ */ jsx24(DropdownMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx24(
996
1378
  DropdownMenuPrimitive.Content,
997
1379
  {
998
1380
  ref,
999
1381
  sideOffset,
1000
1382
  className: cn(
1001
- "z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-none border border-primary/5 bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
1383
+ "z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
1002
1384
  className
1003
1385
  ),
1004
1386
  ...props
@@ -1006,12 +1388,13 @@ var DropdownMenuContent = React5.forwardRef(({ className, sideOffset = 4, ...pro
1006
1388
  ) });
1007
1389
  });
1008
1390
  DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
1009
- var DropdownMenuItem = React5.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
1391
+ var DropdownMenuItem = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx24(
1010
1392
  DropdownMenuPrimitive.Item,
1011
1393
  {
1012
1394
  ref,
1013
1395
  className: cn(
1014
- "relative flex cursor-pointer select-none items-center gap-2 rounded-none px-2 py-1.5 text-sm outline-none transition-colors hover-unified focus:bg-primary/5 focus:text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1396
+ "relative flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1397
+ menuItemBase,
1015
1398
  inset && "pl-8",
1016
1399
  className
1017
1400
  ),
@@ -1019,40 +1402,42 @@ var DropdownMenuItem = React5.forwardRef(({ className, inset, ...props }, ref) =
1019
1402
  }
1020
1403
  ));
1021
1404
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
1022
- var DropdownMenuCheckboxItem = React5.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs(
1405
+ var DropdownMenuCheckboxItem = React6.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs6(
1023
1406
  DropdownMenuPrimitive.CheckboxItem,
1024
1407
  {
1025
1408
  ref,
1026
1409
  className: cn(
1027
- "relative flex cursor-default select-none items-center rounded-none py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover-primary-light focus:bg-primary/5 focus:text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
1410
+ "relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
1411
+ menuItemBase,
1028
1412
  className
1029
1413
  ),
1030
1414
  checked,
1031
1415
  ...props,
1032
1416
  children: [
1033
- /* @__PURE__ */ jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
1417
+ /* @__PURE__ */ jsx24("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx24(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx24(Check2, { className: "h-4 w-4" }) }) }),
1034
1418
  children
1035
1419
  ]
1036
1420
  }
1037
1421
  ));
1038
1422
  DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
1039
- var DropdownMenuRadioItem = React5.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1423
+ var DropdownMenuRadioItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs6(
1040
1424
  DropdownMenuPrimitive.RadioItem,
1041
1425
  {
1042
1426
  ref,
1043
1427
  className: cn(
1044
- "relative flex cursor-default select-none items-center rounded-none py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover-primary-light focus:bg-primary/5 focus:text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
1428
+ "relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
1429
+ menuItemBase,
1045
1430
  className
1046
1431
  ),
1047
1432
  ...props,
1048
1433
  children: [
1049
- /* @__PURE__ */ jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Circle, { className: "h-2 w-2 fill-current" }) }) }),
1434
+ /* @__PURE__ */ jsx24("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx24(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx24(Circle, { className: "h-2 w-2 fill-current" }) }) }),
1050
1435
  children
1051
1436
  ]
1052
1437
  }
1053
1438
  ));
1054
1439
  DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
1055
- var DropdownMenuLabel = React5.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
1440
+ var DropdownMenuLabel = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx24(
1056
1441
  DropdownMenuPrimitive.Label,
1057
1442
  {
1058
1443
  ref,
@@ -1065,7 +1450,7 @@ var DropdownMenuLabel = React5.forwardRef(({ className, inset, ...props }, ref)
1065
1450
  }
1066
1451
  ));
1067
1452
  DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
1068
- var DropdownMenuSeparator = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1453
+ var DropdownMenuSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
1069
1454
  DropdownMenuPrimitive.Separator,
1070
1455
  {
1071
1456
  ref,
@@ -1074,8 +1459,8 @@ var DropdownMenuSeparator = React5.forwardRef(({ className, ...props }, ref) =>
1074
1459
  }
1075
1460
  ));
1076
1461
  DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
1077
- var DropdownMenuShortcut = React5.forwardRef(({ className, ...props }, ref) => {
1078
- return /* @__PURE__ */ jsx(
1462
+ var DropdownMenuShortcut = React6.forwardRef(({ className, ...props }, ref) => {
1463
+ return /* @__PURE__ */ jsx24(
1079
1464
  "span",
1080
1465
  {
1081
1466
  ref,
@@ -1085,27 +1470,39 @@ var DropdownMenuShortcut = React5.forwardRef(({ className, ...props }, ref) => {
1085
1470
  );
1086
1471
  });
1087
1472
  DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
1473
+
1474
+ // src/components/select.tsx
1475
+ import * as SelectPrimitive from "@radix-ui/react-select";
1476
+ import { cva as cva10 } from "class-variance-authority";
1477
+ import { Check as Check3, ChevronDown as ChevronDown2, ChevronUp } from "lucide-react";
1478
+ import { forwardRef as forwardRef20 } from "react";
1479
+ import { jsx as jsx25, jsxs as jsxs7 } from "react/jsx-runtime";
1088
1480
  function Select({ ...props }) {
1089
- return /* @__PURE__ */ jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
1481
+ return /* @__PURE__ */ jsx25(SelectPrimitive.Root, { "data-slot": "select", ...props });
1090
1482
  }
1091
1483
  function SelectGroup({
1092
1484
  ...props
1093
1485
  }) {
1094
- return /* @__PURE__ */ jsx(SelectPrimitive.Group, { "data-slot": "select-group", ...props });
1486
+ return /* @__PURE__ */ jsx25(SelectPrimitive.Group, { "data-slot": "select-group", ...props });
1095
1487
  }
1096
1488
  function SelectValue({
1097
1489
  ...props
1098
1490
  }) {
1099
- return /* @__PURE__ */ jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
1491
+ return /* @__PURE__ */ jsx25(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
1100
1492
  }
1101
- var selectTriggerVariants = cva(
1102
- "flex w-full items-center justify-between gap-2 rounded-none border border-input bg-background px-3 text-sm text-foreground cursor-pointer transition-all duration-150 focus:!border-primary focus-visible:!border-primary focus:outline-none hover:border-primary/30 disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-primary/5 data-[placeholder]:text-muted-foreground aria-[invalid=true]:border-destructive aria-[invalid=true]:focus:!border-destructive [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4",
1493
+ var selectTriggerVariants = cva10(
1494
+ // hover:border-primary (full strength) keeps the hover boundary more visible
1495
+ // than the resting border-input, not a fainter alpha of it.
1496
+ "flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background px-3 text-sm text-foreground cursor-pointer transition-all duration-150 focus:border-primary! focus-visible:border-primary! focus:outline-none hover:border-primary disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-primary/5 data-[placeholder]:text-muted-foreground aria-[invalid=true]:border-destructive aria-[invalid=true]:focus:border-destructive! [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4",
1103
1497
  {
1104
1498
  variants: {
1105
1499
  size: {
1106
- sm: "h-8 text-sm",
1107
- default: "h-10 text-sm",
1108
- lg: "h-11 text-base"
1500
+ // `-md`, matching Button and Input: one height for one size name. A
1501
+ // select sitting beside a small button in a filter row is the case that
1502
+ // makes a 4px difference visible.
1503
+ sm: "h-[var(--nx-control-height-md)] text-sm",
1504
+ default: "h-[var(--nx-control-height)] text-sm",
1505
+ lg: "h-[var(--nx-control-height-lg)] text-base"
1109
1506
  }
1110
1507
  },
1111
1508
  defaultVariants: {
@@ -1113,8 +1510,8 @@ var selectTriggerVariants = cva(
1113
1510
  }
1114
1511
  }
1115
1512
  );
1116
- var SelectTrigger = forwardRef(({ className, size, children, ...props }, ref) => {
1117
- return /* @__PURE__ */ jsxs(
1513
+ var SelectTrigger = forwardRef20(({ className, size, children, ...props }, ref) => {
1514
+ return /* @__PURE__ */ jsxs7(
1118
1515
  SelectPrimitive.Trigger,
1119
1516
  {
1120
1517
  ref,
@@ -1123,7 +1520,7 @@ var SelectTrigger = forwardRef(({ className, size, children, ...props }, ref) =>
1123
1520
  ...props,
1124
1521
  children: [
1125
1522
  children,
1126
- /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 opacity-50" }) })
1523
+ /* @__PURE__ */ jsx25(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx25(ChevronDown2, { className: "size-4 opacity-50" }) })
1127
1524
  ]
1128
1525
  }
1129
1526
  );
@@ -1136,20 +1533,20 @@ function SelectContent({
1136
1533
  ...props
1137
1534
  }) {
1138
1535
  const portalContainer = usePortalContainer();
1139
- return /* @__PURE__ */ jsx(SelectPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
1536
+ return /* @__PURE__ */ jsx25(SelectPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs7(
1140
1537
  SelectPrimitive.Content,
1141
1538
  {
1142
1539
  "data-slot": "select-content",
1143
1540
  className: cn(
1144
- "bg-popover text-popover-foreground border border-primary/5 shadow-none rounded-none z-9999 max-h-(--radix-select-content-available-height) min-w-32 overflow-hidden data-[state=open]:animate-zoom-in-95 data-[state=closed]:animate-zoom-out-95 data-[side=bottom]:animate-slide-in-from-top-2 data-[side=left]:animate-slide-in-from-right-2 data-[side=right]:animate-slide-in-from-left-2 data-[side=top]:animate-slide-in-from-bottom-2",
1541
+ "bg-popover text-popover-foreground border border-border shadow-none rounded-lg z-9999 max-h-(--radix-select-content-available-height) min-w-32 overflow-hidden data-[state=open]:animate-zoom-in-95 data-[state=closed]:animate-zoom-out-95 data-[side=bottom]:animate-slide-in-from-top-2 data-[side=left]:animate-slide-in-from-right-2 data-[side=right]:animate-slide-in-from-left-2 data-[side=top]:animate-slide-in-from-bottom-2",
1145
1542
  position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
1146
1543
  className
1147
1544
  ),
1148
1545
  position,
1149
1546
  ...props,
1150
1547
  children: [
1151
- /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
1152
- /* @__PURE__ */ jsx(
1548
+ /* @__PURE__ */ jsx25(SelectScrollUpButton, {}),
1549
+ /* @__PURE__ */ jsx25(
1153
1550
  SelectPrimitive.Viewport,
1154
1551
  {
1155
1552
  className: cn(
@@ -1159,7 +1556,7 @@ function SelectContent({
1159
1556
  children
1160
1557
  }
1161
1558
  ),
1162
- /* @__PURE__ */ jsx(SelectScrollDownButton, {})
1559
+ /* @__PURE__ */ jsx25(SelectScrollDownButton, {})
1163
1560
  ]
1164
1561
  }
1165
1562
  ) });
@@ -1168,7 +1565,7 @@ function SelectLabel({
1168
1565
  className,
1169
1566
  ...props
1170
1567
  }) {
1171
- return /* @__PURE__ */ jsx(
1568
+ return /* @__PURE__ */ jsx25(
1172
1569
  SelectPrimitive.Label,
1173
1570
  {
1174
1571
  "data-slot": "select-label",
@@ -1182,18 +1579,18 @@ function SelectItem({
1182
1579
  children,
1183
1580
  ...props
1184
1581
  }) {
1185
- return /* @__PURE__ */ jsxs(
1582
+ return /* @__PURE__ */ jsxs7(
1186
1583
  SelectPrimitive.Item,
1187
1584
  {
1188
1585
  "data-slot": "select-item",
1189
1586
  className: cn(
1190
- "relative flex w-full cursor-pointer items-center gap-2 rounded-none py-2 pr-8 pl-2 text-sm text-foreground outline-none select-none transition-colors hover-unified focus:bg-primary/5 focus:text-primary data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4",
1587
+ "relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-2 pr-8 pl-2 text-sm text-foreground outline-none select-none transition-colors hover-unified focus:bg-primary/5 focus:text-primary data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4",
1191
1588
  className
1192
1589
  ),
1193
1590
  ...props,
1194
1591
  children: [
1195
- /* @__PURE__ */ jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "size-4" }) }) }),
1196
- /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
1592
+ /* @__PURE__ */ jsx25("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx25(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx25(Check3, { className: "size-4" }) }) }),
1593
+ /* @__PURE__ */ jsx25(SelectPrimitive.ItemText, { children })
1197
1594
  ]
1198
1595
  }
1199
1596
  );
@@ -1202,7 +1599,7 @@ function SelectSeparator({
1202
1599
  className,
1203
1600
  ...props
1204
1601
  }) {
1205
- return /* @__PURE__ */ jsx(
1602
+ return /* @__PURE__ */ jsx25(
1206
1603
  SelectPrimitive.Separator,
1207
1604
  {
1208
1605
  "data-slot": "select-separator",
@@ -1215,7 +1612,7 @@ function SelectScrollUpButton({
1215
1612
  className,
1216
1613
  ...props
1217
1614
  }) {
1218
- return /* @__PURE__ */ jsx(
1615
+ return /* @__PURE__ */ jsx25(
1219
1616
  SelectPrimitive.ScrollUpButton,
1220
1617
  {
1221
1618
  "data-slot": "select-scroll-up-button",
@@ -1224,7 +1621,7 @@ function SelectScrollUpButton({
1224
1621
  className
1225
1622
  ),
1226
1623
  ...props,
1227
- children: /* @__PURE__ */ jsx(ChevronUp, { className: "size-4" })
1624
+ children: /* @__PURE__ */ jsx25(ChevronUp, { className: "size-4" })
1228
1625
  }
1229
1626
  );
1230
1627
  }
@@ -1232,7 +1629,7 @@ function SelectScrollDownButton({
1232
1629
  className,
1233
1630
  ...props
1234
1631
  }) {
1235
- return /* @__PURE__ */ jsx(
1632
+ return /* @__PURE__ */ jsx25(
1236
1633
  SelectPrimitive.ScrollDownButton,
1237
1634
  {
1238
1635
  "data-slot": "select-scroll-down-button",
@@ -1241,19 +1638,32 @@ function SelectScrollDownButton({
1241
1638
  className
1242
1639
  ),
1243
1640
  ...props,
1244
- children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
1641
+ children: /* @__PURE__ */ jsx25(ChevronDown2, { className: "size-4" })
1245
1642
  }
1246
1643
  );
1247
1644
  }
1248
- var Sheet = DialogPrimitive.Root;
1249
- var SheetTrigger = DialogPrimitive.Trigger;
1250
- var SheetClose = DialogPrimitive.Close;
1251
- var SheetPortal = DialogPrimitive.Portal;
1252
- var SheetOverlay = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1253
- DialogPrimitive.Overlay,
1645
+
1646
+ // src/components/sheet.tsx
1647
+ import * as DialogPrimitive2 from "@radix-ui/react-dialog";
1648
+ import { cva as cva11 } from "class-variance-authority";
1649
+ import * as React7 from "react";
1650
+ import { jsx as jsx26, jsxs as jsxs8 } from "react/jsx-runtime";
1651
+ var SheetModalContext = React7.createContext(true);
1652
+ var Sheet = ({ modal = true, children, ...props }) => /* @__PURE__ */ jsx26(SheetModalContext.Provider, { value: modal, children: /* @__PURE__ */ jsx26(DialogPrimitive2.Root, { modal, ...props, children }) });
1653
+ Sheet.displayName = "Sheet";
1654
+ var SheetTrigger = DialogPrimitive2.Trigger;
1655
+ var SheetClose = DialogPrimitive2.Close;
1656
+ var SheetPortal = DialogPrimitive2.Portal;
1657
+ var SheetOverlay = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx26(
1658
+ DialogPrimitive2.Overlay,
1254
1659
  {
1255
1660
  className: cn(
1256
- "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm",
1661
+ // A modal scrim, from the `--nx-overlay` token rather than a surface
1662
+ // token. A black wash is the point — painting it from `background` would
1663
+ // make it a white veil in light mode — but the alpha still has to differ
1664
+ // per mode, because what it composites over is white in one and mid-tone
1665
+ // in the other.
1666
+ "fixed inset-0 z-50 bg-overlay backdrop-blur-sm",
1257
1667
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
1258
1668
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1259
1669
  className
@@ -1262,16 +1672,16 @@ var SheetOverlay = React5.forwardRef(({ className, ...props }, ref) => /* @__PUR
1262
1672
  ref
1263
1673
  }
1264
1674
  ));
1265
- SheetOverlay.displayName = DialogPrimitive.Overlay.displayName;
1266
- var sheetVariants = cva(
1675
+ SheetOverlay.displayName = DialogPrimitive2.Overlay.displayName;
1676
+ var sheetVariants = cva11(
1267
1677
  "fixed z-50 gap-4 bg-background p-6 shadow-lg will-change-transform transition ease-in-out data-[state=closed]:duration-150 data-[state=open]:duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out",
1268
1678
  {
1269
1679
  variants: {
1270
1680
  side: {
1271
- top: "inset-x-0 top-0 border-b border-primary/5 data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
1272
- bottom: "inset-x-0 bottom-0 border-t border-primary/5 data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
1273
- left: "inset-y-0 left-0 h-full w-3/4 border-r border-primary/5 data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
1274
- right: "inset-y-0 right-0 h-full w-3/4 border-l border-primary/5 data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"
1681
+ top: "inset-x-0 top-0 border-b border-border data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
1682
+ bottom: "inset-x-0 bottom-0 border-t border-border data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
1683
+ left: "inset-y-0 left-0 h-full w-3/4 border-r border-border data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
1684
+ right: "inset-y-0 right-0 h-full w-3/4 border-l border-border data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"
1275
1685
  }
1276
1686
  },
1277
1687
  defaultVariants: {
@@ -1279,12 +1689,13 @@ var sheetVariants = cva(
1279
1689
  }
1280
1690
  }
1281
1691
  );
1282
- var SheetContent = React5.forwardRef(({ side = "right", className, children, ...props }, ref) => {
1692
+ var SheetContent = React7.forwardRef(({ side = "right", className, children, ...props }, ref) => {
1283
1693
  const portalContainer = usePortalContainer();
1284
- return /* @__PURE__ */ jsxs(SheetPortal, { container: portalContainer, children: [
1285
- /* @__PURE__ */ jsx(SheetOverlay, {}),
1286
- /* @__PURE__ */ jsx(
1287
- DialogPrimitive.Content,
1694
+ const modal = React7.useContext(SheetModalContext);
1695
+ return /* @__PURE__ */ jsxs8(SheetPortal, { container: portalContainer, children: [
1696
+ modal ? /* @__PURE__ */ jsx26(SheetOverlay, {}) : null,
1697
+ /* @__PURE__ */ jsx26(
1698
+ DialogPrimitive2.Content,
1288
1699
  {
1289
1700
  ref,
1290
1701
  "data-slot": "sheet-content",
@@ -1295,11 +1706,11 @@ var SheetContent = React5.forwardRef(({ side = "right", className, children, ...
1295
1706
  )
1296
1707
  ] });
1297
1708
  });
1298
- SheetContent.displayName = DialogPrimitive.Content.displayName;
1709
+ SheetContent.displayName = DialogPrimitive2.Content.displayName;
1299
1710
  var SheetHeader = ({
1300
1711
  className,
1301
1712
  ...props
1302
- }) => /* @__PURE__ */ jsx(
1713
+ }) => /* @__PURE__ */ jsx26(
1303
1714
  "div",
1304
1715
  {
1305
1716
  className: cn(
@@ -1313,7 +1724,7 @@ SheetHeader.displayName = "SheetHeader";
1313
1724
  var SheetFooter = ({
1314
1725
  className,
1315
1726
  ...props
1316
- }) => /* @__PURE__ */ jsx(
1727
+ }) => /* @__PURE__ */ jsx26(
1317
1728
  "div",
1318
1729
  {
1319
1730
  className: cn(
@@ -1324,31 +1735,38 @@ var SheetFooter = ({
1324
1735
  }
1325
1736
  );
1326
1737
  SheetFooter.displayName = "SheetFooter";
1327
- var SheetTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1328
- DialogPrimitive.Title,
1738
+ var SheetTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx26(
1739
+ DialogPrimitive2.Title,
1329
1740
  {
1330
1741
  ref,
1331
1742
  className: cn("text-lg font-semibold text-foreground", className),
1332
1743
  ...props
1333
1744
  }
1334
1745
  ));
1335
- SheetTitle.displayName = DialogPrimitive.Title.displayName;
1336
- var SheetDescription = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1337
- DialogPrimitive.Description,
1746
+ SheetTitle.displayName = DialogPrimitive2.Title.displayName;
1747
+ var SheetDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx26(
1748
+ DialogPrimitive2.Description,
1338
1749
  {
1339
1750
  ref,
1340
1751
  className: cn("text-sm text-muted-foreground", className),
1341
1752
  ...props
1342
1753
  }
1343
1754
  ));
1344
- SheetDescription.displayName = DialogPrimitive.Description.displayName;
1345
- var Command = forwardRef(
1346
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1347
- Command$1,
1755
+ SheetDescription.displayName = DialogPrimitive2.Description.displayName;
1756
+
1757
+ // src/components/command.tsx
1758
+ import * as DialogPrimitive3 from "@radix-ui/react-dialog";
1759
+ import { Command as CommandPrimitive, defaultFilter } from "cmdk";
1760
+ import { Search } from "lucide-react";
1761
+ import { forwardRef as forwardRef22 } from "react";
1762
+ import { jsx as jsx27, jsxs as jsxs9 } from "react/jsx-runtime";
1763
+ var Command = forwardRef22(
1764
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx27(
1765
+ CommandPrimitive,
1348
1766
  {
1349
1767
  ref,
1350
1768
  className: cn(
1351
- "flex h-full w-full flex-col overflow-hidden rounded-none bg-background text-foreground",
1769
+ "flex h-full w-full flex-col overflow-hidden rounded-lg bg-background text-foreground",
1352
1770
  className
1353
1771
  ),
1354
1772
  ...props
@@ -1356,12 +1774,17 @@ var Command = forwardRef(
1356
1774
  )
1357
1775
  );
1358
1776
  Command.displayName = "Command";
1359
- var CommandDialogOverlay = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1360
- DialogPrimitive.Overlay,
1777
+ var CommandDialogOverlay = forwardRef22(({ className, ...props }, ref) => /* @__PURE__ */ jsx27(
1778
+ DialogPrimitive3.Overlay,
1361
1779
  {
1362
1780
  ref,
1363
1781
  className: cn(
1364
- "fixed inset-0 z-[99] bg-black/80 backdrop-blur-sm",
1782
+ // A modal scrim, from the `--nx-overlay` token rather than a surface
1783
+ // token. A black wash is the point — painting it from `background` would
1784
+ // make it a white veil in light mode — but the alpha still has to differ
1785
+ // per mode, because what it composites over is white in one and mid-tone
1786
+ // in the other.
1787
+ "fixed inset-0 z-[99] bg-overlay backdrop-blur-sm",
1365
1788
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
1366
1789
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1367
1790
  "transition-opacity duration-200",
@@ -1371,13 +1794,19 @@ var CommandDialogOverlay = forwardRef(({ className, ...props }, ref) => /* @__PU
1371
1794
  }
1372
1795
  ));
1373
1796
  CommandDialogOverlay.displayName = "CommandDialogOverlay";
1374
- var CommandDialog = ({ children, ...props }) => {
1797
+ var CommandDialog = ({
1798
+ children,
1799
+ commandProps,
1800
+ contentProps,
1801
+ ...props
1802
+ }) => {
1375
1803
  const portalContainer = usePortalContainer();
1376
- return /* @__PURE__ */ jsx(DialogPrimitive.Root, { ...props, children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { container: portalContainer, children: [
1377
- /* @__PURE__ */ jsx(CommandDialogOverlay, {}),
1378
- /* @__PURE__ */ jsx(
1379
- DialogPrimitive.Content,
1804
+ return /* @__PURE__ */ jsx27(DialogPrimitive3.Root, { ...props, children: /* @__PURE__ */ jsxs9(DialogPrimitive3.Portal, { container: portalContainer, children: [
1805
+ /* @__PURE__ */ jsx27(CommandDialogOverlay, {}),
1806
+ /* @__PURE__ */ jsx27(
1807
+ DialogPrimitive3.Content,
1380
1808
  {
1809
+ ...contentProps,
1381
1810
  "data-slot": "command-content",
1382
1811
  className: cn(
1383
1812
  // Position
@@ -1395,7 +1824,7 @@ var CommandDialog = ({ children, ...props }) => {
1395
1824
  "m-4 sm:m-0",
1396
1825
  // 16px margin on mobile, no margin on desktop
1397
1826
  // Visual
1398
- "overflow-hidden rounded-none border border-primary/5 bg-background shadow-xl",
1827
+ "overflow-hidden rounded-lg border border-border bg-background shadow-xl",
1399
1828
  // Animation
1400
1829
  "duration-200",
1401
1830
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
@@ -1403,20 +1832,32 @@ var CommandDialog = ({ children, ...props }) => {
1403
1832
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
1404
1833
  "data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]"
1405
1834
  ),
1406
- children: /* @__PURE__ */ jsx(Command, { className: "[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wide [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:mb-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-3 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:h-4 [&_[cmdk-item]_svg]:w-4", children })
1835
+ children: /* @__PURE__ */ jsx27(
1836
+ Command,
1837
+ {
1838
+ ...commandProps,
1839
+ className: cn(
1840
+ "[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wide [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:mb-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-3 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:h-4 [&_[cmdk-item]_svg]:w-4",
1841
+ // Merged rather than overridden: a caller passing `className` for its own reason
1842
+ // would otherwise silently drop every layout rule this dialog depends on.
1843
+ commandProps?.className
1844
+ ),
1845
+ children
1846
+ }
1847
+ )
1407
1848
  }
1408
1849
  )
1409
1850
  ] }) });
1410
1851
  };
1411
- var CommandInput = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs(
1852
+ var CommandInput = forwardRef22(({ className, ...props }, ref) => /* @__PURE__ */ jsxs9(
1412
1853
  "div",
1413
1854
  {
1414
- className: "flex items-center border-b border-primary/5 px-4",
1855
+ className: "flex items-center border-b border-border px-4",
1415
1856
  "cmdk-input-wrapper": "",
1416
1857
  children: [
1417
- /* @__PURE__ */ jsx(Search, { className: "mr-3 h-5 w-5 shrink-0 text-muted-foreground" }),
1418
- /* @__PURE__ */ jsx(
1419
- Command$1.Input,
1858
+ /* @__PURE__ */ jsx27(Search, { className: "mr-3 h-5 w-5 shrink-0 text-muted-foreground" }),
1859
+ /* @__PURE__ */ jsx27(
1860
+ CommandPrimitive.Input,
1420
1861
  {
1421
1862
  ref,
1422
1863
  className: cn(
@@ -1440,8 +1881,8 @@ var CommandInput = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
1440
1881
  }
1441
1882
  ));
1442
1883
  CommandInput.displayName = "CommandInput";
1443
- var CommandList = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1444
- Command$1.List,
1884
+ var CommandList = forwardRef22(({ className, ...props }, ref) => /* @__PURE__ */ jsx27(
1885
+ CommandPrimitive.List,
1445
1886
  {
1446
1887
  ref,
1447
1888
  className: cn(
@@ -1455,8 +1896,8 @@ var CommandList = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ j
1455
1896
  }
1456
1897
  ));
1457
1898
  CommandList.displayName = "CommandList";
1458
- var CommandEmpty = forwardRef((props, ref) => /* @__PURE__ */ jsx(
1459
- Command$1.Empty,
1899
+ var CommandEmpty = forwardRef22((props, ref) => /* @__PURE__ */ jsx27(
1900
+ CommandPrimitive.Empty,
1460
1901
  {
1461
1902
  ref,
1462
1903
  className: "py-8 px-4 text-center text-sm text-muted-foreground",
@@ -1464,8 +1905,8 @@ var CommandEmpty = forwardRef((props, ref) => /* @__PURE__ */ jsx(
1464
1905
  }
1465
1906
  ));
1466
1907
  CommandEmpty.displayName = "CommandEmpty";
1467
- var CommandGroup = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1468
- Command$1.Group,
1908
+ var CommandGroup = forwardRef22(({ className, ...props }, ref) => /* @__PURE__ */ jsx27(
1909
+ CommandPrimitive.Group,
1469
1910
  {
1470
1911
  ref,
1471
1912
  className: cn(
@@ -1479,8 +1920,8 @@ var CommandGroup = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
1479
1920
  }
1480
1921
  ));
1481
1922
  CommandGroup.displayName = "CommandGroup";
1482
- var CommandSeparator = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1483
- Command$1.Separator,
1923
+ var CommandSeparator = forwardRef22(({ className, ...props }, ref) => /* @__PURE__ */ jsx27(
1924
+ CommandPrimitive.Separator,
1484
1925
  {
1485
1926
  ref,
1486
1927
  className: cn("h-px bg-border my-2", className),
@@ -1488,8 +1929,8 @@ var CommandSeparator = forwardRef(({ className, ...props }, ref) => /* @__PURE__
1488
1929
  }
1489
1930
  ));
1490
1931
  CommandSeparator.displayName = "CommandSeparator";
1491
- var CommandItem = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1492
- Command$1.Item,
1932
+ var CommandItem = forwardRef22(({ className, ...props }, ref) => /* @__PURE__ */ jsx27(
1933
+ CommandPrimitive.Item,
1493
1934
  {
1494
1935
  ref,
1495
1936
  className: cn(
@@ -1501,7 +1942,7 @@ var CommandItem = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ j
1501
1942
  // Spacing
1502
1943
  "px-3 py-2.5",
1503
1944
  // Visual
1504
- "rounded-none text-base sm:text-sm outline-none",
1945
+ "rounded-sm text-base sm:text-sm outline-none",
1505
1946
  // Transitions
1506
1947
  "transition-all duration-200 ease-(--ease-premium)",
1507
1948
  // Hover state - shared dashboard hover treatment
@@ -1517,9 +1958,9 @@ var CommandItem = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ j
1517
1958
  }
1518
1959
  ));
1519
1960
  CommandItem.displayName = "CommandItem";
1520
- var CommandShortcut = forwardRef(
1961
+ var CommandShortcut = forwardRef22(
1521
1962
  ({ className, ...props }, ref) => {
1522
- return /* @__PURE__ */ jsx(
1963
+ return /* @__PURE__ */ jsx27(
1523
1964
  "span",
1524
1965
  {
1525
1966
  ref,
@@ -1530,7 +1971,7 @@ var CommandShortcut = forwardRef(
1530
1971
  "text-xs font-mono",
1531
1972
  // Visual
1532
1973
  "text-muted-foreground bg-primary/5",
1533
- "border border-primary/5 rounded-none",
1974
+ "border border-border rounded-md",
1534
1975
  // Spacing
1535
1976
  "px-1.5 py-0.5",
1536
1977
  className
@@ -1541,7 +1982,14 @@ var CommandShortcut = forwardRef(
1541
1982
  }
1542
1983
  );
1543
1984
  CommandShortcut.displayName = "CommandShortcut";
1544
- var spinnerVariants = cva("animate-spin motion-reduce:animate-none", {
1985
+ var commandDefaultFilter = defaultFilter;
1986
+
1987
+ // src/components/spinner.tsx
1988
+ import { cva as cva12 } from "class-variance-authority";
1989
+ import { Loader2 } from "lucide-react";
1990
+ import { forwardRef as forwardRef23 } from "react";
1991
+ import { jsx as jsx28 } from "react/jsx-runtime";
1992
+ var spinnerVariants = cva12("animate-spin motion-reduce:animate-none", {
1545
1993
  variants: {
1546
1994
  size: {
1547
1995
  sm: "h-4 w-4",
@@ -1553,9 +2001,9 @@ var spinnerVariants = cva("animate-spin motion-reduce:animate-none", {
1553
2001
  size: "md"
1554
2002
  }
1555
2003
  });
1556
- var Spinner = forwardRef(
2004
+ var Spinner = forwardRef23(
1557
2005
  ({ size = "md", className, "aria-label": ariaLabel = "Loading", ...props }, ref) => {
1558
- return /* @__PURE__ */ jsx(
2006
+ return /* @__PURE__ */ jsx28(
1559
2007
  Loader2,
1560
2008
  {
1561
2009
  ref,
@@ -1568,12 +2016,23 @@ var Spinner = forwardRef(
1568
2016
  }
1569
2017
  );
1570
2018
  Spinner.displayName = "Spinner";
2019
+
2020
+ // src/components/toaster.tsx
2021
+ import {
2022
+ CheckCircle2,
2023
+ AlertCircle,
2024
+ AlertTriangle,
2025
+ XCircle,
2026
+ Loader2 as Loader22
2027
+ } from "lucide-react";
2028
+ import { toast, Toaster as Sonner } from "sonner";
2029
+ import { jsx as jsx29 } from "react/jsx-runtime";
1571
2030
  function Toaster({ theme = "system", ...props }) {
1572
- return /* @__PURE__ */ jsx(
1573
- Toaster$1,
2031
+ return /* @__PURE__ */ jsx29(
2032
+ Sonner,
1574
2033
  {
1575
2034
  theme,
1576
- className: "toaster group !bg-transparent !overflow-visible !z-[9999]",
2035
+ className: "toaster group bg-transparent! overflow-visible! z-[9999]!",
1577
2036
  "data-slot": "toaster",
1578
2037
  toastOptions: {
1579
2038
  classNames: {
@@ -1581,23 +2040,27 @@ function Toaster({ theme = "system", ...props }) {
1581
2040
  }
1582
2041
  },
1583
2042
  icons: {
1584
- success: /* @__PURE__ */ jsx(CheckCircle2, { className: "h-4 w-4" }),
1585
- info: /* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4" }),
1586
- warning: /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4" }),
1587
- error: /* @__PURE__ */ jsx(XCircle, { className: "h-4 w-4" }),
1588
- loading: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" })
2043
+ success: /* @__PURE__ */ jsx29(CheckCircle2, { className: "h-4 w-4" }),
2044
+ info: /* @__PURE__ */ jsx29(AlertCircle, { className: "h-4 w-4" }),
2045
+ warning: /* @__PURE__ */ jsx29(AlertTriangle, { className: "h-4 w-4" }),
2046
+ error: /* @__PURE__ */ jsx29(XCircle, { className: "h-4 w-4" }),
2047
+ loading: /* @__PURE__ */ jsx29(Loader22, { className: "h-4 w-4 animate-spin" })
1589
2048
  },
1590
2049
  style: {
1591
- "--normal-bg": "hsl(var(--popover, 0 0% 100%))",
1592
- "--normal-text": "hsl(var(--popover-foreground, 222.2 84% 4.9%))",
1593
- "--normal-border": "hsl(var(--border, 214.3 31.8% 91.4%))",
2050
+ "--normal-bg": "var(--nx-popover)",
2051
+ "--normal-text": "var(--nx-popover-foreground)",
2052
+ "--normal-border": "var(--nx-border)",
1594
2053
  "--border-radius": "0px"
1595
2054
  },
1596
2055
  ...props
1597
2056
  }
1598
2057
  );
1599
2058
  }
1600
- var Table = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx(
2059
+
2060
+ // src/components/table.tsx
2061
+ import * as React8 from "react";
2062
+ import { jsx as jsx30 } from "react/jsx-runtime";
2063
+ var Table = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx30(
1601
2064
  "table",
1602
2065
  {
1603
2066
  ref,
@@ -1606,9 +2069,16 @@ var Table = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
1606
2069
  }
1607
2070
  ) }));
1608
2071
  Table.displayName = "Table";
1609
- var TableHeader = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr] :border-b border-primary/5", className), ...props }));
2072
+ var TableHeader = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
2073
+ "thead",
2074
+ {
2075
+ ref,
2076
+ className: cn("[&_tr]:border-b border-border", className),
2077
+ ...props
2078
+ }
2079
+ ));
1610
2080
  TableHeader.displayName = "TableHeader";
1611
- var TableBody = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2081
+ var TableBody = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
1612
2082
  "tbody",
1613
2083
  {
1614
2084
  ref,
@@ -1617,28 +2087,31 @@ var TableBody = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__
1617
2087
  }
1618
2088
  ));
1619
2089
  TableBody.displayName = "TableBody";
1620
- var TableFooter = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2090
+ var TableFooter = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
1621
2091
  "tfoot",
1622
2092
  {
1623
2093
  ref,
1624
- className: cn("border-t border-primary/5 font-medium [&>tr]:last:border-b-0", className),
2094
+ className: cn(
2095
+ "border-t border-border font-medium [&>tr]:last:border-b-0",
2096
+ className
2097
+ ),
1625
2098
  ...props
1626
2099
  }
1627
2100
  ));
1628
2101
  TableFooter.displayName = "TableFooter";
1629
- var TableRow = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2102
+ var TableRow = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
1630
2103
  "tr",
1631
2104
  {
1632
2105
  ref,
1633
2106
  className: cn(
1634
- "border-b border-primary/5 transition-colors data-[state=selected]:bg-primary/5",
2107
+ "border-b border-border transition-colors data-[state=selected]:bg-primary/5",
1635
2108
  className
1636
2109
  ),
1637
2110
  ...props
1638
2111
  }
1639
2112
  ));
1640
2113
  TableRow.displayName = "TableRow";
1641
- var TableHead = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2114
+ var TableHead = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
1642
2115
  "th",
1643
2116
  {
1644
2117
  ref,
@@ -1650,7 +2123,7 @@ var TableHead = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__
1650
2123
  }
1651
2124
  ));
1652
2125
  TableHead.displayName = "TableHead";
1653
- var TableCell = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2126
+ var TableCell = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
1654
2127
  "td",
1655
2128
  {
1656
2129
  ref,
@@ -1662,7 +2135,7 @@ var TableCell = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__
1662
2135
  }
1663
2136
  ));
1664
2137
  TableCell.displayName = "TableCell";
1665
- var TableCaption = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2138
+ var TableCaption = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
1666
2139
  "caption",
1667
2140
  {
1668
2141
  ref,
@@ -1671,6 +2144,10 @@ var TableCaption = React5.forwardRef(({ className, ...props }, ref) => /* @__PUR
1671
2144
  }
1672
2145
  ));
1673
2146
  TableCaption.displayName = "TableCaption";
2147
+
2148
+ // src/components/table-search.tsx
2149
+ import { Search as Search2, Loader2 as Loader23, X as X2 } from "lucide-react";
2150
+ import { jsx as jsx31, jsxs as jsxs10 } from "react/jsx-runtime";
1674
2151
  function TableSearch({
1675
2152
  value,
1676
2153
  onChange,
@@ -1679,9 +2156,9 @@ function TableSearch({
1679
2156
  isLoading = false,
1680
2157
  inputRef
1681
2158
  }) {
1682
- return /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-lg", children: [
1683
- /* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
1684
- /* @__PURE__ */ jsx(
2159
+ return /* @__PURE__ */ jsxs10("div", { className: "relative w-full max-w-lg", children: [
2160
+ /* @__PURE__ */ jsx31(Search2, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
2161
+ /* @__PURE__ */ jsx31(
1685
2162
  "input",
1686
2163
  {
1687
2164
  ref: inputRef,
@@ -1690,541 +2167,2112 @@ function TableSearch({
1690
2167
  value,
1691
2168
  onChange: (e) => onChange(e.target.value),
1692
2169
  "aria-busy": isLoading,
1693
- className: "h-10 w-full rounded-none border border-primary/5 bg-background pl-10 pr-10 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 transition-all"
2170
+ className: "h-10 w-full rounded-md border border-input bg-background pl-10 pr-10 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 transition-all"
1694
2171
  }
1695
2172
  ),
1696
- (value || isLoading) && /* @__PURE__ */ jsxs("div", { className: "absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-2", children: [
1697
- isLoading && /* @__PURE__ */ jsx(Loader2, { className: "w-3.5 h-3.5 text-primary animate-spin" }),
1698
- value && /* @__PURE__ */ jsx(
2173
+ (value || isLoading) && /* @__PURE__ */ jsxs10("div", { className: "absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-2", children: [
2174
+ isLoading && /* @__PURE__ */ jsx31(Loader23, { className: "w-3.5 h-3.5 text-primary animate-spin" }),
2175
+ value && /* @__PURE__ */ jsx31(
1699
2176
  "button",
1700
2177
  {
1701
2178
  type: "button",
1702
2179
  onClick: onClear,
1703
- className: "text-muted-foreground/60 hover:text-foreground transition-colors p-0.5 rounded-none hover:bg-primary/5",
2180
+ className: "text-muted-foreground hover:text-foreground transition-colors p-0.5 rounded-md hover:bg-primary/5",
1704
2181
  "aria-label": "Clear search",
1705
- children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5" })
2182
+ children: /* @__PURE__ */ jsx31(X2, { className: "w-3.5 h-3.5" })
1706
2183
  }
1707
2184
  )
1708
2185
  ] })
1709
2186
  ] });
1710
2187
  }
2188
+
2189
+ // src/components/table-states.tsx
2190
+ import { AlertCircle as AlertCircle2, Loader2 as Loader24, FileQuestion } from "lucide-react";
2191
+ import { jsx as jsx32, jsxs as jsxs11 } from "react/jsx-runtime";
1711
2192
  function TableError({
1712
2193
  message = "An error occurred. Please try again."
1713
2194
  }) {
1714
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1715
- /* @__PURE__ */ jsx(AlertCircle, { className: "w-4 h-4 shrink-0" }),
1716
- /* @__PURE__ */ jsx("span", { children: message })
2195
+ return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
2196
+ /* @__PURE__ */ jsx32(AlertCircle2, { className: "w-4 h-4 shrink-0" }),
2197
+ /* @__PURE__ */ jsx32("span", { children: message })
1717
2198
  ] });
1718
2199
  }
1719
2200
  function TableLoading() {
1720
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-4 p-12 text-muted-foreground", children: [
1721
- /* @__PURE__ */ jsx(Loader2, { className: "w-8 h-8 animate-spin text-primary/80" }),
1722
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Loading data..." })
2201
+ return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center justify-center gap-4 p-12 text-muted-foreground", children: [
2202
+ /* @__PURE__ */ jsx32(Loader24, { className: "w-8 h-8 animate-spin text-primary/80" }),
2203
+ /* @__PURE__ */ jsx32("span", { className: "text-sm font-medium", children: "Loading data..." })
1723
2204
  ] });
1724
2205
  }
1725
2206
  function TableEmpty({ message = "No records found" }) {
1726
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-4 p-16 text-center text-muted-foreground", children: [
1727
- /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-none bg-primary/5", children: /* @__PURE__ */ jsx(FileQuestion, { className: "h-6 w-6" }) }),
1728
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: message })
1729
- ] });
1730
- }
1731
- function renderPageNumbers(currentPage, totalPages, maxVisiblePages, onPageChange) {
1732
- const getBtnClass = (active) => `flex h-8 w-8 items-center justify-center border-y border-primary/5 border-r border-primary/5 text-xs z-10 -ml-px transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring ${active ? "!bg-primary !text-primary-foreground !border-primary z-20" : "!bg-background !border-primary/5 hover-muted disabled:opacity-50"}`;
1733
- if (totalPages <= maxVisiblePages) {
1734
- return Array.from({ length: totalPages }).map((_, i) => /* @__PURE__ */ jsx(
1735
- "button",
1736
- {
1737
- onClick: () => onPageChange(i),
1738
- "aria-label": `Go to page ${i + 1}`,
1739
- "aria-current": currentPage === i ? "page" : void 0,
1740
- className: getBtnClass(currentPage === i),
1741
- children: i + 1
1742
- },
1743
- `page-${i}`
1744
- ));
1745
- }
1746
- const pages = [];
1747
- const startPage = Math.max(0, currentPage - Math.floor(maxVisiblePages / 2));
1748
- const endPage = Math.min(totalPages - 1, startPage + maxVisiblePages - 1);
1749
- if (startPage > 0) {
1750
- pages.push(
1751
- /* @__PURE__ */ jsx(
1752
- "button",
1753
- {
1754
- onClick: () => onPageChange(0),
1755
- "aria-label": "Go to page 1",
1756
- className: getBtnClass(currentPage === 0),
1757
- children: "1"
1758
- },
1759
- "page-0"
1760
- )
1761
- );
1762
- if (startPage > 1) {
1763
- pages.push(
1764
- /* @__PURE__ */ jsx(
1765
- "span",
1766
- {
1767
- className: "flex h-8 w-8 items-center justify-center border-y border-primary/5 border-r border-primary/5 !border-primary/5 !bg-background text-muted-foreground text-xs -ml-px",
1768
- "aria-hidden": "true",
1769
- children: "..."
1770
- },
1771
- "ellipsis-start"
1772
- )
1773
- );
1774
- }
1775
- }
1776
- for (let i = startPage; i <= endPage; i++) {
1777
- pages.push(
1778
- /* @__PURE__ */ jsx(
1779
- "button",
1780
- {
1781
- onClick: () => onPageChange(i),
1782
- "aria-label": `Go to page ${i + 1}`,
1783
- "aria-current": currentPage === i ? "page" : void 0,
1784
- className: getBtnClass(currentPage === i),
1785
- children: i + 1
1786
- },
1787
- i
1788
- )
1789
- );
1790
- }
1791
- if (endPage < totalPages - 1) {
1792
- if (endPage < totalPages - 2) {
1793
- pages.push(
1794
- /* @__PURE__ */ jsx(
1795
- "span",
1796
- {
1797
- className: "flex h-8 w-8 items-center justify-center border-y border-primary/5 border-r border-primary/5 !border-primary/5 !bg-background text-muted-foreground text-xs -ml-px",
1798
- "aria-hidden": "true",
1799
- children: "..."
1800
- },
1801
- "ellipsis-end"
1802
- )
1803
- );
1804
- }
1805
- pages.push(
1806
- /* @__PURE__ */ jsx(
1807
- "button",
1808
- {
1809
- onClick: () => onPageChange(totalPages - 1),
1810
- "aria-label": `Go to page ${totalPages}`,
1811
- className: getBtnClass(currentPage === totalPages - 1),
1812
- children: totalPages
1813
- },
1814
- totalPages - 1
1815
- )
1816
- );
1817
- }
1818
- return pages;
1819
- }
1820
- function TablePagination({
1821
- meta,
1822
- onPageChange,
1823
- onPageSizeChange,
1824
- config,
1825
- isLoading = false
1826
- }) {
1827
- const {
1828
- showPageSizeSelector = true,
1829
- pageSizeOptions = [10, 20, 30, 50],
1830
- maxVisiblePages = 5
1831
- } = config || {};
1832
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row w-full items-center justify-between gap-4 text-xs sm:text-sm text-muted-foreground p-4 border-t border-primary/5", children: [
1833
- /* @__PURE__ */ jsxs("div", { className: "whitespace-nowrap order-2 sm:order-1", children: [
1834
- "Showing ",
1835
- (meta.page - 1) * meta.limit + 1,
1836
- "-",
1837
- Math.min(meta.page * meta.limit, meta.total),
1838
- " of ",
1839
- meta.total,
1840
- " entries"
1841
- ] }),
1842
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-4 sm:gap-6 lg:gap-8 order-1 sm:order-2", children: [
1843
- showPageSizeSelector && /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
1844
- /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap hidden sm:inline-block", children: "Rows per page" }),
1845
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1846
- /* @__PURE__ */ jsx(
1847
- "select",
1848
- {
1849
- id: "pageSize",
1850
- value: meta.limit,
1851
- onChange: (e) => {
1852
- const newPageSize = Number(e.target.value);
1853
- onPageSizeChange(newPageSize);
1854
- },
1855
- className: "h-8 w-[70px] appearance-none rounded-none border border-primary/5 bg-background px-2 py-1 text-sm font-medium focus-visible:outline-none focus:ring-1 focus:ring-ring disabled:opacity-50 hover-muted cursor-pointer",
1856
- disabled: isLoading,
1857
- children: pageSizeOptions.map((size) => /* @__PURE__ */ jsx("option", { value: size, children: size }, size))
1858
- }
1859
- ),
1860
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-muted-foreground", children: /* @__PURE__ */ jsx(
1861
- "svg",
1862
- {
1863
- className: "h-3 w-3",
1864
- fill: "none",
1865
- viewBox: "0 0 24 24",
1866
- stroke: "currentColor",
1867
- children: /* @__PURE__ */ jsx(
1868
- "path",
1869
- {
1870
- strokeLinecap: "round",
1871
- strokeLinejoin: "round",
1872
- strokeWidth: 2,
1873
- d: "M19 9l-7 7-7-7"
1874
- }
1875
- )
1876
- }
1877
- ) })
1878
- ] })
1879
- ] }),
1880
- /* @__PURE__ */ jsxs("div", { className: "flex items-center -space-x-px", children: [
1881
- /* @__PURE__ */ jsx(
1882
- "button",
1883
- {
1884
- onClick: () => onPageChange(0),
1885
- disabled: meta.page === 0 || isLoading,
1886
- className: "hidden sm:flex h-8 w-8 items-center justify-center rounded-none border border-primary/5 bg-background hover-muted disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring z-10",
1887
- "aria-label": "First page",
1888
- children: /* @__PURE__ */ jsx(ChevronsLeft, { className: "h-4 w-4" })
1889
- }
1890
- ),
1891
- /* @__PURE__ */ jsx(
1892
- "button",
1893
- {
1894
- onClick: () => onPageChange(meta.page - 1),
1895
- disabled: meta.page === 0 || isLoading,
1896
- className: "flex h-8 w-8 items-center justify-center rounded-none sm:rounded-none border border-primary/5 bg-background hover-muted disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring z-10",
1897
- "aria-label": "Previous page",
1898
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
1899
- }
1900
- ),
1901
- /* @__PURE__ */ jsx("div", { className: "flex", children: renderPageNumbers(
1902
- meta.page,
1903
- meta.totalPages,
1904
- maxVisiblePages,
1905
- onPageChange
1906
- ) }),
1907
- /* @__PURE__ */ jsx(
1908
- "button",
1909
- {
1910
- onClick: () => onPageChange(meta.page + 1),
1911
- disabled: meta.page >= meta.totalPages - 1 || isLoading,
1912
- className: "flex h-8 w-8 items-center justify-center rounded-none sm:rounded-none border-y border-primary/5 border-x border-primary/5 sm :border-r border-primary/5 bg-background hover-muted disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring z-10",
1913
- "aria-label": "Next page",
1914
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
1915
- }
1916
- ),
1917
- /* @__PURE__ */ jsx(
1918
- "button",
1919
- {
1920
- onClick: () => onPageChange(meta.totalPages - 1),
1921
- disabled: meta.page >= meta.totalPages - 1 || isLoading,
1922
- className: "hidden sm:flex h-8 w-8 items-center justify-center rounded-none border border-primary/5 bg-background hover-muted disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring z-10",
1923
- "aria-label": "Last page",
1924
- children: /* @__PURE__ */ jsx(ChevronsRight, { className: "h-4 w-4" })
1925
- }
1926
- )
1927
- ] }),
1928
- /* @__PURE__ */ jsxs("div", { className: "whitespace-nowrap hidden sm:block", children: [
1929
- "Page ",
1930
- meta.page + 1,
1931
- " of ",
1932
- meta.totalPages
1933
- ] })
1934
- ] })
2207
+ return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center justify-center gap-4 p-16 text-center text-muted-foreground", children: [
2208
+ /* @__PURE__ */ jsx32("div", { className: "flex h-12 w-12 items-center justify-center rounded-md bg-primary/5", children: /* @__PURE__ */ jsx32(FileQuestion, { className: "h-6 w-6" }) }),
2209
+ /* @__PURE__ */ jsx32("span", { className: "text-sm font-medium", children: message })
1935
2210
  ] });
1936
2211
  }
1937
- var GrayBar = ({ className }) => /* @__PURE__ */ jsx(Skeleton, { className });
2212
+
2213
+ // src/components/table-skeleton.tsx
2214
+ import { Fragment, jsx as jsx33, jsxs as jsxs12 } from "react/jsx-runtime";
2215
+ var GrayBar = ({ className }) => /* @__PURE__ */ jsx33(Skeleton, { className });
1938
2216
  var TableSkeleton = ({
1939
2217
  columns = 5,
1940
2218
  rowCount = 8,
1941
2219
  hideWrapper = false,
1942
2220
  hideFooter = false
1943
2221
  }) => {
1944
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
1945
- /* @__PURE__ */ jsx("div", { className: "border-0 rounded-none shadow-none", children: /* @__PURE__ */ jsxs(Table, { children: [
1946
- /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: columns }).map((_, colIdx) => /* @__PURE__ */ jsx(TableHead, { className: "py-3", children: colIdx === 0 ? /* @__PURE__ */ jsx(GrayBar, { className: "h-4 w-4" }) : colIdx === columns - 1 ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4 rounded-none" }) }) : colIdx === 1 ? /* @__PURE__ */ jsx(GrayBar, { className: "h-4 w-[70%] max-w-[180px]" }) : /* @__PURE__ */ jsx(GrayBar, { className: "h-4 w-[60%] max-w-[120px]" }) }, `skeleton-header-${colIdx}`)) }) }),
1947
- /* @__PURE__ */ jsx(TableBody, { children: Array.from({ length: rowCount }).map((_, rowIdx) => /* @__PURE__ */ jsx(TableRow, { className: "border-b border-primary/5", children: Array.from({ length: columns }).map((_2, colIdx) => /* @__PURE__ */ jsx(TableCell, { className: "py-3", children: colIdx === 0 ? /* @__PURE__ */ jsx(GrayBar, { className: "h-4 w-4" }) : colIdx === columns - 1 ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-8 rounded-none" }) }) : colIdx === 1 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1948
- /* @__PURE__ */ jsx(Skeleton, { className: "w-9 rounded-none shrink-0" }),
1949
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 flex-1", children: [
1950
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-[120px]" }),
1951
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-[80px]" })
2222
+ const content = /* @__PURE__ */ jsxs12(Fragment, { children: [
2223
+ /* @__PURE__ */ jsx33("div", { className: "border-0 rounded-none shadow-none", children: /* @__PURE__ */ jsxs12(Table, { children: [
2224
+ /* @__PURE__ */ jsx33(TableHeader, { children: /* @__PURE__ */ jsx33(TableRow, { children: Array.from({ length: columns }).map((_, colIdx) => /* @__PURE__ */ jsx33(TableHead, { className: "py-3", children: colIdx === 0 ? /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-4" }) : colIdx === columns - 1 ? /* @__PURE__ */ jsx33("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx33(Skeleton, { className: "h-4 w-4 rounded-sm" }) }) : colIdx === 1 ? /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-[70%] max-w-[180px]" }) : /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-[60%] max-w-[120px]" }) }, `skeleton-header-${colIdx}`)) }) }),
2225
+ /* @__PURE__ */ jsx33(TableBody, { children: Array.from({ length: rowCount }).map((_, rowIdx) => /* @__PURE__ */ jsx33(TableRow, { className: "border-b border-border", children: Array.from({ length: columns }).map((_2, colIdx) => /* @__PURE__ */ jsx33(TableCell, { className: "py-3", children: colIdx === 0 ? /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-4" }) : colIdx === columns - 1 ? /* @__PURE__ */ jsx33("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx33(Skeleton, { className: "h-8 w-8 rounded-md" }) }) : colIdx === 1 ? /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-3", children: [
2226
+ /* @__PURE__ */ jsx33(Skeleton, { className: "w-9 rounded-md shrink-0" }),
2227
+ /* @__PURE__ */ jsxs12("div", { className: "space-y-1.5 flex-1", children: [
2228
+ /* @__PURE__ */ jsx33(Skeleton, { className: "h-4 w-[120px]" }),
2229
+ /* @__PURE__ */ jsx33(Skeleton, { className: "h-3 w-[80px]" })
1952
2230
  ] })
1953
- ] }) : /* @__PURE__ */ jsx(GrayBar, { className: "h-4 w-[60%] max-w-[120px]" }) }, colIdx)) }, rowIdx)) })
2231
+ ] }) : /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-[60%] max-w-[120px]" }) }, colIdx)) }, rowIdx)) })
1954
2232
  ] }) }),
1955
- !hideFooter && /* @__PURE__ */ jsx("div", { className: "table-footer border-t border-primary/5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-2 py-4 p-4", children: [
1956
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx(GrayBar, { className: "h-4 w-[120px]" }) }),
1957
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6", children: [
1958
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1959
- /* @__PURE__ */ jsx(GrayBar, { className: "h-4 w-20" }),
1960
- /* @__PURE__ */ jsx(GrayBar, { className: "h-8 w-[70px]" })
2233
+ !hideFooter && /* @__PURE__ */ jsx33("div", { className: "table-footer border-t border-border", children: /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between px-2 py-4", children: [
2234
+ /* @__PURE__ */ jsx33("div", { className: "flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-[120px]" }) }),
2235
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-6", children: [
2236
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
2237
+ /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-20" }),
2238
+ /* @__PURE__ */ jsx33(GrayBar, { className: "h-8 w-[70px]" })
1961
2239
  ] }),
1962
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1963
- /* @__PURE__ */ jsx(GrayBar, { className: "h-8 w-8" }),
1964
- /* @__PURE__ */ jsx(GrayBar, { className: "h-8 w-8" }),
1965
- /* @__PURE__ */ jsx(GrayBar, { className: "h-8 w-8" }),
1966
- /* @__PURE__ */ jsx(GrayBar, { className: "h-8 w-8" }),
1967
- /* @__PURE__ */ jsx(GrayBar, { className: "h-8 w-8" })
2240
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1", children: [
2241
+ /* @__PURE__ */ jsx33(GrayBar, { className: "h-8 w-8" }),
2242
+ /* @__PURE__ */ jsx33(GrayBar, { className: "h-8 w-8" }),
2243
+ /* @__PURE__ */ jsx33(GrayBar, { className: "h-8 w-8" }),
2244
+ /* @__PURE__ */ jsx33(GrayBar, { className: "h-8 w-8" }),
2245
+ /* @__PURE__ */ jsx33(GrayBar, { className: "h-8 w-8" })
1968
2246
  ] }),
1969
- /* @__PURE__ */ jsx(GrayBar, { className: "h-4 w-[120px]" })
2247
+ /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-[120px]" })
1970
2248
  ] })
1971
2249
  ] }) })
1972
2250
  ] });
1973
2251
  if (hideWrapper) {
1974
2252
  return content;
1975
2253
  }
1976
- return /* @__PURE__ */ jsx("div", { className: "table-wrapper rounded-none border border-primary/5 bg-card overflow-hidden", children: content });
2254
+ return /* @__PURE__ */ jsx33("div", { className: "table-wrapper rounded-md border border-border bg-card overflow-hidden", children: content });
1977
2255
  };
1978
2256
  TableSkeleton.displayName = "TableSkeleton";
1979
- function ResponsiveTableInner({
1980
- data,
1981
- columns,
1982
- onRowClick,
1983
- renderMobileCard,
1984
- className,
1985
- emptyMessage = "No results found.",
1986
- ariaLabel,
1987
- tableWrapperClassName,
1988
- footer
1989
- }, ref) {
1990
- const visibleMobileColumns = React5.useMemo(
1991
- () => columns.filter((col) => !col.hideOnMobile),
1992
- [columns]
1993
- );
1994
- const primaryColumn = React5.useMemo(() => {
1995
- return visibleMobileColumns.find(
1996
- (col) => col.key !== "select" && col.key !== "actions"
1997
- ) || visibleMobileColumns[0];
1998
- }, [visibleMobileColumns]);
1999
- const secondaryColumns = React5.useMemo(
2000
- () => visibleMobileColumns.filter((col) => col.key !== primaryColumn?.key),
2001
- [visibleMobileColumns, primaryColumn]
2002
- );
2003
- React5.useEffect(() => {
2004
- const isDev = typeof globalThis !== "undefined" && globalThis.process && globalThis.process.env?.NODE_ENV === "development";
2005
- if (isDev && visibleMobileColumns.length === 0) {
2006
- console.warn(
2007
- "ResponsiveTable: All columns are hidden on mobile (hideOnMobile: true). Consider showing at least one column for better mobile UX. Users will see empty card borders on mobile devices."
2008
- );
2009
- }
2010
- }, [visibleMobileColumns.length]);
2011
- const handleItemClick = React5.useCallback(
2012
- (item, e) => {
2013
- if (!onRowClick) return;
2014
- if (e) {
2015
- const target = e.target;
2016
- if (target.closest('[role="checkbox"]') || target.closest("button") || target.closest("a") || target.closest('[role^="menuitem"]') || target.closest("[data-actions]")) {
2017
- return;
2018
- }
2019
- }
2020
- onRowClick(item);
2021
- },
2022
- [onRowClick]
2023
- );
2024
- const handleCardKeyDown = React5.useCallback(
2025
- (item) => (e) => {
2026
- if (onRowClick && (e.key === "Enter" || e.key === " ")) {
2027
- e.preventDefault();
2028
- handleItemClick(item, e);
2029
- }
2030
- },
2031
- [handleItemClick, onRowClick]
2032
- );
2033
- if (data.length === 0) {
2034
- return /* @__PURE__ */ jsx(
2257
+
2258
+ // src/components/color-picker.tsx
2259
+ import { Pipette } from "lucide-react";
2260
+ import * as React9 from "react";
2261
+
2262
+ // src/lib/color/convert.ts
2263
+ var clamp01 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
2264
+ function normalizeHue(hue) {
2265
+ if (!Number.isFinite(hue)) return 0;
2266
+ const wrapped = hue % 360;
2267
+ return wrapped < 0 ? wrapped + 360 : wrapped;
2268
+ }
2269
+ function hsvToRgb({ h, s, v }) {
2270
+ const hue = normalizeHue(h);
2271
+ const sat = clamp01(s);
2272
+ const val = clamp01(v);
2273
+ const sector = hue / 60;
2274
+ const chroma = val * sat;
2275
+ const x = chroma * (1 - Math.abs(sector % 2 - 1));
2276
+ const base = val - chroma;
2277
+ let rgb;
2278
+ if (sector < 1) rgb = [chroma, x, 0];
2279
+ else if (sector < 2) rgb = [x, chroma, 0];
2280
+ else if (sector < 3) rgb = [0, chroma, x];
2281
+ else if (sector < 4) rgb = [0, x, chroma];
2282
+ else if (sector < 5) rgb = [x, 0, chroma];
2283
+ else rgb = [chroma, 0, x];
2284
+ return { r: rgb[0] + base, g: rgb[1] + base, b: rgb[2] + base };
2285
+ }
2286
+ function rgbToHsv({ r, g, b }) {
2287
+ const red = clamp01(r);
2288
+ const green = clamp01(g);
2289
+ const blue = clamp01(b);
2290
+ const max = Math.max(red, green, blue);
2291
+ const min = Math.min(red, green, blue);
2292
+ const chroma = max - min;
2293
+ let hue = 0;
2294
+ if (chroma !== 0) {
2295
+ if (max === red) hue = (green - blue) / chroma % 6;
2296
+ else if (max === green) hue = (blue - red) / chroma + 2;
2297
+ else hue = (red - green) / chroma + 4;
2298
+ hue *= 60;
2299
+ }
2300
+ return {
2301
+ h: normalizeHue(hue),
2302
+ s: max === 0 ? 0 : chroma / max,
2303
+ v: max
2304
+ };
2305
+ }
2306
+
2307
+ // src/lib/color/hex.ts
2308
+ var HEX = /^#?(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
2309
+ var clamp012 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
2310
+ function pair(channel) {
2311
+ const value = Number.isFinite(channel) ? clamp012(channel) : 0;
2312
+ return Math.round(value * 255).toString(16).padStart(2, "0");
2313
+ }
2314
+ function parseHex(input) {
2315
+ const text = input.trim();
2316
+ if (!HEX.test(text)) return null;
2317
+ const digits = text.replace("#", "");
2318
+ const short = digits.length < 6;
2319
+ const size = short ? 1 : 2;
2320
+ const channel = (index) => {
2321
+ const slice = digits.slice(index * size, index * size + size);
2322
+ return parseInt(short ? slice + slice : slice, 16) / 255;
2323
+ };
2324
+ const hasAlpha = digits.length === 4 || digits.length === 8;
2325
+ return {
2326
+ r: channel(0),
2327
+ g: channel(1),
2328
+ b: channel(2),
2329
+ alpha: hasAlpha ? channel(3) : 1
2330
+ };
2331
+ }
2332
+ function toHex(color, alpha = 1) {
2333
+ const opacity = Number.isFinite(alpha) ? clamp012(alpha) : 1;
2334
+ const opaque = `#${pair(color.r)}${pair(color.g)}${pair(color.b)}`;
2335
+ return opacity === 1 ? opaque : `${opaque}${pair(opacity)}`;
2336
+ }
2337
+
2338
+ // src/lib/color/picker-geometry.ts
2339
+ var clamp013 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
2340
+ function pointOnSurface(clientX, clientY, rect) {
2341
+ return {
2342
+ x: rect.width === 0 ? 0 : clamp013((clientX - rect.left) / rect.width),
2343
+ y: rect.height === 0 ? 0 : clamp013((clientY - rect.top) / rect.height)
2344
+ };
2345
+ }
2346
+ function saturationValueAt(point) {
2347
+ return { s: clamp013(point.x), v: 1 - clamp013(point.y) };
2348
+ }
2349
+ function surfacePointFor(s, v) {
2350
+ return { x: clamp013(s), y: 1 - clamp013(v) };
2351
+ }
2352
+ function hueAt(fraction) {
2353
+ const hue = clamp013(fraction) * 360;
2354
+ return hue >= 360 ? 0 : hue;
2355
+ }
2356
+ function huePosition(hue) {
2357
+ const wrapped = (hue % 360 + 360) % 360;
2358
+ return wrapped / 360;
2359
+ }
2360
+ function hueSliderValue(hue, max) {
2361
+ const step = Math.round(huePosition(hue) * (max + 1));
2362
+ return step > max ? max : step;
2363
+ }
2364
+
2365
+ // src/components/color-picker.tsx
2366
+ import { Fragment as Fragment2, jsx as jsx34, jsxs as jsxs13 } from "react/jsx-runtime";
2367
+ function toHsva(hex) {
2368
+ const parsed = parseHex(hex);
2369
+ if (!parsed) return { h: 0, s: 0, v: 0, a: 1 };
2370
+ const { r, g, b, alpha } = parsed;
2371
+ return { ...rgbToHsv({ r, g, b }), a: alpha };
2372
+ }
2373
+ function toHexString(hsva, withAlpha) {
2374
+ return toHex(hsvToRgb(hsva), withAlpha ? hsva.a : 1);
2375
+ }
2376
+ var HUE_MAX = 359;
2377
+ function hsvaFrom(color, alpha, currentHue) {
2378
+ const hsv = rgbToHsv(color);
2379
+ return { ...hsv, h: hsv.s === 0 ? currentHue : hsv.h, a: alpha };
2380
+ }
2381
+ var SLIDER = "h-3 w-full cursor-pointer appearance-none rounded-full";
2382
+ var CHECKERBOARD = "repeating-conic-gradient(#c8c8c8 0% 25%, #ffffff 0% 50%)";
2383
+ function eyeDropperSupported() {
2384
+ return typeof window !== "undefined" && "EyeDropper" in window;
2385
+ }
2386
+ function ColorPicker({
2387
+ color,
2388
+ onColorChange,
2389
+ swatches = [],
2390
+ onSwatchSelect,
2391
+ recentColors = [],
2392
+ showAlpha = false,
2393
+ className
2394
+ }) {
2395
+ const fieldId = React9.useId();
2396
+ const surfaceRef = React9.useRef(null);
2397
+ const [hsva, setHsva] = React9.useState(() => toHsva(color));
2398
+ const [draftHex, setDraftHex] = React9.useState(null);
2399
+ const rendered = toHexString(hsva, showAlpha);
2400
+ React9.useEffect(() => {
2401
+ const incoming = parseHex(color);
2402
+ if (incoming && toHex(incoming, showAlpha ? incoming.alpha : 1) !== rendered) {
2403
+ setHsva((prev) => hsvaFrom(incoming, incoming.alpha, prev.h));
2404
+ }
2405
+ }, [color, rendered, showAlpha]);
2406
+ const commit = (next) => {
2407
+ setHsva(next);
2408
+ setDraftHex(null);
2409
+ onColorChange(toHexString(next, showAlpha));
2410
+ };
2411
+ const trackPointer = (event) => {
2412
+ const rect = surfaceRef.current?.getBoundingClientRect();
2413
+ if (!rect) return;
2414
+ const { s, v } = saturationValueAt(
2415
+ pointOnSurface(event.clientX, event.clientY, rect)
2416
+ );
2417
+ commit({ ...hsva, s, v });
2418
+ };
2419
+ const nudge = (ds, dv) => {
2420
+ const { s, v } = saturationValueAt(
2421
+ surfacePointFor(hsva.s + ds, hsva.v + dv)
2422
+ );
2423
+ commit({ ...hsva, s, v });
2424
+ };
2425
+ const handleSurfaceKey = (event) => {
2426
+ const step = event.shiftKey ? 0.1 : 0.01;
2427
+ const moves = {
2428
+ ArrowLeft: [-step, 0],
2429
+ ArrowRight: [step, 0],
2430
+ ArrowUp: [0, step],
2431
+ ArrowDown: [0, -step]
2432
+ };
2433
+ const move = moves[event.key];
2434
+ if (!move) return;
2435
+ event.preventDefault();
2436
+ nudge(move[0], move[1]);
2437
+ };
2438
+ const [canPickFromScreen, setCanPickFromScreen] = React9.useState(false);
2439
+ React9.useEffect(() => {
2440
+ setCanPickFromScreen(eyeDropperSupported());
2441
+ }, []);
2442
+ const handle = surfacePointFor(hsva.s, hsva.v);
2443
+ const hueOnly = toHex(hsvToRgb({ h: hsva.h, s: 1, v: 1 }));
2444
+ const pickFromScreen = async () => {
2445
+ const ctor = window.EyeDropper;
2446
+ if (!ctor) return;
2447
+ let sampled;
2448
+ try {
2449
+ sampled = (await new ctor().open()).sRGBHex;
2450
+ } catch {
2451
+ return;
2452
+ }
2453
+ const parsed = parseHex(sampled);
2454
+ if (parsed) commit(hsvaFrom(parsed, hsva.a, hsva.h));
2455
+ };
2456
+ return /* @__PURE__ */ jsxs13("div", { className: cn("w-64 space-y-3", className), children: [
2457
+ /* @__PURE__ */ jsx34(
2035
2458
  "div",
2036
2459
  {
2037
- ref,
2038
- className: cn(
2039
- "p-8 text-center",
2040
- className
2041
- ),
2042
- children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage })
2460
+ ref: surfaceRef,
2461
+ role: "application",
2462
+ tabIndex: 0,
2463
+ "aria-label": `Saturation and brightness: ${Math.round(hsva.s * 100)}% saturation, ${Math.round(hsva.v * 100)}% brightness. Arrow keys adjust.`,
2464
+ className: "ring-offset-background focus-visible:ring-ring relative h-40 w-full cursor-crosshair touch-none rounded-md focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
2465
+ style: {
2466
+ backgroundColor: hueOnly,
2467
+ // Value on TOP of saturation. CSS paints the first layer nearest the
2468
+ // viewer, so the reverse order lets the opaque white end of the
2469
+ // saturation ramp cover the black end of the value ramp: the
2470
+ // bottom-left corner displays white while selecting black.
2471
+ backgroundImage: "linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent)"
2472
+ },
2473
+ onKeyDown: handleSurfaceKey,
2474
+ onPointerDown: (event) => {
2475
+ event.currentTarget.setPointerCapture(event.pointerId);
2476
+ trackPointer(event);
2477
+ },
2478
+ onPointerMove: (event) => {
2479
+ if (event.buttons === 1) trackPointer(event);
2480
+ },
2481
+ children: /* @__PURE__ */ jsx34(
2482
+ "span",
2483
+ {
2484
+ "aria-hidden": "true",
2485
+ className: "pointer-events-none absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm ring-1 ring-black/60",
2486
+ style: { left: `${handle.x * 100}%`, top: `${handle.y * 100}%` }
2487
+ }
2488
+ )
2043
2489
  }
2044
- );
2490
+ ),
2491
+ /* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-hue`, children: "Hue" }),
2492
+ /* @__PURE__ */ jsx34(
2493
+ "input",
2494
+ {
2495
+ id: `${fieldId}-hue`,
2496
+ type: "range",
2497
+ min: 0,
2498
+ max: HUE_MAX,
2499
+ step: 1,
2500
+ value: hueSliderValue(hsva.h, HUE_MAX),
2501
+ onChange: (event) => commit({ ...hsva, h: hueAt(+event.target.value / (HUE_MAX + 1)) }),
2502
+ className: SLIDER,
2503
+ style: {
2504
+ backgroundImage: "linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00)"
2505
+ }
2506
+ }
2507
+ ),
2508
+ showAlpha && /* @__PURE__ */ jsxs13(Fragment2, { children: [
2509
+ /* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-alpha`, children: "Opacity" }),
2510
+ /* @__PURE__ */ jsx34(
2511
+ "input",
2512
+ {
2513
+ id: `${fieldId}-alpha`,
2514
+ type: "range",
2515
+ min: 0,
2516
+ max: 100,
2517
+ step: 1,
2518
+ value: Math.round(hsva.a * 100),
2519
+ onChange: (event) => commit({ ...hsva, a: +event.target.value / 100 }),
2520
+ className: SLIDER,
2521
+ style: {
2522
+ // The ramp runs to the colour being edited, over a chequerboard,
2523
+ // so the track shows what the slider actually controls. Without
2524
+ // any background this rendered as a blank 12px strip whose only
2525
+ // label was screen-reader-only.
2526
+ backgroundImage: `linear-gradient(to right, transparent, ${toHexString({ ...hsva, a: 1 }, false)}), ${CHECKERBOARD}`,
2527
+ backgroundSize: "100% 100%, 8px 8px"
2528
+ }
2529
+ }
2530
+ )
2531
+ ] }),
2532
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
2533
+ /* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-hex`, children: "Hex colour" }),
2534
+ /* @__PURE__ */ jsx34(
2535
+ Input,
2536
+ {
2537
+ id: `${fieldId}-hex`,
2538
+ className: "font-mono",
2539
+ value: draftHex ?? rendered,
2540
+ onChange: (event) => {
2541
+ const text = event.target.value;
2542
+ setDraftHex(text);
2543
+ const parsed = parseHex(text);
2544
+ if (parsed) {
2545
+ setHsva(hsvaFrom(parsed, parsed.alpha, hsva.h));
2546
+ onColorChange(toHex(parsed, showAlpha ? parsed.alpha : 1));
2547
+ }
2548
+ },
2549
+ onBlur: () => setDraftHex(null)
2550
+ }
2551
+ ),
2552
+ canPickFromScreen && /* @__PURE__ */ jsx34(
2553
+ Button,
2554
+ {
2555
+ type: "button",
2556
+ variant: "outline",
2557
+ size: "icon",
2558
+ "aria-label": "Pick a colour from the screen",
2559
+ onClick: () => void pickFromScreen(),
2560
+ children: /* @__PURE__ */ jsx34(Pipette, { className: "size-4" })
2561
+ }
2562
+ )
2563
+ ] }),
2564
+ swatches.length > 0 && /* @__PURE__ */ jsxs13("div", { children: [
2565
+ /* @__PURE__ */ jsx34("p", { className: "text-muted-foreground mb-1 text-xs", children: "Presets" }),
2566
+ /* @__PURE__ */ jsx34("div", { className: "flex flex-wrap gap-1", children: swatches.map((swatch) => /* @__PURE__ */ jsx34(
2567
+ "button",
2568
+ {
2569
+ type: "button",
2570
+ title: swatch.label,
2571
+ "aria-label": swatch.label,
2572
+ className: "size-6 rounded border shadow-sm",
2573
+ style: { backgroundColor: swatch.color },
2574
+ onClick: () => onSwatchSelect?.(swatch)
2575
+ },
2576
+ swatch.id
2577
+ )) })
2578
+ ] }),
2579
+ recentColors.length > 0 && /* @__PURE__ */ jsxs13("div", { children: [
2580
+ /* @__PURE__ */ jsx34("p", { className: "text-muted-foreground mb-1 text-xs", children: "Recent" }),
2581
+ /* @__PURE__ */ jsx34("div", { className: "flex flex-wrap gap-1", children: recentColors.map((recent) => /* @__PURE__ */ jsx34(
2582
+ "button",
2583
+ {
2584
+ type: "button",
2585
+ title: recent,
2586
+ "aria-label": recent,
2587
+ className: "size-6 rounded border shadow-sm",
2588
+ style: { backgroundColor: recent },
2589
+ onClick: () => {
2590
+ const parsed = parseHex(recent);
2591
+ if (parsed) commit(hsvaFrom(parsed, parsed.alpha, hsva.h));
2592
+ }
2593
+ },
2594
+ recent
2595
+ )) })
2596
+ ] })
2597
+ ] });
2598
+ }
2599
+
2600
+ // src/components/context-menu.tsx
2601
+ import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
2602
+ import { Check as Check4, ChevronRight as ChevronRight2, Circle as Circle2 } from "lucide-react";
2603
+ import * as React10 from "react";
2604
+ import { jsx as jsx35, jsxs as jsxs14 } from "react/jsx-runtime";
2605
+ var menuItemBase2 = "cursor-pointer transition-colors data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
2606
+ var menuSurface = "z-50 max-h-[var(--radix-context-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 origin-[--radix-context-menu-content-transform-origin]";
2607
+ var ContextMenu = ContextMenuPrimitive.Root;
2608
+ var ContextMenuTrigger = ContextMenuPrimitive.Trigger;
2609
+ var ContextMenuGroup = ContextMenuPrimitive.Group;
2610
+ var ContextMenuSub = ContextMenuPrimitive.Sub;
2611
+ var ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
2612
+ var ContextMenuSubTrigger = React10.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
2613
+ ContextMenuPrimitive.SubTrigger,
2614
+ {
2615
+ ref,
2616
+ className: cn(
2617
+ "flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-muted [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
2618
+ menuItemBase2,
2619
+ inset && "pl-8",
2620
+ className
2621
+ ),
2622
+ ...props,
2623
+ children: [
2624
+ children,
2625
+ /* @__PURE__ */ jsx35(ChevronRight2, { className: "ml-auto" })
2626
+ ]
2627
+ }
2628
+ ));
2629
+ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
2630
+ var ContextMenuSubContent = React10.forwardRef(({ className, ...props }, ref) => {
2631
+ const portalContainer = usePortalContainer();
2632
+ return /* @__PURE__ */ jsx35(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx35(
2633
+ ContextMenuPrimitive.SubContent,
2634
+ {
2635
+ ref,
2636
+ className: cn(menuSurface, className),
2637
+ ...props
2638
+ }
2639
+ ) });
2640
+ });
2641
+ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
2642
+ var ContextMenuContent = React10.forwardRef(({ className, ...props }, ref) => {
2643
+ const portalContainer = usePortalContainer();
2644
+ return /* @__PURE__ */ jsx35(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx35(
2645
+ ContextMenuPrimitive.Content,
2646
+ {
2647
+ ref,
2648
+ className: cn(menuSurface, className),
2649
+ ...props
2650
+ }
2651
+ ) });
2652
+ });
2653
+ ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
2654
+ var ContextMenuItem = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx35(
2655
+ ContextMenuPrimitive.Item,
2656
+ {
2657
+ ref,
2658
+ className: cn(
2659
+ "relative flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
2660
+ menuItemBase2,
2661
+ inset && "pl-8",
2662
+ className
2663
+ ),
2664
+ ...props
2045
2665
  }
2046
- return /* @__PURE__ */ jsxs("div", { ref, className: cn("w-full", className), children: [
2047
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4 md:hidden", children: data.map((item) => {
2048
- const primaryValue = primaryColumn ? String(item[primaryColumn.key]) : String(item.id);
2049
- if (renderMobileCard) {
2050
- return /* @__PURE__ */ jsx(
2666
+ ));
2667
+ ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
2668
+ var ContextMenuCheckboxItem = React10.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs14(
2669
+ ContextMenuPrimitive.CheckboxItem,
2670
+ {
2671
+ ref,
2672
+ className: cn(
2673
+ "relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
2674
+ menuItemBase2,
2675
+ className
2676
+ ),
2677
+ checked,
2678
+ ...props,
2679
+ children: [
2680
+ /* @__PURE__ */ jsx35("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx35(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx35(Check4, { className: "h-4 w-4" }) }) }),
2681
+ children
2682
+ ]
2683
+ }
2684
+ ));
2685
+ ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
2686
+ var ContextMenuRadioItem = React10.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
2687
+ ContextMenuPrimitive.RadioItem,
2688
+ {
2689
+ ref,
2690
+ className: cn(
2691
+ "relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
2692
+ menuItemBase2,
2693
+ className
2694
+ ),
2695
+ ...props,
2696
+ children: [
2697
+ /* @__PURE__ */ jsx35("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx35(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx35(Circle2, { className: "h-2 w-2 fill-current" }) }) }),
2698
+ children
2699
+ ]
2700
+ }
2701
+ ));
2702
+ ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
2703
+ var ContextMenuLabel = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx35(
2704
+ ContextMenuPrimitive.Label,
2705
+ {
2706
+ ref,
2707
+ className: cn(
2708
+ "px-2 py-1.5 text-sm font-semibold text-foreground",
2709
+ inset && "pl-8",
2710
+ className
2711
+ ),
2712
+ ...props
2713
+ }
2714
+ ));
2715
+ ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
2716
+ var ContextMenuSeparator = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx35(
2717
+ ContextMenuPrimitive.Separator,
2718
+ {
2719
+ ref,
2720
+ className: cn("-mx-1 my-1 h-px bg-border", className),
2721
+ ...props
2722
+ }
2723
+ ));
2724
+ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
2725
+ var ContextMenuShortcut = ({
2726
+ className,
2727
+ ...props
2728
+ }) => /* @__PURE__ */ jsx35(
2729
+ "span",
2730
+ {
2731
+ className: cn(
2732
+ "ml-auto text-xs tracking-widest text-muted-foreground",
2733
+ className
2734
+ ),
2735
+ ...props
2736
+ }
2737
+ );
2738
+ ContextMenuShortcut.displayName = "ContextMenuShortcut";
2739
+
2740
+ // src/components/resizable.tsx
2741
+ import { GripVertical } from "lucide-react";
2742
+ import * as ResizablePrimitive from "react-resizable-panels";
2743
+ import { jsx as jsx36, jsxs as jsxs15 } from "react/jsx-runtime";
2744
+ var ResizablePanelGroup = ({
2745
+ className,
2746
+ ...props
2747
+ }) => /* @__PURE__ */ jsx36(
2748
+ ResizablePrimitive.Group,
2749
+ {
2750
+ className: cn("h-full w-full", className),
2751
+ ...props
2752
+ }
2753
+ );
2754
+ var ResizablePanel = ResizablePrimitive.Panel;
2755
+ var ResizableHandle = ({
2756
+ withGrip,
2757
+ className,
2758
+ children,
2759
+ ...props
2760
+ }) => /* @__PURE__ */ jsxs15(
2761
+ ResizablePrimitive.Separator,
2762
+ {
2763
+ className: cn(
2764
+ // The drawn line is 1px; the element around it is wider and transparent, so the pointer
2765
+ // target is comfortably larger than what it appears to grab (WCAG 2.5.8).
2766
+ "relative flex items-center justify-center bg-border",
2767
+ // Keyed off `aria-orientation`, which is what the separator actually carries, and read as
2768
+ // the ARIA spec defines it: the attribute describes the SEPARATOR, not the group. A
2769
+ // horizontal group puts its panels side by side, so its separator is a vertical line.
2770
+ "aria-[orientation=vertical]:w-px aria-[orientation=horizontal]:h-px",
2771
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
2772
+ // Reachable without precision pointing, without drawing a heavier divider: the hit area
2773
+ // grows across the line, so a vertical line widens and a horizontal one deepens.
2774
+ "after:absolute after:inset-0",
2775
+ "aria-[orientation=vertical]:after:-inset-x-1 aria-[orientation=horizontal]:after:-inset-y-1",
2776
+ className
2777
+ ),
2778
+ ...props,
2779
+ children: [
2780
+ withGrip ? /* @__PURE__ */ jsx36("div", { className: "z-10 flex h-4 w-3 items-center justify-center rounded-sm border border-border bg-border", children: /* @__PURE__ */ jsx36(GripVertical, { className: "h-2.5 w-2.5 text-muted-foreground" }) }) : null,
2781
+ children
2782
+ ]
2783
+ }
2784
+ );
2785
+
2786
+ // src/components/tree-view.tsx
2787
+ import { useVirtualizer } from "@tanstack/react-virtual";
2788
+ import { ChevronRight as ChevronRight3 } from "lucide-react";
2789
+ import * as React11 from "react";
2790
+ import { jsx as jsx37, jsxs as jsxs16 } from "react/jsx-runtime";
2791
+ var ROW_HEIGHT = 28;
2792
+ var INDENT_PER_LEVEL = 12;
2793
+ function textOf(node) {
2794
+ if (typeof node.textValue === "string") return node.textValue;
2795
+ return typeof node.label === "string" ? node.label : "";
2796
+ }
2797
+ function flatten(nodes, expanded) {
2798
+ const rows = [];
2799
+ const pending = [{ list: nodes, index: 0, level: 0 }];
2800
+ while (pending.length > 0) {
2801
+ const frame = pending[pending.length - 1];
2802
+ if (frame === void 0 || frame.index >= frame.list.length) {
2803
+ pending.pop();
2804
+ continue;
2805
+ }
2806
+ const node = frame.list[frame.index];
2807
+ const posInSet = frame.index;
2808
+ frame.index += 1;
2809
+ if (node === void 0) continue;
2810
+ const hasChildren = node.children !== void 0;
2811
+ rows.push({
2812
+ node,
2813
+ level: frame.level,
2814
+ setSize: frame.list.length,
2815
+ posInSet,
2816
+ parentId: frame.parentId,
2817
+ hasChildren
2818
+ });
2819
+ if (hasChildren && expanded.has(node.id)) {
2820
+ pending.push({
2821
+ list: node.children ?? [],
2822
+ index: 0,
2823
+ level: frame.level + 1,
2824
+ parentId: node.id
2825
+ });
2826
+ }
2827
+ }
2828
+ return rows;
2829
+ }
2830
+ function useControllable(controlled, fallback) {
2831
+ const [uncontrolled, setUncontrolled] = React11.useState(fallback);
2832
+ return [
2833
+ controlled === void 0 ? uncontrolled : controlled,
2834
+ setUncontrolled
2835
+ ];
2836
+ }
2837
+ var TreeView = React11.forwardRef(
2838
+ ({
2839
+ nodes,
2840
+ expandedIds,
2841
+ defaultExpandedIds,
2842
+ onExpandedChange,
2843
+ selectedId,
2844
+ defaultSelectedId,
2845
+ onSelectedChange,
2846
+ className,
2847
+ "aria-label": ariaLabel,
2848
+ "aria-labelledby": ariaLabelledBy,
2849
+ "aria-describedby": ariaDescribedBy,
2850
+ ...props
2851
+ }, forwardedRef) => {
2852
+ const scrollRef = React11.useRef(null);
2853
+ const attachScroll = React11.useCallback(
2854
+ (node) => {
2855
+ scrollRef.current = node;
2856
+ if (typeof forwardedRef === "function") forwardedRef(node);
2857
+ else if (forwardedRef !== null && forwardedRef !== void 0) {
2858
+ forwardedRef.current = node;
2859
+ }
2860
+ },
2861
+ [forwardedRef]
2862
+ );
2863
+ const [expandedState, setExpandedState] = useControllable(
2864
+ expandedIds === void 0 ? void 0 : [...expandedIds],
2865
+ [...defaultExpandedIds ?? []]
2866
+ );
2867
+ const expanded = React11.useMemo(
2868
+ () => new Set(expandedIds ?? expandedState),
2869
+ [expandedIds, expandedState]
2870
+ );
2871
+ const [selected, setSelected] = useControllable(
2872
+ selectedId === void 0 ? void 0 : selectedId,
2873
+ defaultSelectedId ?? null
2874
+ );
2875
+ const rows = React11.useMemo(
2876
+ () => flatten(nodes, expanded),
2877
+ [nodes, expanded]
2878
+ );
2879
+ const [activeId, setActiveId] = React11.useState(null);
2880
+ const activeIndex = Math.max(
2881
+ 0,
2882
+ rows.findIndex((row) => row.node.id === (activeId ?? selected))
2883
+ );
2884
+ const virtualizer = useVirtualizer({
2885
+ count: rows.length,
2886
+ getScrollElement: () => scrollRef.current,
2887
+ estimateSize: () => ROW_HEIGHT,
2888
+ overscan: 8
2889
+ });
2890
+ const commitExpanded = (next) => {
2891
+ const ids = [...next];
2892
+ if (expandedIds === void 0) setExpandedState(ids);
2893
+ onExpandedChange?.(ids);
2894
+ };
2895
+ const setExpansion = (id, open) => {
2896
+ const next = new Set(expanded);
2897
+ if (open) next.add(id);
2898
+ else next.delete(id);
2899
+ commitExpanded(next);
2900
+ };
2901
+ const choose = (id) => {
2902
+ if (selectedId === void 0) setSelected(id);
2903
+ onSelectedChange?.(id);
2904
+ };
2905
+ const focusRow = (index) => {
2906
+ const row = rows[index];
2907
+ if (row === void 0) return;
2908
+ setActiveId(row.node.id);
2909
+ virtualizer.scrollToIndex(index, { align: "auto" });
2910
+ requestAnimationFrame(() => {
2911
+ const element = scrollRef.current?.querySelector(
2912
+ `[data-tree-index="${index}"]`
2913
+ );
2914
+ element?.focus();
2915
+ });
2916
+ };
2917
+ const step = (from, delta) => {
2918
+ for (let index = from + delta; index >= 0 && index < rows.length; index += delta) {
2919
+ if (rows[index]?.node.disabled !== true) return index;
2920
+ }
2921
+ return from;
2922
+ };
2923
+ const typeahead = React11.useRef({ query: "", at: 0 });
2924
+ const onKeyDown = (event) => {
2925
+ const index = activeIndex;
2926
+ const row = rows[index];
2927
+ if (row === void 0) return;
2928
+ switch (event.key) {
2929
+ case "ArrowDown":
2930
+ event.preventDefault();
2931
+ focusRow(step(index, 1));
2932
+ return;
2933
+ case "ArrowUp":
2934
+ event.preventDefault();
2935
+ focusRow(step(index, -1));
2936
+ return;
2937
+ case "ArrowRight":
2938
+ event.preventDefault();
2939
+ if (row.hasChildren && !expanded.has(row.node.id)) {
2940
+ setExpansion(row.node.id, true);
2941
+ } else if (row.hasChildren) {
2942
+ for (let child = index + 1; child < rows.length && (rows[child]?.level ?? 0) > row.level; child += 1) {
2943
+ if (rows[child]?.parentId === row.node.id && rows[child]?.node.disabled !== true) {
2944
+ focusRow(child);
2945
+ break;
2946
+ }
2947
+ }
2948
+ }
2949
+ return;
2950
+ case "ArrowLeft":
2951
+ event.preventDefault();
2952
+ if (row.hasChildren && expanded.has(row.node.id)) {
2953
+ setExpansion(row.node.id, false);
2954
+ } else if (row.parentId !== void 0) {
2955
+ let ancestor = row.parentId;
2956
+ while (ancestor !== void 0) {
2957
+ const at = rows.findIndex(
2958
+ (candidate) => candidate.node.id === ancestor
2959
+ );
2960
+ if (at < 0) break;
2961
+ if (rows[at]?.node.disabled !== true) {
2962
+ focusRow(at);
2963
+ break;
2964
+ }
2965
+ ancestor = rows[at]?.parentId;
2966
+ }
2967
+ }
2968
+ return;
2969
+ case "Home":
2970
+ event.preventDefault();
2971
+ focusRow(rows[0]?.node.disabled === true ? step(0, 1) : 0);
2972
+ return;
2973
+ case "End": {
2974
+ event.preventDefault();
2975
+ const last = rows.length - 1;
2976
+ focusRow(rows[last]?.node.disabled === true ? step(last, -1) : last);
2977
+ return;
2978
+ }
2979
+ case "Enter":
2980
+ case " ":
2981
+ event.preventDefault();
2982
+ if (row.node.disabled !== true) choose(row.node.id);
2983
+ return;
2984
+ case "*": {
2985
+ event.preventDefault();
2986
+ const next = new Set(expanded);
2987
+ for (const sibling of rows) {
2988
+ if (sibling.parentId === row.parentId && sibling.hasChildren) {
2989
+ next.add(sibling.node.id);
2990
+ }
2991
+ }
2992
+ commitExpanded(next);
2993
+ return;
2994
+ }
2995
+ default:
2996
+ break;
2997
+ }
2998
+ if (event.key.length !== 1 || event.metaKey || event.ctrlKey || event.altKey) {
2999
+ return;
3000
+ }
3001
+ event.preventDefault();
3002
+ const now = Date.now();
3003
+ const state = typeahead.current;
3004
+ state.query = now - state.at > 500 ? event.key : state.query + event.key;
3005
+ state.at = now;
3006
+ const query = state.query.toLowerCase();
3007
+ for (let offset = 1; offset <= rows.length; offset += 1) {
3008
+ const candidate = rows[(index + offset) % rows.length];
3009
+ if (candidate === void 0 || candidate.node.disabled === true)
3010
+ continue;
3011
+ if (textOf(candidate.node).toLowerCase().startsWith(query)) {
3012
+ focusRow(rows.indexOf(candidate));
3013
+ return;
3014
+ }
3015
+ }
3016
+ };
3017
+ const virtualItems = virtualizer.getVirtualItems();
3018
+ const usable = (index) => rows[index]?.node.disabled !== true;
3019
+ const tabStopIndex = virtualItems.some((item) => item.index === activeIndex) && usable(activeIndex) ? activeIndex : virtualItems.find((item) => usable(item.index))?.index ?? -1;
3020
+ return /* @__PURE__ */ jsx37(
3021
+ "div",
3022
+ {
3023
+ ref: attachScroll,
3024
+ className: cn("overflow-auto", className),
3025
+ ...props,
3026
+ children: /* @__PURE__ */ jsx37(
2051
3027
  "div",
2052
3028
  {
2053
- onClick: (e) => handleItemClick(item, e),
2054
- role: onRowClick ? "button" : void 0,
2055
- tabIndex: onRowClick ? 0 : void 0,
2056
- onKeyDown: onRowClick ? handleCardKeyDown(item) : void 0,
2057
- className: onRowClick ? "cursor-pointer" : void 0,
2058
- "aria-label": onRowClick ? `View details for ${primaryValue}` : void 0,
2059
- children: renderMobileCard(item, visibleMobileColumns)
2060
- },
2061
- item.id
2062
- );
3029
+ role: "tree",
3030
+ "aria-label": ariaLabel,
3031
+ "aria-labelledby": ariaLabelledBy,
3032
+ "aria-describedby": ariaDescribedBy,
3033
+ onKeyDown,
3034
+ style: { height: virtualizer.getTotalSize(), position: "relative" },
3035
+ children: virtualItems.map((item) => {
3036
+ const row = rows[item.index];
3037
+ if (row === void 0) return null;
3038
+ const isSelected = selected === row.node.id;
3039
+ return /* @__PURE__ */ jsxs16(
3040
+ "div",
3041
+ {
3042
+ "data-tree-index": item.index,
3043
+ role: "treeitem",
3044
+ "aria-level": row.level + 1,
3045
+ "aria-setsize": row.setSize,
3046
+ "aria-posinset": row.posInSet + 1,
3047
+ "aria-selected": isSelected,
3048
+ "aria-expanded": row.hasChildren ? expanded.has(row.node.id) : void 0,
3049
+ "aria-disabled": row.node.disabled === true ? true : void 0,
3050
+ tabIndex: item.index === tabStopIndex ? 0 : -1,
3051
+ onFocus: () => setActiveId(row.node.id),
3052
+ onClick: () => {
3053
+ if (row.node.disabled === true) return;
3054
+ setActiveId(row.node.id);
3055
+ choose(row.node.id);
3056
+ },
3057
+ className: cn(
3058
+ "absolute left-0 flex w-full select-none items-center gap-1 rounded-sm pr-2 text-sm outline-none",
3059
+ "focus-visible:ring-1 focus-visible:ring-ring",
3060
+ row.node.disabled === true ? "pointer-events-none opacity-50" : "cursor-pointer",
3061
+ isSelected ? "bg-muted text-foreground" : "hover:bg-muted/50"
3062
+ ),
3063
+ style: {
3064
+ height: item.size,
3065
+ transform: `translateY(${item.start}px)`,
3066
+ paddingLeft: 4 + row.level * INDENT_PER_LEVEL
3067
+ },
3068
+ children: [
3069
+ /* @__PURE__ */ jsx37(
3070
+ "span",
3071
+ {
3072
+ "aria-hidden": "true",
3073
+ className: "flex size-4 shrink-0 items-center justify-center",
3074
+ onClick: (event) => {
3075
+ if (!row.hasChildren) return;
3076
+ event.stopPropagation();
3077
+ setExpansion(row.node.id, !expanded.has(row.node.id));
3078
+ },
3079
+ children: row.hasChildren ? /* @__PURE__ */ jsx37(
3080
+ ChevronRight3,
3081
+ {
3082
+ className: cn(
3083
+ "size-3.5 text-muted-foreground transition-transform",
3084
+ expanded.has(row.node.id) && "rotate-90"
3085
+ )
3086
+ }
3087
+ ) : null
3088
+ }
3089
+ ),
3090
+ row.node.icon !== void 0 ? /* @__PURE__ */ jsx37("span", { className: "flex size-4 shrink-0 items-center justify-center text-muted-foreground", children: row.node.icon }) : null,
3091
+ /* @__PURE__ */ jsx37("span", { className: "truncate", children: row.node.label })
3092
+ ]
3093
+ },
3094
+ row.node.id
3095
+ );
3096
+ })
3097
+ }
3098
+ )
3099
+ }
3100
+ );
3101
+ }
3102
+ );
3103
+ TreeView.displayName = "TreeView";
3104
+
3105
+ // src/components/slider.tsx
3106
+ import * as SliderPrimitive from "@radix-ui/react-slider";
3107
+ import * as React12 from "react";
3108
+
3109
+ // src/lib/dev-warn.ts
3110
+ var emitted = /* @__PURE__ */ new Set();
3111
+ var SPEAKING_ENVIRONMENTS = /* @__PURE__ */ new Set(["development", "test"]);
3112
+ function isDevelopmentRuntime() {
3113
+ if (typeof process === "undefined") return false;
3114
+ const env = process?.env?.NODE_ENV;
3115
+ return env !== void 0 && SPEAKING_ENVIRONMENTS.has(env);
3116
+ }
3117
+ function devWarnOnce(condition, message) {
3118
+ if (condition) return;
3119
+ if (!isDevelopmentRuntime()) return;
3120
+ if (emitted.has(message)) return;
3121
+ emitted.add(message);
3122
+ console.warn(`[@nextlyhq/ui] ${message}`);
3123
+ }
3124
+
3125
+ // src/components/slider.tsx
3126
+ import { jsx as jsx38, jsxs as jsxs17 } from "react/jsx-runtime";
3127
+ function thumbCount(value, defaultValue) {
3128
+ return Math.max(1, value?.length ?? defaultValue?.length ?? 1);
3129
+ }
3130
+ function hasAccessibleName(value) {
3131
+ return value !== void 0 && value.trim() !== "";
3132
+ }
3133
+ var Slider = React12.forwardRef(
3134
+ ({
3135
+ className,
3136
+ value,
3137
+ defaultValue,
3138
+ thumbs,
3139
+ orientation = "horizontal",
3140
+ "aria-label": ariaLabel,
3141
+ "aria-labelledby": ariaLabelledBy,
3142
+ ...props
3143
+ }, ref) => {
3144
+ const initialUncontrolledCount = React12.useRef(
3145
+ thumbCount(void 0, defaultValue)
3146
+ ).current;
3147
+ const count = value?.length ?? initialUncontrolledCount;
3148
+ const isEmptyDefault = defaultValue !== void 0 && defaultValue.length === 0;
3149
+ const isEmptyControlled = value !== void 0 && value.length === 0;
3150
+ devWarnOnce(
3151
+ !isEmptyDefault && !isEmptyControlled,
3152
+ "Slider: `value`/`defaultValue` must hold one number per thumb, and an empty array holds none \u2014 the control has nothing to slide. An empty `defaultValue` falls back to `min`; an empty `value` renders nothing at all, because a controlled slider cannot be given a value without taking state the caller owns. Render nothing until the value is loaded rather than passing `[]`."
3153
+ );
3154
+ if (isEmptyControlled) return null;
3155
+ const isNamed = (index) => {
3156
+ const own = thumbs?.[index];
3157
+ if (hasAccessibleName(own?.["aria-label"])) return true;
3158
+ if (hasAccessibleName(own?.["aria-labelledby"])) return true;
3159
+ return count === 1 && (hasAccessibleName(ariaLabel) || hasAccessibleName(ariaLabelledBy));
3160
+ };
3161
+ devWarnOnce(
3162
+ Array.from({ length: count }).every((_, i) => isNamed(i)),
3163
+ "Slider: every thumb needs an accessible name. A single thumb may take it from the root's `aria-label`/`aria-labelledby`; a range needs one `thumbs` entry per thumb, because the root's name is not inherited and two thumbs sharing one name are announced identically."
3164
+ );
3165
+ const ariaFor = (index) => {
3166
+ const supplied = thumbs?.[index] ?? {};
3167
+ const ownLabel = hasAccessibleName(supplied["aria-label"]) ? supplied["aria-label"] : void 0;
3168
+ const ownLabelledBy = hasAccessibleName(supplied["aria-labelledby"]) ? supplied["aria-labelledby"] : void 0;
3169
+ if (count !== 1) {
3170
+ return {
3171
+ ...supplied,
3172
+ "aria-label": ownLabel,
3173
+ "aria-labelledby": ownLabelledBy
3174
+ };
2063
3175
  }
2064
- return /* @__PURE__ */ jsxs(
2065
- Card,
3176
+ const namesItself = ownLabel !== void 0 || ownLabelledBy !== void 0;
3177
+ return {
3178
+ "aria-label": namesItself ? ownLabel : ariaLabel,
3179
+ "aria-labelledby": namesItself ? ownLabelledBy : ariaLabelledBy,
3180
+ "aria-valuetext": supplied["aria-valuetext"],
3181
+ "aria-describedby": supplied["aria-describedby"]
3182
+ };
3183
+ };
3184
+ const isVertical = orientation === "vertical";
3185
+ return (
3186
+ // `aria-label`/`aria-labelledby` are destructured out above rather than
3187
+ // spread here: left on the root they would be a second, roleless copy
3188
+ // of a name only the thumb is read for.
3189
+ /* @__PURE__ */ jsxs17(
3190
+ SliderPrimitive.Root,
2066
3191
  {
2067
- variant: onRowClick ? "interactive" : "default",
3192
+ ref,
2068
3193
  className: cn(
2069
- onRowClick && "cursor-pointer",
2070
- "transition-all duration-150"
3194
+ "relative flex touch-none select-none items-center",
3195
+ // WCAG 2.5.8 wants a 24px target. Padding alone does not reach it: the
3196
+ // thumb is absolutely positioned, so the cross-axis size is the 6px
3197
+ // track plus the padding — 22px with `py-2`. An explicit minimum
3198
+ // states the target rather than leaving it to arithmetic that moves
3199
+ // whenever the track thickness does.
3200
+ isVertical ? (
3201
+ // A vertical slider needs a LENGTH, and it cannot inherit one:
3202
+ // `h-full` inside an auto-height parent resolves to zero, leaving
3203
+ // a control with no track to drag along. A concrete default is
3204
+ // usable everywhere and, being a plain utility, is replaced by a
3205
+ // caller's own `h-*` — including `h-full`, for the fill-the-parent
3206
+ // case this default gives up.
3207
+ "h-44 min-w-6 flex-col px-2"
3208
+ ) : "min-h-6 w-full py-2",
3209
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
3210
+ className
2071
3211
  ),
2072
- onClick: (e) => handleItemClick(item, e),
2073
- role: onRowClick ? "button" : void 0,
2074
- tabIndex: onRowClick ? 0 : void 0,
2075
- onKeyDown: onRowClick ? handleCardKeyDown(item) : void 0,
2076
- "aria-label": onRowClick ? `View details for ${primaryValue}` : void 0,
3212
+ orientation,
3213
+ value,
3214
+ defaultValue: isEmptyDefault ? void 0 : defaultValue,
3215
+ ...props,
2077
3216
  children: [
2078
- primaryColumn ? /* @__PURE__ */ jsx(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: primaryColumn.render ? primaryColumn.render(item[primaryColumn.key], item) : String(item[primaryColumn.key]) }) }) : null,
2079
- secondaryColumns.length > 0 && /* @__PURE__ */ jsx(CardContent, { className: "pb-3", children: /* @__PURE__ */ jsx("dl", { className: "flex flex-col gap-2", children: secondaryColumns.map((column) => /* @__PURE__ */ jsxs(
2080
- "div",
2081
- {
2082
- className: "flex items-start justify-between gap-4 text-sm",
2083
- children: [
2084
- !column.hideLabelOnMobile && /* @__PURE__ */ jsxs("dt", { className: "text-muted-foreground min-w-[80px] shrink-0", children: [
2085
- column.label,
2086
- ":"
2087
- ] }),
2088
- /* @__PURE__ */ jsx(
2089
- "dd",
2090
- {
2091
- className: cn(
2092
- "font-medium flex-1",
2093
- !column.hideLabelOnMobile ? "text-right" : "text-left"
2094
- ),
2095
- children: column.render ? column.render(item[column.key], item) : String(item[column.key])
2096
- }
2097
- )
2098
- ]
2099
- },
2100
- String(column.key)
2101
- )) }) })
2102
- ]
2103
- },
2104
- item.id
2105
- );
2106
- }) }),
2107
- /* @__PURE__ */ jsx(
2108
- "div",
2109
- {
2110
- className: cn(
2111
- "table-wrapper hidden md:block overflow-hidden rounded-none border border-primary/5",
2112
- tableWrapperClassName
2113
- ),
2114
- children: /* @__PURE__ */ jsxs(Table, { "aria-label": ariaLabel || "Data table", children: [
2115
- /* @__PURE__ */ jsx(TableHeader, { className: "bg-[hsl(var(--table-header-bg))]", children: /* @__PURE__ */ jsx(TableRow, { children: columns.map((column) => /* @__PURE__ */ jsx(
2116
- TableHead,
2117
- {
2118
- className: column.headerClassName,
2119
- children: column.label
2120
- },
2121
- String(column.key)
2122
- )) }) }),
2123
- /* @__PURE__ */ jsx(TableBody, { children: data.map((item) => {
2124
- const primaryValue = primaryColumn ? String(item[primaryColumn.key]) : String(item.id);
2125
- return /* @__PURE__ */ jsx(
2126
- TableRow,
3217
+ /* @__PURE__ */ jsx38(
3218
+ SliderPrimitive.Track,
2127
3219
  {
2128
3220
  className: cn(
2129
- "hover-unified-table-row",
2130
- onRowClick && "cursor-pointer"
3221
+ "bg-secondary relative grow overflow-hidden rounded-full",
3222
+ isVertical ? "h-full w-1.5" : "h-1.5 w-full"
2131
3223
  ),
2132
- onClick: (e) => handleItemClick(item, e),
2133
- role: onRowClick ? "button" : void 0,
2134
- tabIndex: onRowClick ? 0 : void 0,
2135
- onKeyDown: onRowClick ? handleCardKeyDown(item) : void 0,
2136
- "aria-label": onRowClick ? `View details for ${primaryValue}` : void 0,
2137
- children: columns.map((column) => /* @__PURE__ */ jsx(
2138
- TableCell,
3224
+ children: /* @__PURE__ */ jsx38(
3225
+ SliderPrimitive.Range,
2139
3226
  {
2140
- className: column.cellClassName,
2141
- children: column.render ? column.render(item[column.key], item) : String(item[column.key])
2142
- },
2143
- String(column.key)
2144
- ))
3227
+ className: cn(
3228
+ "bg-primary absolute",
3229
+ isVertical ? "w-full" : "h-full"
3230
+ )
3231
+ }
3232
+ )
3233
+ }
3234
+ ),
3235
+ Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx38(
3236
+ SliderPrimitive.Thumb,
3237
+ {
3238
+ ...ariaFor(i),
3239
+ className: cn(
3240
+ "border-primary bg-background block h-4 w-4 rounded-full border-2",
3241
+ "ring-offset-background transition-colors",
3242
+ "focus-visible:ring-ring focus-visible:outline-none focus-visible:ring-2",
3243
+ "focus-visible:ring-offset-2",
3244
+ "disabled:pointer-events-none disabled:opacity-50"
3245
+ )
2145
3246
  },
2146
- item.id
2147
- );
2148
- }) })
2149
- ] })
2150
- }
2151
- ),
2152
- footer && /* @__PURE__ */ jsx("div", { className: "table-footer border-t border-primary/5 bg-[hsl(var(--table-header-bg))]", children: footer })
2153
- ] });
3247
+ i
3248
+ ))
3249
+ ]
3250
+ }
3251
+ )
3252
+ );
3253
+ }
3254
+ );
3255
+ Slider.displayName = SliderPrimitive.Root.displayName;
3256
+
3257
+ // src/lib/shortcuts/react.tsx
3258
+ import * as React13 from "react";
3259
+
3260
+ // src/lib/shortcuts/key-spec.ts
3261
+ function normalizeKey(key) {
3262
+ return [...key].length === 1 ? key.toLowerCase() : key;
3263
+ }
3264
+ function shiftIsMeaningful(key) {
3265
+ if (key.length > 1) return true;
3266
+ if (key === " ") return true;
3267
+ return /[\p{L}\p{N}]/u.test(key);
3268
+ }
3269
+ function parseKeys(spec) {
3270
+ const steps = spec.trim().split(/\s+/).filter(Boolean);
3271
+ if (steps.length === 0) {
3272
+ throw new Error(`Shortcut spec is empty: ${JSON.stringify(spec)}`);
3273
+ }
3274
+ return steps.map((step) => parseChord(step, spec));
3275
+ }
3276
+ function parseChord(step, spec) {
3277
+ const trailingPlusIsKey = step.length > 2 && step.endsWith("++");
3278
+ const body = trailingPlusIsKey ? step.slice(0, -1) : step;
3279
+ const parts = step === "+" ? ["+"] : body.split("+").filter(Boolean);
3280
+ let mod = false;
3281
+ let ctrl = false;
3282
+ let meta = false;
3283
+ let alt = false;
3284
+ let shift = false;
3285
+ let key;
3286
+ for (const raw of parts) {
3287
+ switch (raw.toLowerCase()) {
3288
+ case "mod":
3289
+ mod = true;
3290
+ break;
3291
+ case "ctrl":
3292
+ case "control":
3293
+ ctrl = true;
3294
+ break;
3295
+ case "meta":
3296
+ case "cmd":
3297
+ case "command":
3298
+ meta = true;
3299
+ break;
3300
+ case "alt":
3301
+ case "option":
3302
+ alt = true;
3303
+ break;
3304
+ case "shift":
3305
+ shift = true;
3306
+ break;
3307
+ case "space":
3308
+ key = " ";
3309
+ break;
3310
+ default:
3311
+ if (key !== void 0) {
3312
+ throw new Error(
3313
+ `Shortcut step "${step}" names two keys ("${key}" and "${raw}") in ${JSON.stringify(spec)}`
3314
+ );
3315
+ }
3316
+ key = raw;
3317
+ }
3318
+ }
3319
+ if (trailingPlusIsKey) {
3320
+ if (key !== void 0) {
3321
+ throw new Error(
3322
+ `Shortcut step has more than one key: ${JSON.stringify(step)} in ${JSON.stringify(spec)}`
3323
+ );
3324
+ }
3325
+ key = "+";
3326
+ }
3327
+ if (key === void 0) {
3328
+ throw new Error(
3329
+ `Shortcut step "${step}" names modifiers but no key, in ${JSON.stringify(spec)}`
3330
+ );
3331
+ }
3332
+ return { key: normalizeKey(key), mod, ctrl, meta, alt, shift };
3333
+ }
3334
+ function chordMatches(chord, key, state, isApple) {
3335
+ if (normalizeKey(key) !== chord.key) return false;
3336
+ const wantsCtrl = chord.ctrl || chord.mod && !isApple;
3337
+ const wantsMeta = chord.meta || chord.mod && isApple;
3338
+ if (state.metaKey !== wantsMeta) return false;
3339
+ const altGraph = state.getModifierState?.("AltGraph") ?? false;
3340
+ const synthetic = altGraph && [...chord.key].length === 1 && !wantsCtrl && !chord.alt;
3341
+ if (!synthetic) {
3342
+ if (state.ctrlKey !== wantsCtrl) return false;
3343
+ if (state.altKey !== chord.alt) return false;
3344
+ }
3345
+ if (shiftIsMeaningful(chord.key) && state.shiftKey !== chord.shift)
3346
+ return false;
3347
+ return true;
3348
+ }
3349
+ function detectApplePlatform() {
3350
+ if (typeof navigator === "undefined") return false;
3351
+ const candidate = navigator;
3352
+ const platform = candidate.userAgentData?.platform ?? navigator.platform ?? "";
3353
+ return /mac|iphone|ipad|ipod/i.test(platform);
2154
3354
  }
2155
- var ResponsiveTable = React5.forwardRef(ResponsiveTableInner);
2156
3355
 
2157
- // src/tailwind-preset.ts
2158
- var uiPreset = {
2159
- theme: {
2160
- extend: {
2161
- colors: {
2162
- border: "hsl(var(--border))",
2163
- input: "hsl(var(--input))",
2164
- ring: "hsl(var(--ring))",
2165
- background: "hsl(var(--background))",
2166
- foreground: "hsl(var(--foreground))",
2167
- primary: {
2168
- DEFAULT: "hsl(var(--primary))",
2169
- foreground: "hsl(var(--primary-foreground))"
2170
- },
2171
- secondary: {
2172
- DEFAULT: "hsl(var(--secondary))",
2173
- foreground: "hsl(var(--secondary-foreground))"
2174
- },
2175
- destructive: {
2176
- DEFAULT: "hsl(var(--destructive))",
2177
- foreground: "hsl(var(--destructive-foreground))"
2178
- },
2179
- success: {
2180
- DEFAULT: "hsl(var(--success))",
2181
- foreground: "hsl(var(--success-foreground))"
2182
- },
2183
- warning: {
2184
- DEFAULT: "hsl(var(--warning))",
2185
- foreground: "hsl(var(--warning-foreground))"
2186
- },
2187
- muted: {
2188
- DEFAULT: "hsl(var(--muted))",
2189
- foreground: "hsl(var(--muted-foreground))"
2190
- },
2191
- accent: {
2192
- DEFAULT: "hsl(var(--accent))",
2193
- foreground: "hsl(var(--accent-foreground))"
2194
- },
2195
- popover: {
2196
- DEFAULT: "hsl(var(--popover))",
2197
- foreground: "hsl(var(--popover-foreground))"
2198
- },
2199
- card: {
2200
- DEFAULT: "hsl(var(--card))",
2201
- foreground: "hsl(var(--card-foreground))"
3356
+ // src/lib/shortcuts/manager.ts
3357
+ var DEFAULT_SEQUENCE_TIMEOUT_MS = 1e3;
3358
+ function signature(event) {
3359
+ return event.code || event.key;
3360
+ }
3361
+ function eventTarget(event) {
3362
+ const path = event.composedPath?.();
3363
+ return path && path.length > 0 ? path[0] ?? null : event.target;
3364
+ }
3365
+ function asElement(target) {
3366
+ if (target === null || typeof target !== "object") return null;
3367
+ const node = target;
3368
+ if (node.nodeType !== 1 || typeof node.tagName !== "string") return null;
3369
+ return target;
3370
+ }
3371
+ function inputType(element) {
3372
+ if (element.tagName !== "INPUT") return "";
3373
+ const value = element.type;
3374
+ return typeof value === "string" ? value.toLowerCase() : "";
3375
+ }
3376
+ function controlOwnsKey(target, event) {
3377
+ if (event.ctrlKey || event.metaKey || event.altKey) return false;
3378
+ const element = asElement(target);
3379
+ if (!element) return false;
3380
+ const tag = element.tagName;
3381
+ const type = inputType(element);
3382
+ if (tag === "BUTTON" || type === "button" || type === "submit" || type === "reset" || type === "image") {
3383
+ return event.key === " " || event.key === "Enter";
3384
+ }
3385
+ if (tag === "A" && element.getAttribute("href") !== null) {
3386
+ return event.key === "Enter";
3387
+ }
3388
+ if (tag === "SUMMARY") return event.key === " " || event.key === "Enter";
3389
+ if (type === "checkbox") return event.key === " ";
3390
+ if (type === "color") return event.key === " " || event.key === "Enter";
3391
+ if (type === "file") return event.key === " " || event.key === "Enter";
3392
+ if (type === "range") {
3393
+ return event.key.startsWith("Arrow") || RANGE_KEYS.has(event.key);
3394
+ }
3395
+ if (type === "radio") {
3396
+ return event.key === " " || event.key.startsWith("Arrow");
3397
+ }
3398
+ return false;
3399
+ }
3400
+ function isTypingTarget(target) {
3401
+ const element = asElement(target);
3402
+ if (!element) return false;
3403
+ if (element.isContentEditable) return true;
3404
+ const tag = element.tagName;
3405
+ if (tag === "TEXTAREA") return true;
3406
+ if (tag === "SELECT") return true;
3407
+ if (tag === "INPUT") {
3408
+ return !NON_TEXT_INPUT_TYPES.has(inputType(element));
3409
+ }
3410
+ const role = element.getAttribute("role");
3411
+ return role !== null && TYPE_AHEAD_ROLES.has(role);
3412
+ }
3413
+ var NON_TEXT_INPUT_TYPES = /* @__PURE__ */ new Set([
3414
+ "button",
3415
+ "checkbox",
3416
+ "color",
3417
+ "file",
3418
+ "hidden",
3419
+ "image",
3420
+ "radio",
3421
+ "range",
3422
+ "reset",
3423
+ "submit"
3424
+ ]);
3425
+ function firesWhileTyping(prepared) {
3426
+ const explicit = prepared.binding.whenTyping;
3427
+ if (explicit !== void 0) return explicit;
3428
+ const first = prepared.keys[0];
3429
+ if (first === void 0) return false;
3430
+ return first.mod || first.ctrl || first.meta || first.alt || first.key === "Escape";
3431
+ }
3432
+ function createShortcutManager(options = {}) {
3433
+ const isApple = options.isApple ?? detectApplePlatform();
3434
+ const sequenceTimeoutMs = options.sequenceTimeoutMs ?? DEFAULT_SEQUENCE_TIMEOUT_MS;
3435
+ const now = options.now ?? (() => Date.now());
3436
+ const layers = /* @__PURE__ */ new Set();
3437
+ let nextSequence = 0;
3438
+ let pendingAt = null;
3439
+ let pendingLayer = null;
3440
+ const consumedPresses = /* @__PURE__ */ new Map();
3441
+ let pendingKey = null;
3442
+ function layerShape(bindings, options2) {
3443
+ const keys = bindings.map((b) => b.binding.keys).join("\0");
3444
+ return `${keys}${options2.depth}${options2.priority ?? 0}${options2.blocking === true}${options2.enabled !== false}`;
3445
+ }
3446
+ function blocking() {
3447
+ return ordered().some((layer) => layer.options.blocking === true);
3448
+ }
3449
+ function abandonSequence() {
3450
+ pendingAt = null;
3451
+ pressedEvents.length = 0;
3452
+ pendingLayer = null;
3453
+ pendingKey = null;
3454
+ }
3455
+ function prepare(bindings) {
3456
+ return bindings.map((binding) => ({
3457
+ binding,
3458
+ keys: parseKeys(binding.keys)
3459
+ }));
3460
+ }
3461
+ function ordered() {
3462
+ return [...layers].filter((layer) => layer.options.enabled !== false).sort(
3463
+ (a, b) => (b.options.priority ?? 0) - (a.options.priority ?? 0) || b.options.depth - a.options.depth || b.sequence - a.sequence
3464
+ );
3465
+ }
3466
+ function matchDepth(prepared, pressed) {
3467
+ if (pressed.length > prepared.keys.length) return "none";
3468
+ for (let i = 0; i < pressed.length; i++) {
3469
+ const chord = prepared.keys[i];
3470
+ const event = pressed[i];
3471
+ if (chord === void 0 || event === void 0) return "none";
3472
+ if (!chordMatches(chord, event.key, event, isApple)) return "none";
3473
+ }
3474
+ return pressed.length === prepared.keys.length ? "exact" : "prefix";
3475
+ }
3476
+ function fire(prepared, event, invoke) {
3477
+ if (prepared.binding.preventDefault !== false) event.preventDefault();
3478
+ if (invoke) prepared.binding.run(event);
3479
+ }
3480
+ function insertsText(event, typing) {
3481
+ if (event.key === "Tab")
3482
+ return !event.ctrlKey && !event.metaKey && !event.altKey;
3483
+ if (!typing) return false;
3484
+ const altGraph = event.getModifierState?.("AltGraph") ?? false;
3485
+ if (!altGraph && (event.ctrlKey || event.metaKey)) {
3486
+ const letter = event.key.length === 1 ? event.key.toLowerCase() : event.key;
3487
+ if (letter === "z" && event.shiftKey) return !event.altKey;
3488
+ if (letter === REDO_LETTER)
3489
+ return !isApple && !event.shiftKey && !event.altKey;
3490
+ if (EDITING_NAVIGATION.has(event.key)) return !event.altKey || isApple;
3491
+ if (event.shiftKey || event.altKey) return false;
3492
+ return EDITING_LETTERS.has(letter);
3493
+ }
3494
+ if (!altGraph && event.altKey) {
3495
+ if ((event.key === "ArrowDown" || event.key === "ArrowUp") && asElement(eventTarget(event))?.tagName === "SELECT") {
3496
+ return true;
3497
+ }
3498
+ if (!isApple) return false;
3499
+ if (EDITING_NAVIGATION.has(event.key)) return true;
3500
+ }
3501
+ if (event.key === "Dead" || event.key === "Process") return true;
3502
+ if ([...event.key].length === 1) return true;
3503
+ if (AMBIGUOUS_KEYS.has(event.key)) return targetOwnsAmbiguousKey(event);
3504
+ return FIELD_KEYS.has(event.key);
3505
+ }
3506
+ function offer(pressed, event, typing, invoke) {
3507
+ for (const layer of ordered()) {
3508
+ const mayMatch = pressed.length <= 1 || pendingLayer === null || layer === pendingLayer;
3509
+ if (mayMatch) {
3510
+ let prefixed = false;
3511
+ for (const prepared of layer.bindings) {
3512
+ if (typing && !firesWhileTyping(prepared)) continue;
3513
+ if (prepared.binding.when && !prepared.binding.when()) continue;
3514
+ const depth = matchDepth(prepared, pressed);
3515
+ if (depth === "exact") {
3516
+ fire(prepared, event, invoke);
3517
+ return "fired";
3518
+ }
3519
+ if (depth === "prefix") prefixed = true;
2202
3520
  }
2203
- },
2204
- borderRadius: {
2205
- lg: "var(--radius)",
2206
- md: "calc(var(--radius) - 2px)",
2207
- sm: "calc(var(--radius) - 4px)"
2208
- },
2209
- keyframes: {
2210
- "accordion-down": {
2211
- from: { height: "0" },
2212
- to: { height: "var(--radix-accordion-content-height)" }
3521
+ if (prefixed) {
3522
+ pendingLayer = layer;
3523
+ event.preventDefault();
3524
+ return "pending";
3525
+ }
3526
+ }
3527
+ if (layer.options.blocking) return "blocked";
3528
+ }
3529
+ return "none";
3530
+ }
3531
+ function warnOnPrefixConflicts(prepared, layerName) {
3532
+ const resolved = (chord) => {
3533
+ const ctrl = chord.ctrl || chord.mod && !isApple;
3534
+ const meta = chord.meta || chord.mod && isApple;
3535
+ const shift = shiftIsMeaningful(chord.key) ? chord.shift : false;
3536
+ return `${chord.key}\0${ctrl}${meta}${chord.alt}${shift}`;
3537
+ };
3538
+ const sameChord = (a, b) => resolved(a) === resolved(b);
3539
+ for (const short of prepared) {
3540
+ for (const long of prepared) {
3541
+ if (short === long || short.keys.length >= long.keys.length) continue;
3542
+ if (short.binding.when !== void 0) continue;
3543
+ if (!firesWhileTyping(short) && firesWhileTyping(long)) continue;
3544
+ if (short.keys.every((chord, i) => sameChord(chord, long.keys[i]))) {
3545
+ devWarnOnce(
3546
+ false,
3547
+ `shortcuts: in layer "${layerName}", "${short.binding.keys}" is a prefix of "${long.binding.keys}", so the longer one can never fire. Bind one or the other.`
3548
+ );
3549
+ }
3550
+ }
3551
+ }
3552
+ }
3553
+ const watchers = /* @__PURE__ */ new Set();
3554
+ let snapshot = null;
3555
+ function computeSnapshot() {
3556
+ return ordered().flatMap(
3557
+ (layer) => layer.bindings.map((prepared) => ({
3558
+ keys: prepared.binding.keys,
3559
+ description: prepared.binding.description,
3560
+ layer: layer.options.name
3561
+ }))
3562
+ );
3563
+ }
3564
+ function sameShortcuts(a, b) {
3565
+ return a.length === b.length && a.every(
3566
+ (entry, index) => entry.keys === b[index]?.keys && entry.description === b[index]?.description && entry.layer === b[index]?.layer
3567
+ );
3568
+ }
3569
+ function changed() {
3570
+ const previous = snapshot;
3571
+ snapshot = null;
3572
+ if (watchers.size === 0) return;
3573
+ const next = computeSnapshot();
3574
+ if (previous && sameShortcuts(previous, next)) {
3575
+ snapshot = previous;
3576
+ return;
3577
+ }
3578
+ snapshot = next;
3579
+ for (const watcher of watchers) watcher();
3580
+ }
3581
+ const pressedEvents = [];
3582
+ function runOffer(pressed, event, typing) {
3583
+ try {
3584
+ return offer(pressed, event, typing, true);
3585
+ } catch (error) {
3586
+ abandonSequence();
3587
+ consumedPresses.delete(signature(event));
3588
+ throw error;
3589
+ }
3590
+ }
3591
+ function handle(event) {
3592
+ if (typeof event.key !== "string") return false;
3593
+ if (event.defaultPrevented) {
3594
+ abandonSequence();
3595
+ return true;
3596
+ }
3597
+ if (event.isComposing) {
3598
+ abandonSequence();
3599
+ return true;
3600
+ }
3601
+ if (MODIFIER_KEYS.has(event.key)) return blocking();
3602
+ if (controlOwnsKey(eventTarget(event), event)) {
3603
+ abandonSequence();
3604
+ return true;
3605
+ }
3606
+ const typing = isTypingTarget(eventTarget(event));
3607
+ if (event.repeat) {
3608
+ if (pendingKey !== signature(event)) {
3609
+ abandonSequence();
3610
+ }
3611
+ const held = consumedPresses.get(signature(event));
3612
+ if (held) {
3613
+ if (held.prevented) {
3614
+ event.preventDefault();
3615
+ } else {
3616
+ const still = offer([event], event, typing, false);
3617
+ if (still !== "fired" && !insertsText(event, typing)) {
3618
+ event.preventDefault();
3619
+ }
3620
+ }
3621
+ return true;
3622
+ }
3623
+ const repeated = offer([event], event, typing, false);
3624
+ if (repeated === "blocked" && !insertsText(event, typing)) {
3625
+ event.preventDefault();
3626
+ }
3627
+ return repeated !== "none";
3628
+ }
3629
+ if (pendingAt !== null && now() - pendingAt > sequenceTimeoutMs) {
3630
+ abandonSequence();
3631
+ }
3632
+ pressedEvents.push(event);
3633
+ let outcome = runOffer(pressedEvents, event, typing);
3634
+ if (pressedEvents.length > 1 && (outcome === "none" || outcome === "blocked")) {
3635
+ abandonSequence();
3636
+ pressedEvents.push(event);
3637
+ outcome = runOffer(pressedEvents, event, typing);
3638
+ }
3639
+ if (outcome === "pending") {
3640
+ pendingAt = now();
3641
+ pendingKey = signature(event);
3642
+ consumedPresses.set(signature(event), {
3643
+ prevented: event.defaultPrevented
3644
+ });
3645
+ return true;
3646
+ }
3647
+ abandonSequence();
3648
+ if (outcome === "blocked") {
3649
+ if (!insertsText(event, typing)) event.preventDefault();
3650
+ }
3651
+ const consumed = outcome === "fired" || outcome === "blocked";
3652
+ if (consumed) {
3653
+ consumedPresses.set(signature(event), {
3654
+ prevented: event.defaultPrevented
3655
+ });
3656
+ } else {
3657
+ consumedPresses.delete(signature(event));
3658
+ }
3659
+ return consumed;
3660
+ }
3661
+ return {
3662
+ register(bindings, layerOptions) {
3663
+ const prepared = prepare(bindings);
3664
+ const layer = {
3665
+ options: layerOptions,
3666
+ bindings: prepared,
3667
+ sequence: nextSequence++,
3668
+ shape: layerShape(prepared, layerOptions)
3669
+ };
3670
+ warnOnPrefixConflicts(layer.bindings, layerOptions.name);
3671
+ layers.add(layer);
3672
+ changed();
3673
+ return {
3674
+ update(nextBindings, nextOptions) {
3675
+ layer.bindings = prepare(nextBindings);
3676
+ layer.options = nextOptions;
3677
+ warnOnPrefixConflicts(layer.bindings, nextOptions.name);
3678
+ const shape = layerShape(layer.bindings, nextOptions);
3679
+ const shapeChanged = shape !== layer.shape;
3680
+ layer.shape = shape;
3681
+ if (shapeChanged && pendingLayer === layer) abandonSequence();
3682
+ changed();
2213
3683
  },
2214
- "accordion-up": {
2215
- from: { height: "var(--radix-accordion-content-height)" },
2216
- to: { height: "0" }
3684
+ dispose() {
3685
+ layers.delete(layer);
3686
+ changed();
3687
+ if (pendingLayer === layer) abandonSequence();
2217
3688
  }
2218
- },
2219
- animation: {
2220
- "accordion-down": "accordion-down 0.3s cubic-bezier(0.87, 0, 0.13, 1)",
2221
- "accordion-up": "accordion-up 0.3s cubic-bezier(0.87, 0, 0.13, 1)"
3689
+ };
3690
+ },
3691
+ handle,
3692
+ attach(target) {
3693
+ const listener = (event) => {
3694
+ try {
3695
+ if (handle(event)) event.stopPropagation();
3696
+ } catch (error) {
3697
+ event.stopPropagation();
3698
+ throw error;
3699
+ }
3700
+ };
3701
+ target.addEventListener("keydown", listener);
3702
+ return () => {
3703
+ target.removeEventListener("keydown", listener);
3704
+ abandonSequence();
3705
+ consumedPresses.clear();
3706
+ };
3707
+ },
3708
+ subscribe(onChange) {
3709
+ watchers.add(onChange);
3710
+ return () => {
3711
+ watchers.delete(onChange);
3712
+ };
3713
+ },
3714
+ activeBindings() {
3715
+ if (snapshot) return snapshot;
3716
+ snapshot = computeSnapshot();
3717
+ return snapshot;
3718
+ }
3719
+ };
3720
+ }
3721
+ var MODIFIER_KEYS = /* @__PURE__ */ new Set([
3722
+ "Control",
3723
+ "Meta",
3724
+ "Alt",
3725
+ "Shift",
3726
+ // A dedicated AltGraph key reports its own keydown before the character-producing one. Without
3727
+ // it here, pressing AltGraph mid-sequence abandons the sequence before the character that would
3728
+ // have completed it ever arrives.
3729
+ "AltGraph"
3730
+ ]);
3731
+ var TYPE_AHEAD_ROLES = /* @__PURE__ */ new Set([
3732
+ "textbox",
3733
+ "combobox",
3734
+ "listbox",
3735
+ // The focused element inside an open listbox is the OPTION, and it is what the event reports;
3736
+ // the listbox itself is only its ancestor.
3737
+ "option",
3738
+ "menu",
3739
+ "menuitem",
3740
+ "menuitemcheckbox",
3741
+ "menuitemradio"
3742
+ ]);
3743
+ var RANGE_KEYS = /* @__PURE__ */ new Set(["Home", "End", "PageUp", "PageDown"]);
3744
+ var EDITING_LETTERS = /* @__PURE__ */ new Set(["a", "c", "v", "x", "z"]);
3745
+ var REDO_LETTER = "y";
3746
+ var EDITING_NAVIGATION = /* @__PURE__ */ new Set([
3747
+ "Insert",
3748
+ "ArrowLeft",
3749
+ "ArrowRight",
3750
+ "ArrowUp",
3751
+ "ArrowDown",
3752
+ "Home",
3753
+ "End",
3754
+ "Backspace",
3755
+ "Delete"
3756
+ ]);
3757
+ var AMBIGUOUS_KEYS = /* @__PURE__ */ new Set(["Enter", "PageUp", "PageDown"]);
3758
+ function targetOwnsAmbiguousKey(event) {
3759
+ const element = asElement(eventTarget(event));
3760
+ if (element === null) return false;
3761
+ const multiline = element.tagName === "TEXTAREA" || element.isContentEditable;
3762
+ if (event.key === "Enter") return multiline;
3763
+ return multiline || element.tagName === "SELECT";
3764
+ }
3765
+ var FIELD_KEYS = /* @__PURE__ */ new Set([
3766
+ "Backspace",
3767
+ "Delete",
3768
+ "ArrowUp",
3769
+ "ArrowDown",
3770
+ "ArrowLeft",
3771
+ "ArrowRight",
3772
+ "Home",
3773
+ "End",
3774
+ // Shift+Insert pastes and carries no ctrl or meta, so it arrives here rather than at the
3775
+ // chord branch where Ctrl+Insert is recognised.
3776
+ "Insert",
3777
+ // Tab moves focus, and a blocking layer must NOT take it. The documented case for blocking is
3778
+ // a modal, whose focus trap only calls `preventDefault()` at the first and last tabbable
3779
+ // element — ordinary moves between the controls inside it rely on the browser default.
3780
+ // Suppressing every Tab therefore pinned focus to one control in exactly the situation
3781
+ // blocking exists to serve. A layer that genuinely wants Tab binds it.
3782
+ "Tab"
3783
+ ]);
3784
+
3785
+ // src/lib/shortcuts/react.tsx
3786
+ import { jsx as jsx39 } from "react/jsx-runtime";
3787
+ var ShortcutContext = React13.createContext(null);
3788
+ var ownersByTarget = /* @__PURE__ */ new WeakMap();
3789
+ var useIsomorphicLayoutEffect = typeof document === "undefined" ? React13.useEffect : React13.useLayoutEffect;
3790
+ function optionsFingerprint(options) {
3791
+ return [
3792
+ options.isApple ?? "auto",
3793
+ options.sequenceTimeoutMs ?? "default",
3794
+ options.now ? "clock" : "no-clock"
3795
+ ].join("\0");
3796
+ }
3797
+ function ShortcutProvider({
3798
+ children,
3799
+ target,
3800
+ ...managerOptions
3801
+ }) {
3802
+ const parent = React13.useContext(ShortcutContext);
3803
+ const resolvedTarget = target === null ? null : target ?? (typeof document === "undefined" ? null : document);
3804
+ const nestedOnSameTarget = parent !== null && parent.target === resolvedTarget;
3805
+ const optionsRef = React13.useRef(managerOptions);
3806
+ const ownManagers = React13.useRef(/* @__PURE__ */ new WeakMap());
3807
+ const ownDetached = React13.useRef(null);
3808
+ const detached = React13.useMemo(() => {
3809
+ if (resolvedTarget === null) {
3810
+ ownDetached.current ??= createShortcutManager(optionsRef.current);
3811
+ return ownDetached.current;
3812
+ }
3813
+ const existing = ownManagers.current.get(resolvedTarget);
3814
+ if (existing) return existing;
3815
+ const created = createShortcutManager(optionsRef.current);
3816
+ ownManagers.current.set(resolvedTarget, created);
3817
+ return created;
3818
+ }, [resolvedTarget]);
3819
+ let owner = resolvedTarget === null ? null : ownersByTarget.get(resolvedTarget);
3820
+ const fingerprint = optionsFingerprint(optionsRef.current);
3821
+ if (resolvedTarget !== null && (!owner || owner.retired)) {
3822
+ owner = {
3823
+ manager: detached,
3824
+ providers: 0,
3825
+ retired: false,
3826
+ options: fingerprint
3827
+ };
3828
+ ownersByTarget.set(resolvedTarget, owner);
3829
+ }
3830
+ const adoptedDiffers = Boolean(owner) && owner?.options !== fingerprint || nestedOnSameTarget && parent !== null && parent.options !== fingerprint;
3831
+ devWarnOnce(
3832
+ !adoptedDiffers,
3833
+ "ShortcutProvider: another provider is already listening on this target with different options, so the ones passed here are being ignored. Managers are shared per target; give the providers matching options, or a target of their own."
3834
+ );
3835
+ const manager = nestedOnSameTarget && parent ? parent.manager : owner ? owner.manager : detached;
3836
+ useIsomorphicLayoutEffect(() => {
3837
+ if (resolvedTarget === null) return;
3838
+ let entry = ownersByTarget.get(resolvedTarget);
3839
+ if (!entry) {
3840
+ entry = {
3841
+ manager,
3842
+ providers: 0,
3843
+ retired: false,
3844
+ options: optionsFingerprint(optionsRef.current)
3845
+ };
3846
+ ownersByTarget.set(resolvedTarget, entry);
3847
+ }
3848
+ const owned = entry;
3849
+ owned.providers += 1;
3850
+ owned.retired = false;
3851
+ if (owned.providers === 1) {
3852
+ owned.detach = owned.manager.attach(resolvedTarget);
3853
+ }
3854
+ return () => {
3855
+ owned.providers -= 1;
3856
+ if (owned.providers === 0) {
3857
+ owned.detach?.();
3858
+ owned.detach = void 0;
3859
+ owned.retired = true;
2222
3860
  }
3861
+ };
3862
+ }, [resolvedTarget, manager]);
3863
+ const depth = nestedOnSameTarget && parent ? parent.depth : 0;
3864
+ const value = React13.useMemo(
3865
+ () => ({ manager, depth, target: resolvedTarget, options: fingerprint }),
3866
+ [manager, depth, resolvedTarget, fingerprint]
3867
+ );
3868
+ return /* @__PURE__ */ jsx39(ShortcutContext.Provider, { value, children });
3869
+ }
3870
+ function ShortcutScope({
3871
+ children
3872
+ }) {
3873
+ const parent = React13.useContext(ShortcutContext);
3874
+ if (!parent) {
3875
+ throw new Error("ShortcutScope must be rendered inside a ShortcutProvider");
3876
+ }
3877
+ const value = React13.useMemo(
3878
+ () => ({
3879
+ manager: parent.manager,
3880
+ depth: parent.depth + 1,
3881
+ target: parent.target,
3882
+ // Inherited: a scope raises precedence, it does not build a manager, so the options in force
3883
+ // are still the ones the provider above it used.
3884
+ options: parent.options
3885
+ }),
3886
+ [parent.manager, parent.depth, parent.target, parent.options]
3887
+ );
3888
+ return /* @__PURE__ */ jsx39(ShortcutContext.Provider, { value, children });
3889
+ }
3890
+ function useShortcuts(bindings, options) {
3891
+ const context = React13.useContext(ShortcutContext);
3892
+ if (!context) {
3893
+ throw new Error("useShortcuts must be called inside a ShortcutProvider");
3894
+ }
3895
+ const { manager, depth } = context;
3896
+ const registration = React13.useRef(null);
3897
+ const latest = React13.useRef({ bindings, options });
3898
+ useIsomorphicLayoutEffect(() => {
3899
+ registration.current = manager.register([], {
3900
+ name: latest.current.options.name,
3901
+ depth
3902
+ });
3903
+ return () => {
3904
+ registration.current?.dispose();
3905
+ registration.current = null;
3906
+ };
3907
+ }, [manager, depth]);
3908
+ useIsomorphicLayoutEffect(() => {
3909
+ latest.current = { bindings, options };
3910
+ registration.current?.update(bindings, {
3911
+ name: options.name,
3912
+ depth,
3913
+ enabled: options.enabled,
3914
+ blocking: options.blocking,
3915
+ priority: options.priority
3916
+ });
3917
+ });
3918
+ }
3919
+ function useShortcutManager() {
3920
+ const context = React13.useContext(ShortcutContext);
3921
+ if (!context) {
3922
+ throw new Error(
3923
+ "useShortcutManager must be called inside a ShortcutProvider"
3924
+ );
3925
+ }
3926
+ return context.manager;
3927
+ }
3928
+ function useActiveShortcuts() {
3929
+ const manager = useShortcutManager();
3930
+ return React13.useSyncExternalStore(
3931
+ manager.subscribe,
3932
+ manager.activeBindings,
3933
+ manager.activeBindings
3934
+ );
3935
+ }
3936
+
3937
+ // src/components/field-shell.tsx
3938
+ import { cva as cva13 } from "class-variance-authority";
3939
+ import { cloneElement, Fragment as Fragment3, useEffect as useEffect3, useId as useId2 } from "react";
3940
+ import { jsx as jsx40, jsxs as jsxs18 } from "react/jsx-runtime";
3941
+ var controlWidth = cva13("w-full", {
3942
+ variants: {
3943
+ width: {
3944
+ half: "max-w-[var(--nx-field-half,380px)]",
3945
+ full: "max-w-[var(--nx-field-full,760px)]",
3946
+ fill: ""
2223
3947
  }
3948
+ },
3949
+ defaultVariants: { width: "half" }
3950
+ });
3951
+ function readControlProps(child) {
3952
+ const props = child.props;
3953
+ return props && typeof props === "object" ? props : {};
3954
+ }
3955
+ function isRenderFunction(children) {
3956
+ return typeof children === "function";
3957
+ }
3958
+ function computeControlWiring(ownProps, requestedId, renderedMessageIds, hasError) {
3959
+ const ownId = typeof ownProps.id === "string" && ownProps.id !== "" ? ownProps.id : void 0;
3960
+ const id = ownId ?? requestedId;
3961
+ const ownDescribedByIds = typeof ownProps["aria-describedby"] === "string" ? ownProps["aria-describedby"].split(" ").filter(Boolean) : [];
3962
+ const describedByIds = Array.from(
3963
+ /* @__PURE__ */ new Set([...ownDescribedByIds, ...renderedMessageIds])
3964
+ );
3965
+ const describedBy = describedByIds.length > 0 ? describedByIds.join(" ") : void 0;
3966
+ const ownInvalid = typeof ownProps["aria-invalid"] === "boolean" ? ownProps["aria-invalid"] : void 0;
3967
+ const invalid = hasError ? true : ownInvalid;
3968
+ return { id, describedBy, invalid };
3969
+ }
3970
+ function FieldShell({
3971
+ label,
3972
+ description,
3973
+ error,
3974
+ width = "half",
3975
+ htmlFor,
3976
+ className,
3977
+ children
3978
+ }) {
3979
+ const generatedControlId = useId2();
3980
+ const messageBaseId = useId2();
3981
+ const descriptionId = `${messageBaseId}-description`;
3982
+ const errorId = `${messageBaseId}-error`;
3983
+ const requestedId = htmlFor ?? generatedControlId;
3984
+ const renderedMessageIds = [
3985
+ description ? descriptionId : null,
3986
+ error ? errorId : null
3987
+ ].filter((id) => id !== null);
3988
+ const wiring = isRenderFunction(children) ? computeControlWiring({}, requestedId, renderedMessageIds, Boolean(error)) : computeControlWiring(
3989
+ readControlProps(children),
3990
+ requestedId,
3991
+ renderedMessageIds,
3992
+ Boolean(error)
3993
+ );
3994
+ const isFragmentChild = !isRenderFunction(children) && children.type === Fragment3;
3995
+ useEffect3(() => {
3996
+ if (!isDevelopmentRuntime()) return;
3997
+ if (isFragmentChild) return;
3998
+ const landed = document.getElementById(wiring.id) !== null;
3999
+ const fieldName = typeof label === "string" ? `"${label}"` : "this field";
4000
+ devWarnOnce(
4001
+ landed,
4002
+ `FieldShell: the id computed for ${fieldName} never appeared on any element in the document, so its label and any description are not connected to the control. This happens when the control is a compound component \u2014 a Radix \`Select\`, \`RadioGroup\`, or similar \u2014 whose root does not forward \`id\`/\`aria-describedby\`/\`aria-invalid\` to a real DOM node. Pass \`children\` as a function and apply those to the control's actual focusable element (its trigger) instead of a single top-level clone.`
4003
+ );
4004
+ }, [wiring.id, label, isFragmentChild]);
4005
+ let control;
4006
+ if (isRenderFunction(children)) {
4007
+ control = children(wiring);
4008
+ } else {
4009
+ devWarnOnce(
4010
+ !isFragmentChild,
4011
+ "FieldShell: `children` must be a single element, not a Fragment. A Fragment forwards no props to the elements inside it, so the id, aria-describedby and aria-invalid this component computes would have nowhere to land \u2014 the label and the control would look wired up and never actually connect. Wrap the intended elements in a real element instead, such as a `<div>`."
4012
+ );
4013
+ const controlOverrides = {
4014
+ id: wiring.id,
4015
+ ...wiring.describedBy !== void 0 ? { "aria-describedby": wiring.describedBy } : {},
4016
+ ...wiring.invalid !== void 0 ? { "aria-invalid": wiring.invalid } : {}
4017
+ };
4018
+ control = isFragmentChild ? children : cloneElement(children, controlOverrides);
2224
4019
  }
2225
- };
2226
- var tailwind_preset_default = uiPreset;
4020
+ return /* @__PURE__ */ jsxs18("div", { className: cn("flex flex-col gap-1.5", className), children: [
4021
+ label ? /* @__PURE__ */ jsx40(
4022
+ "label",
4023
+ {
4024
+ htmlFor: wiring.id,
4025
+ className: "text-sm font-medium text-foreground",
4026
+ children: label
4027
+ }
4028
+ ) : null,
4029
+ /* @__PURE__ */ jsx40("div", { className: controlWidth({ width }), children: control }),
4030
+ description ? /* @__PURE__ */ jsx40("p", { id: descriptionId, className: "text-sm text-muted-foreground", children: description }) : null,
4031
+ error ? /* @__PURE__ */ jsx40("p", { id: errorId, className: "text-sm font-medium text-destructive", children: error }) : null
4032
+ ] });
4033
+ }
4034
+
4035
+ // src/components/form-section.tsx
4036
+ import { useId as useId3 } from "react";
4037
+ import { jsx as jsx41, jsxs as jsxs19 } from "react/jsx-runtime";
4038
+ function FormSection({
4039
+ label,
4040
+ description,
4041
+ className,
4042
+ children
4043
+ }) {
4044
+ const labelId = useId3();
4045
+ return /* @__PURE__ */ jsxs19("section", { "aria-labelledby": labelId, className: cn("space-y-2", className), children: [
4046
+ /* @__PURE__ */ jsxs19("div", { className: "space-y-1", children: [
4047
+ /* @__PURE__ */ jsx41(
4048
+ "p",
4049
+ {
4050
+ id: labelId,
4051
+ className: "text-xs font-semibold tracking-[0.08em] uppercase text-muted-foreground",
4052
+ children: label
4053
+ }
4054
+ ),
4055
+ description ? /* @__PURE__ */ jsx41("p", { className: "text-sm text-muted-foreground", children: description }) : null
4056
+ ] }),
4057
+ /* @__PURE__ */ jsx41(Card, { className: "overflow-hidden", children: /* @__PURE__ */ jsx41("div", { className: "divide-y divide-foreground/10 px-6", children }) })
4058
+ ] });
4059
+ }
2227
4060
 
2228
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, Avatar, AvatarFallback, AvatarImage, Badge, Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Input, Label, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortalProvider, Progress, RadioGroup, RadioGroupItem, ResponsiveTable, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Skeleton, Spinner, Switch, Table, TableBody, TableCaption, TableCell, TableEmpty, TableError, TableFooter, TableHead, TableHeader, TableLoading, TablePagination, TableRow, TableSearch, TableSkeleton, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, alertVariants, avatarVariants, badgeVariants, buttonVariants, cardVariants, cn, dialogContentVariants, inputVariants, progressVariants, selectTriggerVariants, sheetVariants, spinnerVariants, tailwind_preset_default as uiPreset, usePortalContainer };
2229
- //# sourceMappingURL=index.mjs.map
4061
+ // src/components/form-layout.tsx
4062
+ import { cva as cva14 } from "class-variance-authority";
4063
+ import { jsx as jsx42, jsxs as jsxs20 } from "react/jsx-runtime";
4064
+ var measure = cva14("mx-auto w-full px-6 py-8", {
4065
+ variants: {
4066
+ width: {
4067
+ form: "max-w-[56rem]",
4068
+ wide: "max-w-[72rem]"
4069
+ }
4070
+ },
4071
+ defaultVariants: { width: "form" }
4072
+ });
4073
+ function FormLayout({
4074
+ width = "form",
4075
+ className,
4076
+ children
4077
+ }) {
4078
+ return /* @__PURE__ */ jsx42("div", { className: cn(measure({ width }), className), children });
4079
+ }
4080
+ function FormActions({ dirty, className, children }) {
4081
+ return /* @__PURE__ */ jsxs20(
4082
+ "div",
4083
+ {
4084
+ className: cn(
4085
+ "sticky bottom-0 mt-8 flex items-center justify-end gap-3",
4086
+ "border-t border-border bg-background/95 py-4 backdrop-blur",
4087
+ className
4088
+ ),
4089
+ children: [
4090
+ dirty ? (
4091
+ // `role="status"` (implying `aria-live="polite"`) so a screen-reader
4092
+ // user is told when the flag flips false to true, not only sighted
4093
+ // users watching the bar. This is the only live region FormActions
4094
+ // renders, one per form.
4095
+ /* @__PURE__ */ jsx42("span", { role: "status", className: "mr-auto text-sm text-muted-foreground", children: "You have unsaved changes" })
4096
+ ) : null,
4097
+ children
4098
+ ]
4099
+ }
4100
+ );
4101
+ }
4102
+ export {
4103
+ Accordion,
4104
+ AccordionContent,
4105
+ AccordionItem,
4106
+ AccordionTrigger,
4107
+ Alert,
4108
+ AlertDescription,
4109
+ AlertDialog,
4110
+ AlertDialogAction,
4111
+ AlertDialogCancel,
4112
+ AlertDialogContent,
4113
+ AlertDialogDescription,
4114
+ AlertDialogFooter,
4115
+ AlertDialogHeader,
4116
+ AlertDialogOverlay,
4117
+ AlertDialogPortal,
4118
+ AlertDialogTitle,
4119
+ AlertDialogTrigger,
4120
+ AlertTitle,
4121
+ Avatar,
4122
+ AvatarFallback,
4123
+ AvatarImage,
4124
+ Badge,
4125
+ Button,
4126
+ Card,
4127
+ CardAction,
4128
+ CardContent,
4129
+ CardDescription,
4130
+ CardFooter,
4131
+ CardHeader,
4132
+ CardTitle,
4133
+ Checkbox,
4134
+ Collapsible,
4135
+ CollapsibleContent2 as CollapsibleContent,
4136
+ CollapsibleTrigger2 as CollapsibleTrigger,
4137
+ ColorPicker,
4138
+ Command,
4139
+ CommandDialog,
4140
+ CommandEmpty,
4141
+ CommandGroup,
4142
+ CommandInput,
4143
+ CommandItem,
4144
+ CommandList,
4145
+ CommandSeparator,
4146
+ CommandShortcut,
4147
+ ContextMenu,
4148
+ ContextMenuCheckboxItem,
4149
+ ContextMenuContent,
4150
+ ContextMenuGroup,
4151
+ ContextMenuItem,
4152
+ ContextMenuLabel,
4153
+ ContextMenuRadioGroup,
4154
+ ContextMenuRadioItem,
4155
+ ContextMenuSeparator,
4156
+ ContextMenuShortcut,
4157
+ ContextMenuSub,
4158
+ ContextMenuSubContent,
4159
+ ContextMenuSubTrigger,
4160
+ ContextMenuTrigger,
4161
+ Dialog,
4162
+ DialogClose,
4163
+ DialogContent,
4164
+ DialogDescription,
4165
+ DialogFooter,
4166
+ DialogHeader,
4167
+ DialogOverlay,
4168
+ DialogPortal,
4169
+ DialogTitle,
4170
+ DialogTrigger,
4171
+ DropdownMenu,
4172
+ DropdownMenuCheckboxItem,
4173
+ DropdownMenuContent,
4174
+ DropdownMenuGroup,
4175
+ DropdownMenuItem,
4176
+ DropdownMenuLabel,
4177
+ DropdownMenuPortal,
4178
+ DropdownMenuRadioGroup,
4179
+ DropdownMenuRadioItem,
4180
+ DropdownMenuSeparator,
4181
+ DropdownMenuShortcut,
4182
+ DropdownMenuSub,
4183
+ DropdownMenuSubContent,
4184
+ DropdownMenuSubTrigger,
4185
+ DropdownMenuTrigger,
4186
+ FieldShell,
4187
+ FormActions,
4188
+ FormLabelWithTooltip,
4189
+ FormLayout,
4190
+ FormSection,
4191
+ Grid,
4192
+ Input,
4193
+ Label,
4194
+ Popover,
4195
+ PopoverAnchor,
4196
+ PopoverContent,
4197
+ PopoverTrigger,
4198
+ PortalProvider,
4199
+ Progress,
4200
+ RadioGroup,
4201
+ RadioGroupItem,
4202
+ ResizableHandle,
4203
+ ResizablePanel,
4204
+ ResizablePanelGroup,
4205
+ Select,
4206
+ SelectContent,
4207
+ SelectGroup,
4208
+ SelectItem,
4209
+ SelectLabel,
4210
+ SelectScrollDownButton,
4211
+ SelectScrollUpButton,
4212
+ SelectSeparator,
4213
+ SelectTrigger,
4214
+ SelectValue,
4215
+ Separator,
4216
+ Sheet,
4217
+ SheetClose,
4218
+ SheetContent,
4219
+ SheetDescription,
4220
+ SheetFooter,
4221
+ SheetHeader,
4222
+ SheetOverlay,
4223
+ SheetPortal,
4224
+ SheetTitle,
4225
+ SheetTrigger,
4226
+ ShortcutProvider,
4227
+ ShortcutScope,
4228
+ Skeleton,
4229
+ Slider,
4230
+ Spinner,
4231
+ Stack,
4232
+ Stat,
4233
+ Switch,
4234
+ Table,
4235
+ TableBody,
4236
+ TableCaption,
4237
+ TableCell,
4238
+ TableEmpty,
4239
+ TableError,
4240
+ TableFooter,
4241
+ TableHead,
4242
+ TableHeader,
4243
+ TableLoading,
4244
+ TableRow,
4245
+ TableSearch,
4246
+ TableSkeleton,
4247
+ Tabs,
4248
+ TabsContent,
4249
+ TabsList,
4250
+ TabsTrigger,
4251
+ Textarea,
4252
+ Toaster,
4253
+ Tooltip,
4254
+ TooltipContent,
4255
+ TooltipProvider,
4256
+ TooltipTrigger,
4257
+ TreeView,
4258
+ alertVariants,
4259
+ avatarVariants,
4260
+ badgeVariants,
4261
+ buttonVariants,
4262
+ cardVariants,
4263
+ commandDefaultFilter,
4264
+ createShortcutManager,
4265
+ dialogContentVariants,
4266
+ inputVariants,
4267
+ parseKeys,
4268
+ progressVariants,
4269
+ selectTriggerVariants,
4270
+ sheetVariants,
4271
+ spinnerVariants,
4272
+ toast,
4273
+ useActiveShortcuts,
4274
+ usePortalContainer,
4275
+ useShortcutManager,
4276
+ useShortcuts
4277
+ };
2230
4278
  //# sourceMappingURL=index.mjs.map