@petrarca/sonnet-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,5016 @@
1
+ // src/alert.tsx
2
+ import * as React from "react";
3
+ import { cva } from "class-variance-authority";
4
+ import { cn } from "@petrarca/sonnet-core";
5
+ import { jsx } from "react/jsx-runtime";
6
+ var alertVariants = cva(
7
+ "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: "bg-background text-foreground",
12
+ destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"
13
+ }
14
+ },
15
+ defaultVariants: {
16
+ variant: "default"
17
+ }
18
+ }
19
+ );
20
+ var Alert = React.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx(
21
+ "div",
22
+ {
23
+ ref,
24
+ role: "alert",
25
+ className: cn(alertVariants({ variant }), className),
26
+ ...props
27
+ }
28
+ ));
29
+ Alert.displayName = "Alert";
30
+ var AlertTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
31
+ "h5",
32
+ {
33
+ ref,
34
+ className: cn("mb-1 font-medium leading-none tracking-tight", className),
35
+ ...props
36
+ }
37
+ ));
38
+ AlertTitle.displayName = "AlertTitle";
39
+ var AlertDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
40
+ "div",
41
+ {
42
+ ref,
43
+ className: cn("text-sm [&_p]:leading-relaxed", className),
44
+ ...props
45
+ }
46
+ ));
47
+ AlertDescription.displayName = "AlertDescription";
48
+
49
+ // src/avatar.tsx
50
+ import * as React2 from "react";
51
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
52
+ import { cn as cn2 } from "@petrarca/sonnet-core";
53
+ import { jsx as jsx2 } from "react/jsx-runtime";
54
+ var Avatar = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
55
+ AvatarPrimitive.Root,
56
+ {
57
+ ref,
58
+ className: cn2(
59
+ "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
60
+ className
61
+ ),
62
+ ...props
63
+ }
64
+ ));
65
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
66
+ var AvatarImage = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
67
+ AvatarPrimitive.Image,
68
+ {
69
+ ref,
70
+ className: cn2("aspect-square h-full w-full", className),
71
+ ...props
72
+ }
73
+ ));
74
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
75
+ var AvatarFallback = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
76
+ AvatarPrimitive.Fallback,
77
+ {
78
+ ref,
79
+ className: cn2(
80
+ "flex h-full w-full items-center justify-center rounded-full bg-muted",
81
+ className
82
+ ),
83
+ ...props
84
+ }
85
+ ));
86
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
87
+
88
+ // src/badge.tsx
89
+ import { cva as cva2 } from "class-variance-authority";
90
+ import { cn as cn3 } from "@petrarca/sonnet-core";
91
+ import { jsx as jsx3 } from "react/jsx-runtime";
92
+ var badgeVariants = cva2(
93
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
94
+ {
95
+ variants: {
96
+ variant: {
97
+ default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
98
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
99
+ destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
100
+ outline: "text-foreground"
101
+ },
102
+ badgeColor: {
103
+ grape: "border-transparent bg-purple-100 text-purple-800 hover:bg-purple-200 dark:bg-purple-900 dark:text-purple-200 dark:hover:bg-purple-800",
104
+ blue: "border-transparent bg-blue-100 text-blue-800 hover:bg-blue-200 dark:bg-blue-900 dark:text-blue-200 dark:hover:bg-blue-800",
105
+ green: "border-transparent bg-green-100 text-green-800 hover:bg-green-200 dark:bg-green-900 dark:text-green-200 dark:hover:bg-green-800",
106
+ red: "border-transparent bg-red-100 text-red-800 hover:bg-red-200 dark:bg-red-900 dark:text-red-200 dark:hover:bg-red-800",
107
+ orange: "border-transparent bg-orange-100 text-orange-800 hover:bg-orange-200 dark:bg-orange-900 dark:text-orange-200 dark:hover:bg-orange-800",
108
+ yellow: "border-transparent bg-yellow-100 text-yellow-800 hover:bg-yellow-200 dark:bg-yellow-900 dark:text-yellow-200 dark:hover:bg-yellow-800",
109
+ teal: "border-transparent bg-teal-100 text-teal-800 hover:bg-teal-200 dark:bg-teal-900 dark:text-teal-200 dark:hover:bg-teal-800",
110
+ cyan: "border-transparent bg-cyan-100 text-cyan-800 hover:bg-cyan-200 dark:bg-cyan-900 dark:text-cyan-200 dark:hover:bg-cyan-800",
111
+ pink: "border-transparent bg-pink-100 text-pink-800 hover:bg-pink-200 dark:bg-pink-900 dark:text-pink-200 dark:hover:bg-pink-800",
112
+ indigo: "border-transparent bg-indigo-100 text-indigo-800 hover:bg-indigo-200 dark:bg-indigo-900 dark:text-indigo-200 dark:hover:bg-indigo-800",
113
+ violet: "border-transparent bg-violet-100 text-violet-800 hover:bg-violet-200 dark:bg-violet-900 dark:text-violet-200 dark:hover:bg-violet-800"
114
+ }
115
+ },
116
+ defaultVariants: {
117
+ variant: "default"
118
+ }
119
+ }
120
+ );
121
+ function Badge({ className, variant, badgeColor, ...props }) {
122
+ return /* @__PURE__ */ jsx3(
123
+ "div",
124
+ {
125
+ className: cn3(badgeVariants({ variant, badgeColor }), className),
126
+ ...props
127
+ }
128
+ );
129
+ }
130
+
131
+ // src/button.tsx
132
+ import * as React3 from "react";
133
+ import { Slot } from "@radix-ui/react-slot";
134
+ import { cva as cva3 } from "class-variance-authority";
135
+ import { cn as cn4 } from "@petrarca/sonnet-core";
136
+ import { jsx as jsx4 } from "react/jsx-runtime";
137
+ var buttonVariants = cva3(
138
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
139
+ {
140
+ variants: {
141
+ variant: {
142
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
143
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
144
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
145
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
146
+ ghost: "hover:bg-accent hover:text-accent-foreground",
147
+ link: "text-primary underline-offset-4 hover:underline"
148
+ },
149
+ size: {
150
+ default: "h-10 px-4 py-2",
151
+ sm: "h-9 rounded-md px-3",
152
+ lg: "h-11 rounded-md px-8",
153
+ icon: "h-10 w-10",
154
+ compact: "h-7 w-7 p-0"
155
+ }
156
+ },
157
+ defaultVariants: {
158
+ variant: "default",
159
+ size: "default"
160
+ }
161
+ }
162
+ );
163
+ var Button = React3.forwardRef(
164
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
165
+ const Comp = asChild ? Slot : "button";
166
+ return /* @__PURE__ */ jsx4(
167
+ Comp,
168
+ {
169
+ className: cn4(buttonVariants({ variant, size, className })),
170
+ ref,
171
+ ...props
172
+ }
173
+ );
174
+ }
175
+ );
176
+ Button.displayName = "Button";
177
+
178
+ // src/card.tsx
179
+ import * as React4 from "react";
180
+ import { cn as cn5 } from "@petrarca/sonnet-core";
181
+ import { jsx as jsx5 } from "react/jsx-runtime";
182
+ var Card = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
183
+ "div",
184
+ {
185
+ ref,
186
+ className: cn5(
187
+ "rounded-lg border bg-card text-card-foreground shadow-sm",
188
+ className
189
+ ),
190
+ ...props
191
+ }
192
+ ));
193
+ Card.displayName = "Card";
194
+ var CardHeader = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
195
+ "div",
196
+ {
197
+ ref,
198
+ className: cn5("flex flex-col space-y-1.5 p-6", className),
199
+ ...props
200
+ }
201
+ ));
202
+ CardHeader.displayName = "CardHeader";
203
+ var CardTitle = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
204
+ "div",
205
+ {
206
+ ref,
207
+ className: cn5(
208
+ "text-2xl font-semibold leading-none tracking-tight",
209
+ className
210
+ ),
211
+ ...props
212
+ }
213
+ ));
214
+ CardTitle.displayName = "CardTitle";
215
+ var CardDescription = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
216
+ "div",
217
+ {
218
+ ref,
219
+ className: cn5("text-sm text-muted-foreground", className),
220
+ ...props
221
+ }
222
+ ));
223
+ CardDescription.displayName = "CardDescription";
224
+ var CardContent = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5("div", { ref, className: cn5("p-6 pt-0", className), ...props }));
225
+ CardContent.displayName = "CardContent";
226
+ var CardFooter = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
227
+ "div",
228
+ {
229
+ ref,
230
+ className: cn5("flex items-center p-6 pt-0", className),
231
+ ...props
232
+ }
233
+ ));
234
+ CardFooter.displayName = "CardFooter";
235
+
236
+ // src/checkbox.tsx
237
+ import * as React5 from "react";
238
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
239
+ import { Check } from "lucide-react";
240
+ import { cn as cn6 } from "@petrarca/sonnet-core";
241
+ import { jsx as jsx6 } from "react/jsx-runtime";
242
+ var Checkbox = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
243
+ CheckboxPrimitive.Root,
244
+ {
245
+ ref,
246
+ className: cn6(
247
+ "grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
248
+ className
249
+ ),
250
+ ...props,
251
+ children: /* @__PURE__ */ jsx6(
252
+ CheckboxPrimitive.Indicator,
253
+ {
254
+ className: cn6("grid place-content-center text-current"),
255
+ children: /* @__PURE__ */ jsx6(Check, { className: "h-4 w-4" })
256
+ }
257
+ )
258
+ }
259
+ ));
260
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
261
+
262
+ // src/collapsible.tsx
263
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
264
+ var Collapsible = CollapsiblePrimitive.Root;
265
+ var CollapsibleTrigger2 = CollapsiblePrimitive.CollapsibleTrigger;
266
+ var CollapsibleContent2 = CollapsiblePrimitive.CollapsibleContent;
267
+
268
+ // src/command.tsx
269
+ import * as React7 from "react";
270
+ import { Command as CommandPrimitive } from "cmdk";
271
+ import { Search } from "lucide-react";
272
+ import { cn as cn8 } from "@petrarca/sonnet-core";
273
+
274
+ // src/dialog.tsx
275
+ import * as React6 from "react";
276
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
277
+ import { X } from "lucide-react";
278
+ import { cn as cn7 } from "@petrarca/sonnet-core";
279
+ import { jsx as jsx7, jsxs } from "react/jsx-runtime";
280
+ var Dialog = DialogPrimitive.Root;
281
+ var DialogTrigger = DialogPrimitive.Trigger;
282
+ var DialogPortal = DialogPrimitive.Portal;
283
+ var DialogClose = DialogPrimitive.Close;
284
+ var DialogOverlay = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx7(
285
+ DialogPrimitive.Overlay,
286
+ {
287
+ ref,
288
+ className: cn7(
289
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
290
+ className
291
+ ),
292
+ ...props
293
+ }
294
+ ));
295
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
296
+ var DialogContent = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
297
+ /* @__PURE__ */ jsx7(DialogOverlay, {}),
298
+ /* @__PURE__ */ jsxs(
299
+ DialogPrimitive.Content,
300
+ {
301
+ ref,
302
+ className: cn7(
303
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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%] sm:rounded-lg",
304
+ className
305
+ ),
306
+ ...props,
307
+ children: [
308
+ children,
309
+ /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
310
+ /* @__PURE__ */ jsx7(X, { className: "h-4 w-4" }),
311
+ /* @__PURE__ */ jsx7("span", { className: "sr-only", children: "Close" })
312
+ ] })
313
+ ]
314
+ }
315
+ )
316
+ ] }));
317
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
318
+ var DialogHeader = ({
319
+ className,
320
+ ...props
321
+ }) => /* @__PURE__ */ jsx7(
322
+ "div",
323
+ {
324
+ className: cn7(
325
+ "flex flex-col space-y-1.5 text-center sm:text-left",
326
+ className
327
+ ),
328
+ ...props
329
+ }
330
+ );
331
+ DialogHeader.displayName = "DialogHeader";
332
+ var DialogFooter = ({
333
+ className,
334
+ ...props
335
+ }) => /* @__PURE__ */ jsx7(
336
+ "div",
337
+ {
338
+ className: cn7(
339
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
340
+ className
341
+ ),
342
+ ...props
343
+ }
344
+ );
345
+ DialogFooter.displayName = "DialogFooter";
346
+ var DialogTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx7(
347
+ DialogPrimitive.Title,
348
+ {
349
+ ref,
350
+ className: cn7(
351
+ "text-lg font-semibold leading-none tracking-tight",
352
+ className
353
+ ),
354
+ ...props
355
+ }
356
+ ));
357
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
358
+ var DialogDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx7(
359
+ DialogPrimitive.Description,
360
+ {
361
+ ref,
362
+ className: cn7("text-sm text-muted-foreground", className),
363
+ ...props
364
+ }
365
+ ));
366
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
367
+
368
+ // src/command.tsx
369
+ import { jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
370
+ var Command = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
371
+ CommandPrimitive,
372
+ {
373
+ ref,
374
+ className: cn8(
375
+ "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
376
+ className
377
+ ),
378
+ ...props
379
+ }
380
+ ));
381
+ Command.displayName = CommandPrimitive.displayName;
382
+ var CommandDialog = ({ children, ...props }) => {
383
+ return /* @__PURE__ */ jsx8(Dialog, { ...props, children: /* @__PURE__ */ jsx8(DialogContent, { className: "overflow-hidden p-0 shadow-lg", children: /* @__PURE__ */ jsx8(Command, { className: "[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5", children }) }) });
384
+ };
385
+ var CommandInput = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs2("div", { className: "flex items-center border-b px-3", "cmdk-input-wrapper": "", children: [
386
+ /* @__PURE__ */ jsx8(Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
387
+ /* @__PURE__ */ jsx8(
388
+ CommandPrimitive.Input,
389
+ {
390
+ ref,
391
+ className: cn8(
392
+ "flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
393
+ className
394
+ ),
395
+ ...props
396
+ }
397
+ )
398
+ ] }));
399
+ CommandInput.displayName = CommandPrimitive.Input.displayName;
400
+ var CommandList = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
401
+ CommandPrimitive.List,
402
+ {
403
+ ref,
404
+ className: cn8("max-h-[300px] overflow-y-auto overflow-x-hidden", className),
405
+ ...props
406
+ }
407
+ ));
408
+ CommandList.displayName = CommandPrimitive.List.displayName;
409
+ var CommandEmpty = React7.forwardRef((props, ref) => /* @__PURE__ */ jsx8(
410
+ CommandPrimitive.Empty,
411
+ {
412
+ ref,
413
+ className: "py-6 text-center text-sm",
414
+ ...props
415
+ }
416
+ ));
417
+ CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
418
+ var CommandGroup = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
419
+ CommandPrimitive.Group,
420
+ {
421
+ ref,
422
+ className: cn8(
423
+ "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
424
+ className
425
+ ),
426
+ ...props
427
+ }
428
+ ));
429
+ CommandGroup.displayName = CommandPrimitive.Group.displayName;
430
+ var CommandSeparator = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
431
+ CommandPrimitive.Separator,
432
+ {
433
+ ref,
434
+ className: cn8("-mx-1 h-px bg-border", className),
435
+ ...props
436
+ }
437
+ ));
438
+ CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
439
+ var CommandItem = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
440
+ CommandPrimitive.Item,
441
+ {
442
+ ref,
443
+ className: cn8(
444
+ "relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
445
+ className
446
+ ),
447
+ ...props
448
+ }
449
+ ));
450
+ CommandItem.displayName = CommandPrimitive.Item.displayName;
451
+ var CommandShortcut = ({
452
+ className,
453
+ ...props
454
+ }) => {
455
+ return /* @__PURE__ */ jsx8(
456
+ "span",
457
+ {
458
+ className: cn8(
459
+ "ml-auto text-xs tracking-widest text-muted-foreground",
460
+ className
461
+ ),
462
+ ...props
463
+ }
464
+ );
465
+ };
466
+ CommandShortcut.displayName = "CommandShortcut";
467
+
468
+ // src/dropdown-menu.tsx
469
+ import * as React8 from "react";
470
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
471
+ import { Check as Check2, ChevronRight, Circle } from "lucide-react";
472
+ import { cn as cn9 } from "@petrarca/sonnet-core";
473
+ import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
474
+ var DropdownMenu = DropdownMenuPrimitive.Root;
475
+ var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
476
+ var DropdownMenuGroup = DropdownMenuPrimitive.Group;
477
+ var DropdownMenuPortal = DropdownMenuPrimitive.Portal;
478
+ var DropdownMenuSub = DropdownMenuPrimitive.Sub;
479
+ var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
480
+ var DropdownMenuSubTrigger = React8.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs3(
481
+ DropdownMenuPrimitive.SubTrigger,
482
+ {
483
+ ref,
484
+ className: cn9(
485
+ "flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
486
+ inset && "pl-8",
487
+ className
488
+ ),
489
+ ...props,
490
+ children: [
491
+ children,
492
+ /* @__PURE__ */ jsx9(ChevronRight, { className: "ml-auto" })
493
+ ]
494
+ }
495
+ ));
496
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
497
+ var DropdownMenuSubContent = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
498
+ DropdownMenuPrimitive.SubContent,
499
+ {
500
+ ref,
501
+ className: cn9(
502
+ "z-50 min-w-[8rem] overflow-hidden rounded-md 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]",
503
+ className
504
+ ),
505
+ ...props
506
+ }
507
+ ));
508
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
509
+ var DropdownMenuContent = React8.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx9(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx9(
510
+ DropdownMenuPrimitive.Content,
511
+ {
512
+ ref,
513
+ sideOffset,
514
+ className: cn9(
515
+ "z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md 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]",
516
+ className
517
+ ),
518
+ ...props
519
+ }
520
+ ) }));
521
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
522
+ var DropdownMenuItem = React8.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx9(
523
+ DropdownMenuPrimitive.Item,
524
+ {
525
+ ref,
526
+ className: cn9(
527
+ "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
528
+ inset && "pl-8",
529
+ className
530
+ ),
531
+ ...props
532
+ }
533
+ ));
534
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
535
+ var DropdownMenuCheckboxItem = React8.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs3(
536
+ DropdownMenuPrimitive.CheckboxItem,
537
+ {
538
+ ref,
539
+ className: cn9(
540
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
541
+ className
542
+ ),
543
+ checked,
544
+ ...props,
545
+ children: [
546
+ /* @__PURE__ */ jsx9("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx9(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx9(Check2, { className: "h-4 w-4" }) }) }),
547
+ children
548
+ ]
549
+ }
550
+ ));
551
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
552
+ var DropdownMenuRadioItem = React8.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs3(
553
+ DropdownMenuPrimitive.RadioItem,
554
+ {
555
+ ref,
556
+ className: cn9(
557
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
558
+ className
559
+ ),
560
+ ...props,
561
+ children: [
562
+ /* @__PURE__ */ jsx9("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx9(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx9(Circle, { className: "h-2 w-2 fill-current" }) }) }),
563
+ children
564
+ ]
565
+ }
566
+ ));
567
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
568
+ var DropdownMenuLabel = React8.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx9(
569
+ DropdownMenuPrimitive.Label,
570
+ {
571
+ ref,
572
+ className: cn9(
573
+ "px-2 py-1.5 text-sm font-semibold",
574
+ inset && "pl-8",
575
+ className
576
+ ),
577
+ ...props
578
+ }
579
+ ));
580
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
581
+ var DropdownMenuSeparator = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
582
+ DropdownMenuPrimitive.Separator,
583
+ {
584
+ ref,
585
+ className: cn9("-mx-1 my-1 h-px bg-muted", className),
586
+ ...props
587
+ }
588
+ ));
589
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
590
+ var DropdownMenuShortcut = ({
591
+ className,
592
+ ...props
593
+ }) => {
594
+ return /* @__PURE__ */ jsx9(
595
+ "span",
596
+ {
597
+ className: cn9("ml-auto text-xs tracking-widest opacity-60", className),
598
+ ...props
599
+ }
600
+ );
601
+ };
602
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
603
+
604
+ // src/input.tsx
605
+ import * as React9 from "react";
606
+ import { cn as cn10 } from "@petrarca/sonnet-core";
607
+ import { jsx as jsx10 } from "react/jsx-runtime";
608
+ var Input = React9.forwardRef(
609
+ ({ className, type, ...props }, ref) => {
610
+ return /* @__PURE__ */ jsx10(
611
+ "input",
612
+ {
613
+ type,
614
+ className: cn10(
615
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
616
+ className
617
+ ),
618
+ ref,
619
+ ...props
620
+ }
621
+ );
622
+ }
623
+ );
624
+ Input.displayName = "Input";
625
+
626
+ // src/input-group.tsx
627
+ import { cva as cva4 } from "class-variance-authority";
628
+ import { cn as cn12 } from "@petrarca/sonnet-core";
629
+
630
+ // src/textarea.tsx
631
+ import * as React10 from "react";
632
+ import { cn as cn11 } from "@petrarca/sonnet-core";
633
+ import { jsx as jsx11 } from "react/jsx-runtime";
634
+ var Textarea = React10.forwardRef(({ className, ...props }, ref) => {
635
+ return /* @__PURE__ */ jsx11(
636
+ "textarea",
637
+ {
638
+ className: cn11(
639
+ "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
640
+ className
641
+ ),
642
+ ref,
643
+ ...props
644
+ }
645
+ );
646
+ });
647
+ Textarea.displayName = "Textarea";
648
+
649
+ // src/input-group.tsx
650
+ import { jsx as jsx12 } from "react/jsx-runtime";
651
+ function InputGroup({ className, ...props }) {
652
+ return /* @__PURE__ */ jsx12(
653
+ "div",
654
+ {
655
+ "data-slot": "input-group",
656
+ role: "group",
657
+ className: cn12(
658
+ "group/input-group border-input dark:bg-input/30 shadow-xs relative flex w-full items-center rounded-md border outline-none transition-[color,box-shadow]",
659
+ "h-9 has-[>textarea]:h-auto",
660
+ // Variants based on alignment.
661
+ "has-[>[data-align=inline-start]]:[&>input]:pl-2",
662
+ "has-[>[data-align=inline-end]]:[&>input]:pr-2",
663
+ "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
664
+ "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
665
+ // Focus state.
666
+ "has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1",
667
+ // Error state.
668
+ "has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
669
+ className
670
+ ),
671
+ ...props
672
+ }
673
+ );
674
+ }
675
+ var inputGroupAddonVariants = cva4(
676
+ "text-muted-foreground flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
677
+ {
678
+ variants: {
679
+ align: {
680
+ "inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
681
+ "inline-end": "order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]",
682
+ "block-start": "[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5",
683
+ "block-end": "[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5"
684
+ }
685
+ },
686
+ defaultVariants: {
687
+ align: "inline-start"
688
+ }
689
+ }
690
+ );
691
+ function InputGroupAddon({
692
+ className,
693
+ align = "inline-start",
694
+ ...props
695
+ }) {
696
+ return /* @__PURE__ */ jsx12(
697
+ "div",
698
+ {
699
+ role: "group",
700
+ "data-slot": "input-group-addon",
701
+ "data-align": align,
702
+ className: cn12(inputGroupAddonVariants({ align }), className),
703
+ onClick: (e) => {
704
+ if (e.target.closest("button")) {
705
+ return;
706
+ }
707
+ e.currentTarget.parentElement?.querySelector("input")?.focus();
708
+ },
709
+ ...props
710
+ }
711
+ );
712
+ }
713
+ var inputGroupButtonVariants = cva4(
714
+ "flex items-center gap-2 text-sm shadow-none",
715
+ {
716
+ variants: {
717
+ size: {
718
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
719
+ sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",
720
+ "icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
721
+ "icon-sm": "size-8 p-0 has-[>svg]:p-0"
722
+ }
723
+ },
724
+ defaultVariants: {
725
+ size: "xs"
726
+ }
727
+ }
728
+ );
729
+ function InputGroupText({ className, ...props }) {
730
+ return /* @__PURE__ */ jsx12(
731
+ "span",
732
+ {
733
+ className: cn12(
734
+ "text-muted-foreground flex items-center gap-2 text-sm [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
735
+ className
736
+ ),
737
+ ...props
738
+ }
739
+ );
740
+ }
741
+ function InputGroupInput({
742
+ className,
743
+ ...props
744
+ }) {
745
+ return /* @__PURE__ */ jsx12(
746
+ Input,
747
+ {
748
+ "data-slot": "input-group-control",
749
+ className: cn12(
750
+ "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
751
+ className
752
+ ),
753
+ ...props
754
+ }
755
+ );
756
+ }
757
+ function InputGroupTextarea({
758
+ className,
759
+ ...props
760
+ }) {
761
+ return /* @__PURE__ */ jsx12(
762
+ Textarea,
763
+ {
764
+ "data-slot": "input-group-control",
765
+ className: cn12(
766
+ "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
767
+ className
768
+ ),
769
+ ...props
770
+ }
771
+ );
772
+ }
773
+
774
+ // src/label.tsx
775
+ import * as React11 from "react";
776
+ import * as LabelPrimitive from "@radix-ui/react-label";
777
+ import { cva as cva5 } from "class-variance-authority";
778
+ import { cn as cn13 } from "@petrarca/sonnet-core";
779
+ import { jsx as jsx13 } from "react/jsx-runtime";
780
+ var labelVariants = cva5(
781
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
782
+ );
783
+ var Label2 = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
784
+ LabelPrimitive.Root,
785
+ {
786
+ ref,
787
+ className: cn13(labelVariants(), className),
788
+ ...props
789
+ }
790
+ ));
791
+ Label2.displayName = LabelPrimitive.Root.displayName;
792
+
793
+ // src/popover.tsx
794
+ import * as React12 from "react";
795
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
796
+ import { cn as cn14 } from "@petrarca/sonnet-core";
797
+ import { jsx as jsx14 } from "react/jsx-runtime";
798
+ var Popover = PopoverPrimitive.Root;
799
+ var PopoverTrigger = PopoverPrimitive.Trigger;
800
+ var PopoverContent = React12.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx14(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx14(
801
+ PopoverPrimitive.Content,
802
+ {
803
+ ref,
804
+ align,
805
+ sideOffset,
806
+ className: cn14(
807
+ "z-50 w-72 rounded-md 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]",
808
+ className
809
+ ),
810
+ ...props
811
+ }
812
+ ) }));
813
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
814
+
815
+ // src/scroll-area.tsx
816
+ import * as React13 from "react";
817
+ import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
818
+ import { cn as cn15 } from "@petrarca/sonnet-core";
819
+ import { jsx as jsx15, jsxs as jsxs4 } from "react/jsx-runtime";
820
+ var ScrollArea = React13.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs4(
821
+ ScrollAreaPrimitive.Root,
822
+ {
823
+ ref,
824
+ className: cn15("relative overflow-hidden", className),
825
+ ...props,
826
+ children: [
827
+ /* @__PURE__ */ jsx15(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
828
+ /* @__PURE__ */ jsx15(ScrollBar, {}),
829
+ /* @__PURE__ */ jsx15(ScrollAreaPrimitive.Corner, {})
830
+ ]
831
+ }
832
+ ));
833
+ ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
834
+ var ScrollBar = React13.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx15(
835
+ ScrollAreaPrimitive.ScrollAreaScrollbar,
836
+ {
837
+ ref,
838
+ orientation,
839
+ className: cn15(
840
+ "flex touch-none select-none transition-colors",
841
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
842
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
843
+ className
844
+ ),
845
+ ...props,
846
+ children: /* @__PURE__ */ jsx15(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
847
+ }
848
+ ));
849
+ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
850
+
851
+ // src/separator.tsx
852
+ import * as React14 from "react";
853
+ import * as SeparatorPrimitive from "@radix-ui/react-separator";
854
+ import { cn as cn16 } from "@petrarca/sonnet-core";
855
+ import { jsx as jsx16 } from "react/jsx-runtime";
856
+ var Separator2 = React14.forwardRef(
857
+ ({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx16(
858
+ SeparatorPrimitive.Root,
859
+ {
860
+ ref,
861
+ decorative,
862
+ orientation,
863
+ className: cn16(
864
+ "shrink-0 bg-border",
865
+ orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
866
+ className
867
+ ),
868
+ ...props
869
+ }
870
+ )
871
+ );
872
+ Separator2.displayName = SeparatorPrimitive.Root.displayName;
873
+
874
+ // src/sheet.tsx
875
+ import * as React15 from "react";
876
+ import * as DialogPrimitive2 from "@radix-ui/react-dialog";
877
+ import { X as X2 } from "lucide-react";
878
+ import { cn as cn17 } from "@petrarca/sonnet-core";
879
+ import { jsx as jsx17, jsxs as jsxs5 } from "react/jsx-runtime";
880
+ var Sheet = DialogPrimitive2.Root;
881
+ var SheetTrigger = DialogPrimitive2.Trigger;
882
+ var SheetClose = DialogPrimitive2.Close;
883
+ var SheetPortal = DialogPrimitive2.Portal;
884
+ var SheetOverlay = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
885
+ DialogPrimitive2.Overlay,
886
+ {
887
+ ref,
888
+ className: cn17(
889
+ "fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
890
+ className
891
+ ),
892
+ ...props
893
+ }
894
+ ));
895
+ SheetOverlay.displayName = "SheetOverlay";
896
+ var SheetContent = React15.forwardRef(
897
+ ({ className, children, side = "right", offsetTop = "0px", ...props }, ref) => /* @__PURE__ */ jsxs5(SheetPortal, { children: [
898
+ /* @__PURE__ */ jsx17(SheetOverlay, {}),
899
+ /* @__PURE__ */ jsxs5(
900
+ DialogPrimitive2.Content,
901
+ {
902
+ ref,
903
+ className: cn17(
904
+ "fixed z-50 flex flex-col bg-background shadow-xl transition-transform duration-300 ease-in-out",
905
+ "bottom-0 w-[480px] max-w-[90vw] border-l",
906
+ side === "right" && "right-0 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right",
907
+ side === "left" && "left-0 border-l-0 border-r data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left",
908
+ className
909
+ ),
910
+ style: { top: offsetTop },
911
+ ...props,
912
+ children: [
913
+ children,
914
+ /* @__PURE__ */ jsxs5(DialogPrimitive2.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", children: [
915
+ /* @__PURE__ */ jsx17(X2, { className: "h-4 w-4" }),
916
+ /* @__PURE__ */ jsx17("span", { className: "sr-only", children: "Close" })
917
+ ] })
918
+ ]
919
+ }
920
+ )
921
+ ] })
922
+ );
923
+ SheetContent.displayName = "SheetContent";
924
+ var SheetHeader = ({
925
+ className,
926
+ ...props
927
+ }) => /* @__PURE__ */ jsx17("div", { className: cn17("shrink-0 border-b px-6 py-4", className), ...props });
928
+ var SheetTitle = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
929
+ DialogPrimitive2.Title,
930
+ {
931
+ ref,
932
+ className: cn17("text-lg font-semibold", className),
933
+ ...props
934
+ }
935
+ ));
936
+ SheetTitle.displayName = "SheetTitle";
937
+ var SheetDescription = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
938
+ DialogPrimitive2.Description,
939
+ {
940
+ ref,
941
+ className: cn17("text-sm text-muted-foreground mt-1", className),
942
+ ...props
943
+ }
944
+ ));
945
+ SheetDescription.displayName = "SheetDescription";
946
+ var SheetBody = ({
947
+ className,
948
+ ...props
949
+ }) => /* @__PURE__ */ jsx17(
950
+ "div",
951
+ {
952
+ className: cn17("flex-1 overflow-y-auto px-6 py-4", className),
953
+ ...props
954
+ }
955
+ );
956
+ var SheetFooter = ({
957
+ className,
958
+ ...props
959
+ }) => /* @__PURE__ */ jsx17(
960
+ "div",
961
+ {
962
+ className: cn17(
963
+ "shrink-0 border-t px-6 py-4 flex justify-end gap-2",
964
+ className
965
+ ),
966
+ ...props
967
+ }
968
+ );
969
+
970
+ // src/simple-group.tsx
971
+ import { cn as cn18 } from "@petrarca/sonnet-core";
972
+ import { jsx as jsx18 } from "react/jsx-runtime";
973
+ var gapMap = {
974
+ 0: "gap-0",
975
+ xs: "gap-1",
976
+ sm: "gap-2",
977
+ md: "gap-4",
978
+ lg: "gap-6",
979
+ xl: "gap-8",
980
+ 2: "gap-0.5",
981
+ 4: "gap-1",
982
+ 6: "gap-1.5",
983
+ 8: "gap-2",
984
+ 24: "gap-6"
985
+ };
986
+ var alignMap = {
987
+ start: "items-start",
988
+ center: "items-center",
989
+ end: "items-end",
990
+ stretch: "items-stretch",
991
+ "flex-start": "items-start",
992
+ "flex-end": "items-end"
993
+ };
994
+ var justifyMap = {
995
+ start: "justify-start",
996
+ center: "justify-center",
997
+ end: "justify-end",
998
+ between: "justify-between",
999
+ around: "justify-around",
1000
+ "space-between": "justify-between",
1001
+ "flex-start": "justify-start",
1002
+ "flex-end": "justify-end"
1003
+ };
1004
+ var wrapMap = {
1005
+ wrap: "flex-wrap",
1006
+ nowrap: "flex-nowrap",
1007
+ "wrap-reverse": "flex-wrap-reverse"
1008
+ };
1009
+ var mtMap = {
1010
+ xs: "mt-1",
1011
+ sm: "mt-2",
1012
+ md: "mt-4",
1013
+ lg: "mt-6",
1014
+ xl: "mt-8"
1015
+ };
1016
+ function SimpleGroup({
1017
+ children,
1018
+ gap = "md",
1019
+ align,
1020
+ justify,
1021
+ wrap,
1022
+ grow = false,
1023
+ className,
1024
+ style,
1025
+ mt,
1026
+ onClick
1027
+ }) {
1028
+ const gapClass = gapMap[gap] || gapMap.md;
1029
+ const alignClass = align ? alignMap[align] : void 0;
1030
+ const justifyClass = justify ? justifyMap[justify] : void 0;
1031
+ const wrapClass = wrap ? wrapMap[wrap] : void 0;
1032
+ const growClass = grow ? "[&>*]:flex-1" : void 0;
1033
+ const mtClass = mt ? mtMap[mt] : void 0;
1034
+ return /* @__PURE__ */ jsx18(
1035
+ "div",
1036
+ {
1037
+ className: cn18(
1038
+ "flex flex-row",
1039
+ gapClass,
1040
+ alignClass,
1041
+ justifyClass,
1042
+ wrapClass,
1043
+ growClass,
1044
+ mtClass,
1045
+ className
1046
+ ),
1047
+ style,
1048
+ onClick,
1049
+ children
1050
+ }
1051
+ );
1052
+ }
1053
+
1054
+ // src/simple-stack.tsx
1055
+ import { cn as cn19 } from "@petrarca/sonnet-core";
1056
+ import { jsx as jsx19 } from "react/jsx-runtime";
1057
+ var gapMap2 = {
1058
+ 0: "gap-0",
1059
+ xs: "gap-1",
1060
+ sm: "gap-2",
1061
+ md: "gap-4",
1062
+ lg: "gap-6",
1063
+ xl: "gap-8",
1064
+ 2: "gap-0.5",
1065
+ 4: "gap-1",
1066
+ 6: "gap-1.5",
1067
+ 8: "gap-2",
1068
+ 24: "gap-6"
1069
+ };
1070
+ var alignMap2 = {
1071
+ start: "items-start",
1072
+ center: "items-center",
1073
+ end: "items-end",
1074
+ stretch: "items-stretch"
1075
+ };
1076
+ var justifyMap2 = {
1077
+ start: "justify-start",
1078
+ center: "justify-center",
1079
+ end: "justify-end",
1080
+ between: "justify-between",
1081
+ around: "justify-around"
1082
+ };
1083
+ function SimpleStack({
1084
+ children,
1085
+ gap = "md",
1086
+ align,
1087
+ justify,
1088
+ className,
1089
+ style,
1090
+ h
1091
+ }) {
1092
+ const gapClass = gapMap2[gap] || gapMap2.md;
1093
+ const alignClass = align ? alignMap2[align] : void 0;
1094
+ const justifyClass = justify ? justifyMap2[justify] : void 0;
1095
+ const heightStyle = h !== void 0 ? { height: typeof h === "number" ? `${h}px` : h } : void 0;
1096
+ return /* @__PURE__ */ jsx19(
1097
+ "div",
1098
+ {
1099
+ className: cn19(
1100
+ "flex flex-col",
1101
+ gapClass,
1102
+ alignClass,
1103
+ justifyClass,
1104
+ className
1105
+ ),
1106
+ style: { ...heightStyle, ...style },
1107
+ children
1108
+ }
1109
+ );
1110
+ }
1111
+
1112
+ // src/tooltip.tsx
1113
+ import * as React16 from "react";
1114
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
1115
+ import { cn as cn20 } from "@petrarca/sonnet-core";
1116
+ import { jsx as jsx20 } from "react/jsx-runtime";
1117
+ var TooltipProvider = TooltipPrimitive.Provider;
1118
+ var Tooltip = TooltipPrimitive.Root;
1119
+ var TooltipTrigger = TooltipPrimitive.Trigger;
1120
+ var TooltipContent = React16.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx20(
1121
+ TooltipPrimitive.Content,
1122
+ {
1123
+ ref,
1124
+ sideOffset,
1125
+ className: cn20(
1126
+ "z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md 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 origin-[--radix-tooltip-content-transform-origin]",
1127
+ className
1128
+ ),
1129
+ ...props
1130
+ }
1131
+ ));
1132
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
1133
+
1134
+ // src/simple-tooltip.tsx
1135
+ import { jsx as jsx21, jsxs as jsxs6 } from "react/jsx-runtime";
1136
+ function SimpleTooltip({
1137
+ label,
1138
+ children,
1139
+ side,
1140
+ align,
1141
+ delayDuration = 700,
1142
+ sideOffset
1143
+ }) {
1144
+ return /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration, children: /* @__PURE__ */ jsxs6(Tooltip, { children: [
1145
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children }),
1146
+ /* @__PURE__ */ jsx21(TooltipContent, { side, align, sideOffset, children: label })
1147
+ ] }) });
1148
+ }
1149
+
1150
+ // src/skeleton.tsx
1151
+ import { cn as cn21 } from "@petrarca/sonnet-core";
1152
+ import { jsx as jsx22 } from "react/jsx-runtime";
1153
+ function Skeleton({
1154
+ className,
1155
+ ...props
1156
+ }) {
1157
+ return /* @__PURE__ */ jsx22(
1158
+ "div",
1159
+ {
1160
+ className: cn21("animate-pulse rounded-md bg-muted", className),
1161
+ ...props
1162
+ }
1163
+ );
1164
+ }
1165
+
1166
+ // src/spinner.tsx
1167
+ import { cn as cn22 } from "@petrarca/sonnet-core";
1168
+ import { jsx as jsx23 } from "react/jsx-runtime";
1169
+ var sizeClasses = {
1170
+ sm: "h-4 w-4 border-2",
1171
+ md: "h-8 w-8 border-2",
1172
+ lg: "h-12 w-12 border-3"
1173
+ };
1174
+ function Spinner({ className, size = "md" }) {
1175
+ return /* @__PURE__ */ jsx23(
1176
+ "div",
1177
+ {
1178
+ className: cn22(
1179
+ "inline-block animate-spin rounded-full border-solid border-current border-r-transparent align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite]",
1180
+ sizeClasses[size],
1181
+ className
1182
+ ),
1183
+ role: "status",
1184
+ children: /* @__PURE__ */ jsx23("span", { className: "!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]", children: "Loading..." })
1185
+ }
1186
+ );
1187
+ }
1188
+
1189
+ // src/tabs.tsx
1190
+ import * as React17 from "react";
1191
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
1192
+ import { cn as cn23 } from "@petrarca/sonnet-core";
1193
+ import { jsx as jsx24 } from "react/jsx-runtime";
1194
+ var Tabs = TabsPrimitive.Root;
1195
+ var TabsList = React17.forwardRef(({ className, align = "start", ...props }, ref) => {
1196
+ const alignClass = align === "center" ? "justify-center" : align === "end" ? "justify-end" : "justify-start";
1197
+ return /* @__PURE__ */ jsx24(
1198
+ TabsPrimitive.List,
1199
+ {
1200
+ ref,
1201
+ className: cn23(
1202
+ "inline-flex h-10 items-center rounded-md bg-muted p-1 text-muted-foreground",
1203
+ alignClass,
1204
+ className
1205
+ ),
1206
+ ...props
1207
+ }
1208
+ );
1209
+ });
1210
+ TabsList.displayName = TabsPrimitive.List.displayName;
1211
+ var TabsTrigger = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
1212
+ TabsPrimitive.Trigger,
1213
+ {
1214
+ ref,
1215
+ className: cn23(
1216
+ "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
1217
+ className
1218
+ ),
1219
+ ...props
1220
+ }
1221
+ ));
1222
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
1223
+ var TabsContent = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
1224
+ TabsPrimitive.Content,
1225
+ {
1226
+ ref,
1227
+ className: cn23(
1228
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
1229
+ "data-[state=inactive]:hidden",
1230
+ className
1231
+ ),
1232
+ ...props
1233
+ }
1234
+ ));
1235
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
1236
+
1237
+ // src/stepper.tsx
1238
+ import { Check as Check3 } from "lucide-react";
1239
+ import {
1240
+ Direction as DirectionPrimitive,
1241
+ Slot as SlotPrimitive
1242
+ } from "radix-ui";
1243
+ import * as React21 from "react";
1244
+ import { useComposedRefs } from "@petrarca/sonnet-core";
1245
+ import { cn as cn24 } from "@petrarca/sonnet-core";
1246
+
1247
+ // src/radix/hooks/use-as-ref.ts
1248
+ import * as React19 from "react";
1249
+
1250
+ // src/radix/hooks/use-isomorphic-layout-effect.ts
1251
+ import * as React18 from "react";
1252
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? React18.useLayoutEffect : React18.useEffect;
1253
+
1254
+ // src/radix/hooks/use-as-ref.ts
1255
+ function useAsRef(props) {
1256
+ const ref = React19.useRef(props);
1257
+ useIsomorphicLayoutEffect(() => {
1258
+ ref.current = props;
1259
+ });
1260
+ return ref;
1261
+ }
1262
+
1263
+ // src/radix/hooks/use-lazy-ref.ts
1264
+ import * as React20 from "react";
1265
+ function useLazyRef(fn) {
1266
+ const ref = React20.useRef(null);
1267
+ if (ref.current === null) {
1268
+ ref.current = fn();
1269
+ }
1270
+ return ref;
1271
+ }
1272
+
1273
+ // src/stepper.tsx
1274
+ import { jsx as jsx25 } from "react/jsx-runtime";
1275
+ var ROOT_NAME = "Stepper";
1276
+ var LIST_NAME = "StepperList";
1277
+ var ITEM_NAME = "StepperItem";
1278
+ var TRIGGER_NAME = "StepperTrigger";
1279
+ var INDICATOR_NAME = "StepperIndicator";
1280
+ var SEPARATOR_NAME = "StepperSeparator";
1281
+ var TITLE_NAME = "StepperTitle";
1282
+ var DESCRIPTION_NAME = "StepperDescription";
1283
+ var CONTENT_NAME = "StepperContent";
1284
+ var PREV_NAME = "StepperPrev";
1285
+ var NEXT_NAME = "StepperNext";
1286
+ var ENTRY_FOCUS = "stepperFocusGroup.onEntryFocus";
1287
+ var EVENT_OPTIONS = { bubbles: false, cancelable: true };
1288
+ var ARROW_KEYS = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"];
1289
+ function getId(id, variant, value) {
1290
+ return `${id}-${variant}-${value}`;
1291
+ }
1292
+ var MAP_KEY_TO_FOCUS_INTENT = {
1293
+ ArrowLeft: "prev",
1294
+ ArrowUp: "prev",
1295
+ ArrowRight: "next",
1296
+ ArrowDown: "next",
1297
+ PageUp: "first",
1298
+ Home: "first",
1299
+ PageDown: "last",
1300
+ End: "last"
1301
+ };
1302
+ function getDirectionAwareKey(key, dir) {
1303
+ if (dir !== "rtl") return key;
1304
+ return key === "ArrowLeft" ? "ArrowRight" : key === "ArrowRight" ? "ArrowLeft" : key;
1305
+ }
1306
+ function getFocusIntent(event, dir, orientation) {
1307
+ const key = getDirectionAwareKey(event.key, dir);
1308
+ if (orientation === "horizontal" && ["ArrowUp", "ArrowDown"].includes(key))
1309
+ return void 0;
1310
+ if (orientation === "vertical" && ["ArrowLeft", "ArrowRight"].includes(key))
1311
+ return void 0;
1312
+ return MAP_KEY_TO_FOCUS_INTENT[key];
1313
+ }
1314
+ function focusFirst(candidates, preventScroll = false) {
1315
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
1316
+ for (const candidateRef of candidates) {
1317
+ const candidate = candidateRef.current;
1318
+ if (!candidate) continue;
1319
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
1320
+ candidate.focus({ preventScroll });
1321
+ if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
1322
+ }
1323
+ }
1324
+ function wrapArray(array, startIndex) {
1325
+ return array.map(
1326
+ (_, index) => array[(startIndex + index) % array.length]
1327
+ );
1328
+ }
1329
+ function handleActivationKeys(event, nonInteractive, activationMode, isDisabled, triggerRef) {
1330
+ if (event.key === "Enter" && nonInteractive) {
1331
+ event.preventDefault();
1332
+ return true;
1333
+ }
1334
+ if ((event.key === "Enter" || event.key === " ") && activationMode === "manual" && !nonInteractive) {
1335
+ event.preventDefault();
1336
+ if (!isDisabled && triggerRef.current) {
1337
+ triggerRef.current.click();
1338
+ }
1339
+ return true;
1340
+ }
1341
+ return false;
1342
+ }
1343
+ function hasModifierKey(event) {
1344
+ return event.metaKey || event.ctrlKey || event.altKey || event.shiftKey;
1345
+ }
1346
+ function resolveFocusCandidates(items, focusIntent, currentTarget, loop) {
1347
+ let candidateRefs = items.map((item) => item.ref);
1348
+ if (focusIntent === "last") {
1349
+ candidateRefs.reverse();
1350
+ } else if (focusIntent === "prev" || focusIntent === "next") {
1351
+ if (focusIntent === "prev") candidateRefs.reverse();
1352
+ const currentIndex = candidateRefs.findIndex(
1353
+ (ref) => ref.current === currentTarget
1354
+ );
1355
+ candidateRefs = loop ? wrapArray(candidateRefs, currentIndex + 1) : candidateRefs.slice(currentIndex + 1);
1356
+ }
1357
+ return candidateRefs;
1358
+ }
1359
+ async function handleValidatedNavigation(store, candidateRefs, items, itemValue, value, steps) {
1360
+ if (!store.hasValidation() || candidateRefs.length === 0) return false;
1361
+ const nextRef = candidateRefs[0];
1362
+ const nextElement = nextRef?.current;
1363
+ const nextItem = items.find((item) => item.ref.current === nextElement);
1364
+ if (!nextItem || nextItem.value === itemValue) return false;
1365
+ const currentStepIndex = Array.from(steps.keys()).indexOf(value || "");
1366
+ const targetStepIndex = Array.from(steps.keys()).indexOf(nextItem.value);
1367
+ const direction = targetStepIndex > currentStepIndex ? "next" : "prev";
1368
+ if (direction === "next") {
1369
+ const isValid = await store.setStateWithValidation(
1370
+ nextItem.value,
1371
+ direction
1372
+ );
1373
+ if (!isValid) return true;
1374
+ } else {
1375
+ store.setState("value", nextItem.value);
1376
+ }
1377
+ queueMicrotask(() => nextElement?.focus());
1378
+ return true;
1379
+ }
1380
+ function getDataState(value, itemValue, stepState, steps, variant = "item") {
1381
+ const stepKeys = Array.from(steps.keys());
1382
+ const currentIndex = stepKeys.indexOf(itemValue);
1383
+ if (stepState?.completed) return "completed";
1384
+ if (value === itemValue) {
1385
+ return variant === "separator" ? "inactive" : "active";
1386
+ }
1387
+ if (value) {
1388
+ const activeIndex = stepKeys.indexOf(value);
1389
+ if (activeIndex > currentIndex) return "completed";
1390
+ }
1391
+ return "inactive";
1392
+ }
1393
+ var StoreContext = React21.createContext(null);
1394
+ function useStoreContext(consumerName) {
1395
+ const context = React21.useContext(StoreContext);
1396
+ if (!context) {
1397
+ throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
1398
+ }
1399
+ return context;
1400
+ }
1401
+ function useStore(selector) {
1402
+ const store = useStoreContext("useStore");
1403
+ const getSnapshot = React21.useCallback(
1404
+ () => selector(store.getState()),
1405
+ [store, selector]
1406
+ );
1407
+ return React21.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
1408
+ }
1409
+ var StepperContext = React21.createContext(null);
1410
+ function useStepperContext(consumerName) {
1411
+ const context = React21.useContext(StepperContext);
1412
+ if (!context) {
1413
+ throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
1414
+ }
1415
+ return context;
1416
+ }
1417
+ function Stepper(props) {
1418
+ const {
1419
+ value,
1420
+ defaultValue,
1421
+ onValueChange,
1422
+ onValueComplete,
1423
+ onValueAdd,
1424
+ onValueRemove,
1425
+ onValidate,
1426
+ dir: dirProp,
1427
+ orientation = "horizontal",
1428
+ activationMode = "automatic",
1429
+ asChild,
1430
+ disabled = false,
1431
+ nonInteractive = false,
1432
+ loop = false,
1433
+ className,
1434
+ id,
1435
+ ...rootProps
1436
+ } = props;
1437
+ const listenersRef = useLazyRef(() => /* @__PURE__ */ new Set());
1438
+ const stateRef = useLazyRef(() => ({
1439
+ steps: /* @__PURE__ */ new Map(),
1440
+ value: value ?? defaultValue ?? ""
1441
+ }));
1442
+ const propsRef = useAsRef({
1443
+ onValueChange,
1444
+ onValueComplete,
1445
+ onValueAdd,
1446
+ onValueRemove,
1447
+ onValidate
1448
+ });
1449
+ const store = React21.useMemo(() => {
1450
+ return {
1451
+ subscribe: (cb) => {
1452
+ listenersRef.current.add(cb);
1453
+ return () => listenersRef.current.delete(cb);
1454
+ },
1455
+ getState: () => stateRef.current,
1456
+ setState: (key, value2) => {
1457
+ if (Object.is(stateRef.current[key], value2)) return;
1458
+ if (key === "value" && typeof value2 === "string") {
1459
+ stateRef.current.value = value2;
1460
+ propsRef.current.onValueChange?.(value2);
1461
+ } else {
1462
+ stateRef.current[key] = value2;
1463
+ }
1464
+ store.notify();
1465
+ },
1466
+ setStateWithValidation: async (value2, direction) => {
1467
+ if (!propsRef.current.onValidate) {
1468
+ store.setState("value", value2);
1469
+ return true;
1470
+ }
1471
+ try {
1472
+ const isValid = await propsRef.current.onValidate(value2, direction);
1473
+ if (isValid) {
1474
+ store.setState("value", value2);
1475
+ }
1476
+ return isValid;
1477
+ } catch {
1478
+ return false;
1479
+ }
1480
+ },
1481
+ hasValidation: () => !!propsRef.current.onValidate,
1482
+ addStep: (value2, completed, disabled2) => {
1483
+ const newStep = { value: value2, completed, disabled: disabled2 };
1484
+ stateRef.current.steps.set(value2, newStep);
1485
+ propsRef.current.onValueAdd?.(value2);
1486
+ store.notify();
1487
+ },
1488
+ removeStep: (value2) => {
1489
+ stateRef.current.steps.delete(value2);
1490
+ propsRef.current.onValueRemove?.(value2);
1491
+ store.notify();
1492
+ },
1493
+ setStep: (value2, completed, disabled2) => {
1494
+ const step = stateRef.current.steps.get(value2);
1495
+ if (step) {
1496
+ const updatedStep = { ...step, completed, disabled: disabled2 };
1497
+ stateRef.current.steps.set(value2, updatedStep);
1498
+ if (completed !== step.completed) {
1499
+ propsRef.current.onValueComplete?.(value2, completed);
1500
+ }
1501
+ store.notify();
1502
+ }
1503
+ },
1504
+ notify: () => {
1505
+ for (const cb of listenersRef.current) {
1506
+ cb();
1507
+ }
1508
+ }
1509
+ };
1510
+ }, [listenersRef, stateRef, propsRef]);
1511
+ useIsomorphicLayoutEffect(() => {
1512
+ if (value !== void 0) {
1513
+ store.setState("value", value);
1514
+ }
1515
+ }, [value]);
1516
+ const dir = DirectionPrimitive.useDirection(dirProp);
1517
+ const instanceId = React21.useId();
1518
+ const rootId = id ?? instanceId;
1519
+ const contextValue = React21.useMemo(
1520
+ () => ({
1521
+ rootId,
1522
+ dir,
1523
+ orientation,
1524
+ activationMode,
1525
+ disabled,
1526
+ nonInteractive,
1527
+ loop
1528
+ }),
1529
+ [rootId, dir, orientation, activationMode, disabled, nonInteractive, loop]
1530
+ );
1531
+ const RootPrimitive = asChild ? SlotPrimitive.Slot : "div";
1532
+ return /* @__PURE__ */ jsx25(StoreContext.Provider, { value: store, children: /* @__PURE__ */ jsx25(StepperContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx25(
1533
+ RootPrimitive,
1534
+ {
1535
+ id: rootId,
1536
+ "data-disabled": disabled ? "" : void 0,
1537
+ "data-orientation": orientation,
1538
+ "data-slot": "stepper",
1539
+ dir,
1540
+ ...rootProps,
1541
+ className: cn24(
1542
+ "flex gap-6",
1543
+ orientation === "horizontal" ? "w-full flex-col" : "flex-row",
1544
+ className
1545
+ )
1546
+ }
1547
+ ) }) });
1548
+ }
1549
+ var FocusContext = React21.createContext(null);
1550
+ function useFocusContext(consumerName) {
1551
+ const context = React21.useContext(FocusContext);
1552
+ if (!context) {
1553
+ throw new Error(
1554
+ `\`${consumerName}\` must be used within \`FocusProvider\``
1555
+ );
1556
+ }
1557
+ return context;
1558
+ }
1559
+ function StepperList(props) {
1560
+ const {
1561
+ asChild,
1562
+ onBlur: onBlurProp,
1563
+ onFocus: onFocusProp,
1564
+ onMouseDown: onMouseDownProp,
1565
+ className,
1566
+ children,
1567
+ ref,
1568
+ ...listProps
1569
+ } = props;
1570
+ const context = useStepperContext(LIST_NAME);
1571
+ const orientation = context.orientation;
1572
+ const currentValue = useStore((state) => state.value);
1573
+ const propsRef = useAsRef({
1574
+ onBlur: onBlurProp,
1575
+ onFocus: onFocusProp,
1576
+ onMouseDown: onMouseDownProp
1577
+ });
1578
+ const [tabStopId, setTabStopId] = React21.useState(null);
1579
+ const [isTabbingBackOut, setIsTabbingBackOut] = React21.useState(false);
1580
+ const [focusableItemCount, setFocusableItemCount] = React21.useState(0);
1581
+ const isClickFocusRef = React21.useRef(false);
1582
+ const itemsRef = React21.useRef(/* @__PURE__ */ new Map());
1583
+ const listRef = React21.useRef(null);
1584
+ const composedRef = useComposedRefs(ref, listRef);
1585
+ const onItemFocus = React21.useCallback((tabStopId2) => {
1586
+ setTabStopId(tabStopId2);
1587
+ }, []);
1588
+ const onItemShiftTab = React21.useCallback(() => {
1589
+ setIsTabbingBackOut(true);
1590
+ }, []);
1591
+ const onFocusableItemAdd = React21.useCallback(() => {
1592
+ setFocusableItemCount((prevCount) => prevCount + 1);
1593
+ }, []);
1594
+ const onFocusableItemRemove = React21.useCallback(() => {
1595
+ setFocusableItemCount((prevCount) => prevCount - 1);
1596
+ }, []);
1597
+ const onItemRegister = React21.useCallback((item) => {
1598
+ itemsRef.current.set(item.id, item);
1599
+ }, []);
1600
+ const onItemUnregister = React21.useCallback((id) => {
1601
+ itemsRef.current.delete(id);
1602
+ }, []);
1603
+ const getItems = React21.useCallback(() => {
1604
+ return Array.from(itemsRef.current.values()).filter((item) => item.ref.current).sort((a, b) => {
1605
+ const elementA = a.ref.current;
1606
+ const elementB = b.ref.current;
1607
+ if (!elementA || !elementB) return 0;
1608
+ const position = elementA.compareDocumentPosition(elementB);
1609
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
1610
+ return -1;
1611
+ }
1612
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
1613
+ return 1;
1614
+ }
1615
+ return 0;
1616
+ });
1617
+ }, []);
1618
+ const onBlur = React21.useCallback(
1619
+ (event) => {
1620
+ propsRef.current.onBlur?.(event);
1621
+ if (event.defaultPrevented) return;
1622
+ setIsTabbingBackOut(false);
1623
+ },
1624
+ [propsRef]
1625
+ );
1626
+ const onFocus = React21.useCallback(
1627
+ (event) => {
1628
+ propsRef.current.onFocus?.(event);
1629
+ if (event.defaultPrevented) return;
1630
+ const isKeyboardFocus = !isClickFocusRef.current;
1631
+ if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {
1632
+ const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);
1633
+ event.currentTarget.dispatchEvent(entryFocusEvent);
1634
+ if (!entryFocusEvent.defaultPrevented) {
1635
+ const items = Array.from(itemsRef.current.values()).filter(
1636
+ (item) => !item.disabled
1637
+ );
1638
+ const selectedItem = currentValue ? items.find((item) => item.value === currentValue) : void 0;
1639
+ const activeItem = items.find((item) => item.active);
1640
+ const currentItem = items.find((item) => item.id === tabStopId);
1641
+ const candidateItems = [
1642
+ selectedItem,
1643
+ activeItem,
1644
+ currentItem,
1645
+ ...items
1646
+ ].filter(Boolean);
1647
+ const candidateRefs = candidateItems.map((item) => item.ref);
1648
+ focusFirst(candidateRefs, false);
1649
+ }
1650
+ }
1651
+ isClickFocusRef.current = false;
1652
+ },
1653
+ [propsRef, isTabbingBackOut, currentValue, tabStopId]
1654
+ );
1655
+ const onMouseDown = React21.useCallback(
1656
+ (event) => {
1657
+ propsRef.current.onMouseDown?.(event);
1658
+ if (event.defaultPrevented) return;
1659
+ isClickFocusRef.current = true;
1660
+ },
1661
+ [propsRef]
1662
+ );
1663
+ const focusContextValue = React21.useMemo(
1664
+ () => ({
1665
+ tabStopId,
1666
+ onItemFocus,
1667
+ onItemShiftTab,
1668
+ onFocusableItemAdd,
1669
+ onFocusableItemRemove,
1670
+ onItemRegister,
1671
+ onItemUnregister,
1672
+ getItems
1673
+ }),
1674
+ [
1675
+ tabStopId,
1676
+ onItemFocus,
1677
+ onItemShiftTab,
1678
+ onFocusableItemAdd,
1679
+ onFocusableItemRemove,
1680
+ onItemRegister,
1681
+ onItemUnregister,
1682
+ getItems
1683
+ ]
1684
+ );
1685
+ const ListPrimitive = asChild ? SlotPrimitive.Slot : "div";
1686
+ return /* @__PURE__ */ jsx25(FocusContext.Provider, { value: focusContextValue, children: /* @__PURE__ */ jsx25(
1687
+ ListPrimitive,
1688
+ {
1689
+ role: "tablist",
1690
+ "aria-orientation": orientation,
1691
+ "data-orientation": orientation,
1692
+ "data-slot": "stepper-list",
1693
+ dir: context.dir,
1694
+ tabIndex: isTabbingBackOut || focusableItemCount === 0 ? -1 : 0,
1695
+ ...listProps,
1696
+ ref: composedRef,
1697
+ className: cn24(
1698
+ "flex outline-none",
1699
+ orientation === "horizontal" ? "flex-row items-center" : "flex-col items-start",
1700
+ className
1701
+ ),
1702
+ onBlur,
1703
+ onFocus,
1704
+ onMouseDown,
1705
+ children
1706
+ }
1707
+ ) });
1708
+ }
1709
+ var StepperItemContext = React21.createContext(
1710
+ null
1711
+ );
1712
+ function useStepperItemContext(consumerName) {
1713
+ const context = React21.useContext(StepperItemContext);
1714
+ if (!context) {
1715
+ throw new Error(`\`${consumerName}\` must be used within \`${ITEM_NAME}\``);
1716
+ }
1717
+ return context;
1718
+ }
1719
+ function StepperItem(props) {
1720
+ const {
1721
+ value: itemValue,
1722
+ completed = false,
1723
+ disabled = false,
1724
+ asChild,
1725
+ className,
1726
+ children,
1727
+ ref,
1728
+ ...itemProps
1729
+ } = props;
1730
+ const context = useStepperContext(ITEM_NAME);
1731
+ const store = useStoreContext(ITEM_NAME);
1732
+ const orientation = context.orientation;
1733
+ const value = useStore((state) => state.value);
1734
+ useIsomorphicLayoutEffect(() => {
1735
+ store.addStep(itemValue, completed, disabled);
1736
+ return () => {
1737
+ store.removeStep(itemValue);
1738
+ };
1739
+ }, [itemValue, completed, disabled]);
1740
+ useIsomorphicLayoutEffect(() => {
1741
+ store.setStep(itemValue, completed, disabled);
1742
+ }, [itemValue, completed, disabled]);
1743
+ const stepState = useStore((state) => state.steps.get(itemValue));
1744
+ const steps = useStore((state) => state.steps);
1745
+ const dataState = getDataState(value, itemValue, stepState, steps);
1746
+ const itemContextValue = React21.useMemo(
1747
+ () => ({
1748
+ value: itemValue,
1749
+ stepState
1750
+ }),
1751
+ [itemValue, stepState]
1752
+ );
1753
+ const ItemPrimitive = asChild ? SlotPrimitive.Slot : "div";
1754
+ return /* @__PURE__ */ jsx25(StepperItemContext.Provider, { value: itemContextValue, children: /* @__PURE__ */ jsx25(
1755
+ ItemPrimitive,
1756
+ {
1757
+ "data-disabled": stepState?.disabled ? "" : void 0,
1758
+ "data-orientation": orientation,
1759
+ "data-state": dataState,
1760
+ "data-slot": "stepper-item",
1761
+ dir: context.dir,
1762
+ ...itemProps,
1763
+ ref,
1764
+ className: cn24(
1765
+ "relative flex not-last:flex-1 items-center",
1766
+ orientation === "horizontal" ? "flex-row" : "flex-col",
1767
+ className
1768
+ ),
1769
+ children
1770
+ }
1771
+ ) });
1772
+ }
1773
+ function StepperTrigger(props) {
1774
+ const {
1775
+ asChild,
1776
+ onClick: onClickProp,
1777
+ onFocus: onFocusProp,
1778
+ onKeyDown: onKeyDownProp,
1779
+ onMouseDown: onMouseDownProp,
1780
+ disabled,
1781
+ className,
1782
+ ref,
1783
+ ...triggerProps
1784
+ } = props;
1785
+ const context = useStepperContext(TRIGGER_NAME);
1786
+ const itemContext = useStepperItemContext(TRIGGER_NAME);
1787
+ const itemValue = itemContext.value;
1788
+ const store = useStoreContext(TRIGGER_NAME);
1789
+ const focusContext = useFocusContext(TRIGGER_NAME);
1790
+ const value = useStore((state) => state.value);
1791
+ const steps = useStore((state) => state.steps);
1792
+ const stepState = useStore((state) => state.steps.get(itemValue));
1793
+ const propsRef = useAsRef({
1794
+ onClick: onClickProp,
1795
+ onFocus: onFocusProp,
1796
+ onKeyDown: onKeyDownProp,
1797
+ onMouseDown: onMouseDownProp
1798
+ });
1799
+ const activationMode = context.activationMode;
1800
+ const orientation = context.orientation;
1801
+ const loop = context.loop;
1802
+ const stepIndex = Array.from(steps.keys()).indexOf(itemValue);
1803
+ const stepPosition = stepIndex + 1;
1804
+ const stepCount = steps.size;
1805
+ const triggerId = getId(context.rootId, "trigger", itemValue);
1806
+ const contentId = getId(context.rootId, "content", itemValue);
1807
+ const titleId = getId(context.rootId, "title", itemValue);
1808
+ const descriptionId = getId(context.rootId, "description", itemValue);
1809
+ const isDisabled = disabled || stepState?.disabled || context.disabled;
1810
+ const isActive = value === itemValue;
1811
+ const isTabStop = focusContext.tabStopId === triggerId;
1812
+ const dataState = getDataState(value, itemValue, stepState, steps);
1813
+ const triggerRef = React21.useRef(null);
1814
+ const composedRef = useComposedRefs(ref, triggerRef);
1815
+ const isArrowKeyPressedRef = React21.useRef(false);
1816
+ const isMouseClickRef = React21.useRef(false);
1817
+ React21.useEffect(() => {
1818
+ function onKeyDown2(event) {
1819
+ if (ARROW_KEYS.includes(event.key)) {
1820
+ isArrowKeyPressedRef.current = true;
1821
+ }
1822
+ }
1823
+ function onKeyUp() {
1824
+ isArrowKeyPressedRef.current = false;
1825
+ }
1826
+ document.addEventListener("keydown", onKeyDown2);
1827
+ document.addEventListener("keyup", onKeyUp);
1828
+ return () => {
1829
+ document.removeEventListener("keydown", onKeyDown2);
1830
+ document.removeEventListener("keyup", onKeyUp);
1831
+ };
1832
+ }, []);
1833
+ useIsomorphicLayoutEffect(() => {
1834
+ focusContext.onItemRegister({
1835
+ id: triggerId,
1836
+ ref: triggerRef,
1837
+ value: itemValue,
1838
+ active: isTabStop,
1839
+ disabled: !!isDisabled
1840
+ });
1841
+ if (!isDisabled) {
1842
+ focusContext.onFocusableItemAdd();
1843
+ }
1844
+ return () => {
1845
+ focusContext.onItemUnregister(triggerId);
1846
+ if (!isDisabled) {
1847
+ focusContext.onFocusableItemRemove();
1848
+ }
1849
+ };
1850
+ }, [focusContext, triggerId, itemValue, isTabStop, isDisabled]);
1851
+ const onClick = React21.useCallback(
1852
+ async (event) => {
1853
+ propsRef.current.onClick?.(event);
1854
+ if (event.defaultPrevented) return;
1855
+ if (!isDisabled && !context.nonInteractive) {
1856
+ const currentStepIndex = Array.from(steps.keys()).indexOf(value ?? "");
1857
+ const targetStepIndex = Array.from(steps.keys()).indexOf(itemValue);
1858
+ const direction = targetStepIndex > currentStepIndex ? "next" : "prev";
1859
+ await store.setStateWithValidation(itemValue, direction);
1860
+ }
1861
+ },
1862
+ [
1863
+ isDisabled,
1864
+ context.nonInteractive,
1865
+ store,
1866
+ itemValue,
1867
+ value,
1868
+ steps,
1869
+ propsRef
1870
+ ]
1871
+ );
1872
+ const onFocus = React21.useCallback(
1873
+ async (event) => {
1874
+ propsRef.current.onFocus?.(event);
1875
+ if (event.defaultPrevented) return;
1876
+ focusContext.onItemFocus(triggerId);
1877
+ const isKeyboardFocus = !isMouseClickRef.current;
1878
+ if (!isActive && !isDisabled && activationMode !== "manual" && !context.nonInteractive && isKeyboardFocus) {
1879
+ const currentStepIndex = Array.from(steps.keys()).indexOf(value || "");
1880
+ const targetStepIndex = Array.from(steps.keys()).indexOf(itemValue);
1881
+ const direction = targetStepIndex > currentStepIndex ? "next" : "prev";
1882
+ await store.setStateWithValidation(itemValue, direction);
1883
+ }
1884
+ isMouseClickRef.current = false;
1885
+ },
1886
+ [
1887
+ focusContext,
1888
+ triggerId,
1889
+ activationMode,
1890
+ isActive,
1891
+ isDisabled,
1892
+ context.nonInteractive,
1893
+ store,
1894
+ itemValue,
1895
+ value,
1896
+ steps,
1897
+ propsRef
1898
+ ]
1899
+ );
1900
+ const onKeyDown = React21.useCallback(
1901
+ async (event) => {
1902
+ propsRef.current.onKeyDown?.(event);
1903
+ if (event.defaultPrevented) return;
1904
+ if (handleActivationKeys(
1905
+ event,
1906
+ context.nonInteractive,
1907
+ activationMode,
1908
+ isDisabled,
1909
+ triggerRef
1910
+ ))
1911
+ return;
1912
+ if (event.key === "Tab" && event.shiftKey) {
1913
+ focusContext.onItemShiftTab();
1914
+ return;
1915
+ }
1916
+ if (event.target !== event.currentTarget) return;
1917
+ const focusIntent = getFocusIntent(event, context.dir, orientation);
1918
+ if (focusIntent !== void 0) {
1919
+ if (hasModifierKey(event)) return;
1920
+ event.preventDefault();
1921
+ const items = focusContext.getItems().filter((item) => !item.disabled);
1922
+ const candidateRefs = resolveFocusCandidates(
1923
+ items,
1924
+ focusIntent,
1925
+ event.currentTarget,
1926
+ loop
1927
+ );
1928
+ const didNavigate = await handleValidatedNavigation(
1929
+ store,
1930
+ candidateRefs,
1931
+ items,
1932
+ itemValue,
1933
+ value,
1934
+ steps
1935
+ );
1936
+ if (didNavigate) return;
1937
+ queueMicrotask(() => focusFirst(candidateRefs));
1938
+ }
1939
+ },
1940
+ [
1941
+ focusContext,
1942
+ context.nonInteractive,
1943
+ context.dir,
1944
+ activationMode,
1945
+ orientation,
1946
+ loop,
1947
+ isDisabled,
1948
+ store,
1949
+ propsRef,
1950
+ itemValue,
1951
+ value,
1952
+ steps
1953
+ ]
1954
+ );
1955
+ const onMouseDown = React21.useCallback(
1956
+ (event) => {
1957
+ propsRef.current.onMouseDown?.(event);
1958
+ if (event.defaultPrevented) return;
1959
+ isMouseClickRef.current = true;
1960
+ if (isDisabled) {
1961
+ event.preventDefault();
1962
+ } else {
1963
+ focusContext.onItemFocus(triggerId);
1964
+ }
1965
+ },
1966
+ [focusContext, triggerId, isDisabled, propsRef]
1967
+ );
1968
+ const TriggerPrimitive = asChild ? SlotPrimitive.Slot : "button";
1969
+ return /* @__PURE__ */ jsx25(
1970
+ TriggerPrimitive,
1971
+ {
1972
+ id: triggerId,
1973
+ role: "tab",
1974
+ type: "button",
1975
+ "aria-controls": contentId,
1976
+ "aria-current": isActive ? "step" : void 0,
1977
+ "aria-describedby": `${titleId} ${descriptionId}`,
1978
+ "aria-posinset": stepPosition,
1979
+ "aria-selected": isActive,
1980
+ "aria-setsize": stepCount,
1981
+ "data-disabled": isDisabled ? "" : void 0,
1982
+ "data-state": dataState,
1983
+ "data-slot": "stepper-trigger",
1984
+ disabled: isDisabled,
1985
+ tabIndex: isTabStop ? 0 : -1,
1986
+ ...triggerProps,
1987
+ ref: composedRef,
1988
+ className: cn24(
1989
+ "inline-flex items-center justify-center gap-3 rounded-md text-left outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
1990
+ "not-has-data-[slot=description]:rounded-full not-has-data-[slot=title]:rounded-full",
1991
+ className
1992
+ ),
1993
+ onClick,
1994
+ onFocus,
1995
+ onKeyDown,
1996
+ onMouseDown
1997
+ }
1998
+ );
1999
+ }
2000
+ function StepperIndicator(props) {
2001
+ const { className, children, asChild, ref, ...indicatorProps } = props;
2002
+ const context = useStepperContext(INDICATOR_NAME);
2003
+ const itemContext = useStepperItemContext(INDICATOR_NAME);
2004
+ const value = useStore((state) => state.value);
2005
+ const itemValue = itemContext.value;
2006
+ const stepState = useStore((state) => state.steps.get(itemValue));
2007
+ const steps = useStore((state) => state.steps);
2008
+ const stepPosition = Array.from(steps.keys()).indexOf(itemValue) + 1;
2009
+ const dataState = getDataState(value, itemValue, stepState, steps);
2010
+ const IndicatorPrimitive = asChild ? SlotPrimitive.Slot : "div";
2011
+ return /* @__PURE__ */ jsx25(
2012
+ IndicatorPrimitive,
2013
+ {
2014
+ "data-state": dataState,
2015
+ "data-slot": "stepper-indicator",
2016
+ dir: context.dir,
2017
+ ...indicatorProps,
2018
+ ref,
2019
+ className: cn24(
2020
+ "flex size-7 shrink-0 items-center justify-center rounded-full border-2 border-muted bg-background font-medium text-muted-foreground text-sm transition-colors data-[state=active]:border-primary data-[state=completed]:border-primary data-[state=active]:bg-primary data-[state=completed]:bg-primary data-[state=active]:text-primary-foreground data-[state=completed]:text-primary-foreground",
2021
+ className
2022
+ ),
2023
+ children: typeof children === "function" ? children(dataState) : children ? children : dataState === "completed" ? /* @__PURE__ */ jsx25(Check3, { className: "size-4" }) : stepPosition
2024
+ }
2025
+ );
2026
+ }
2027
+ function StepperSeparator(props) {
2028
+ const {
2029
+ className,
2030
+ asChild,
2031
+ forceMount = false,
2032
+ ref,
2033
+ ...separatorProps
2034
+ } = props;
2035
+ const context = useStepperContext(SEPARATOR_NAME);
2036
+ const itemContext = useStepperItemContext(SEPARATOR_NAME);
2037
+ const value = useStore((state) => state.value);
2038
+ const steps = useStore((state) => state.steps);
2039
+ const orientation = context.orientation;
2040
+ const stepIndex = Array.from(steps.keys()).indexOf(itemContext.value);
2041
+ const isLastStep = stepIndex === steps.size - 1;
2042
+ if (isLastStep && !forceMount) return null;
2043
+ const dataState = getDataState(
2044
+ value,
2045
+ itemContext.value,
2046
+ itemContext.stepState,
2047
+ steps,
2048
+ "separator"
2049
+ );
2050
+ const SeparatorPrimitive2 = asChild ? SlotPrimitive.Slot : "div";
2051
+ return /* @__PURE__ */ jsx25(
2052
+ SeparatorPrimitive2,
2053
+ {
2054
+ role: "separator",
2055
+ "aria-hidden": "true",
2056
+ "aria-orientation": orientation,
2057
+ "data-orientation": orientation,
2058
+ "data-state": dataState,
2059
+ "data-slot": "stepper-separator",
2060
+ dir: context.dir,
2061
+ ...separatorProps,
2062
+ ref,
2063
+ className: cn24(
2064
+ "bg-border transition-colors data-[state=active]:bg-primary data-[state=completed]:bg-primary",
2065
+ orientation === "horizontal" ? "h-px flex-1" : "h-10 w-px",
2066
+ className
2067
+ )
2068
+ }
2069
+ );
2070
+ }
2071
+ function StepperTitle(props) {
2072
+ const { className, asChild, ref, ...titleProps } = props;
2073
+ const context = useStepperContext(TITLE_NAME);
2074
+ const itemContext = useStepperItemContext(TITLE_NAME);
2075
+ const titleId = getId(context.rootId, "title", itemContext.value);
2076
+ const TitlePrimitive = asChild ? SlotPrimitive.Slot : "span";
2077
+ return /* @__PURE__ */ jsx25(
2078
+ TitlePrimitive,
2079
+ {
2080
+ id: titleId,
2081
+ "data-slot": "title",
2082
+ dir: context.dir,
2083
+ ...titleProps,
2084
+ ref,
2085
+ className: cn24("font-medium text-sm", className)
2086
+ }
2087
+ );
2088
+ }
2089
+ function StepperDescription(props) {
2090
+ const { className, asChild, ref, ...descriptionProps } = props;
2091
+ const context = useStepperContext(DESCRIPTION_NAME);
2092
+ const itemContext = useStepperItemContext(DESCRIPTION_NAME);
2093
+ const descriptionId = getId(context.rootId, "description", itemContext.value);
2094
+ const DescriptionPrimitive = asChild ? SlotPrimitive.Slot : "span";
2095
+ return /* @__PURE__ */ jsx25(
2096
+ DescriptionPrimitive,
2097
+ {
2098
+ id: descriptionId,
2099
+ "data-slot": "description",
2100
+ dir: context.dir,
2101
+ ...descriptionProps,
2102
+ ref,
2103
+ className: cn24("text-muted-foreground text-xs", className)
2104
+ }
2105
+ );
2106
+ }
2107
+ function StepperContent(props) {
2108
+ const {
2109
+ value: valueProp,
2110
+ asChild,
2111
+ forceMount = false,
2112
+ ref,
2113
+ className,
2114
+ ...contentProps
2115
+ } = props;
2116
+ const context = useStepperContext(CONTENT_NAME);
2117
+ const value = useStore((state) => state.value);
2118
+ const contentId = getId(context.rootId, "content", valueProp);
2119
+ const triggerId = getId(context.rootId, "trigger", valueProp);
2120
+ if (valueProp !== value && !forceMount) return null;
2121
+ const ContentPrimitive = asChild ? SlotPrimitive.Slot : "div";
2122
+ return /* @__PURE__ */ jsx25(
2123
+ ContentPrimitive,
2124
+ {
2125
+ id: contentId,
2126
+ role: "tabpanel",
2127
+ "aria-labelledby": triggerId,
2128
+ "data-slot": "stepper-content",
2129
+ dir: context.dir,
2130
+ ...contentProps,
2131
+ ref,
2132
+ className: cn24("flex-1 outline-none", className)
2133
+ }
2134
+ );
2135
+ }
2136
+ function StepperPrev(props) {
2137
+ const { asChild, onClick: onClickProp, disabled, ...prevProps } = props;
2138
+ const store = useStoreContext(PREV_NAME);
2139
+ const value = useStore((state) => state.value);
2140
+ const steps = useStore((state) => state.steps);
2141
+ const propsRef = useAsRef({
2142
+ onClick: onClickProp
2143
+ });
2144
+ const stepKeys = Array.from(steps.keys());
2145
+ const currentIndex = value ? stepKeys.indexOf(value) : -1;
2146
+ const isDisabled = disabled || currentIndex <= 0;
2147
+ const onClick = React21.useCallback(
2148
+ async (event) => {
2149
+ propsRef.current.onClick?.(event);
2150
+ if (event.defaultPrevented || isDisabled) return;
2151
+ const prevIndex = Math.max(currentIndex - 1, 0);
2152
+ const prevStepValue = stepKeys[prevIndex];
2153
+ if (prevStepValue) {
2154
+ store.setState("value", prevStepValue);
2155
+ }
2156
+ },
2157
+ [propsRef, isDisabled, currentIndex, stepKeys, store]
2158
+ );
2159
+ const PrevPrimitive = asChild ? SlotPrimitive.Slot : "button";
2160
+ return /* @__PURE__ */ jsx25(
2161
+ PrevPrimitive,
2162
+ {
2163
+ type: "button",
2164
+ "data-slot": "stepper-prev",
2165
+ disabled: isDisabled,
2166
+ ...prevProps,
2167
+ onClick
2168
+ }
2169
+ );
2170
+ }
2171
+ function StepperNext(props) {
2172
+ const { asChild, onClick: onClickProp, disabled, ...nextProps } = props;
2173
+ const store = useStoreContext(NEXT_NAME);
2174
+ const value = useStore((state) => state.value);
2175
+ const steps = useStore((state) => state.steps);
2176
+ const propsRef = useAsRef({
2177
+ onClick: onClickProp
2178
+ });
2179
+ const stepKeys = Array.from(steps.keys());
2180
+ const currentIndex = value ? stepKeys.indexOf(value) : -1;
2181
+ const isDisabled = disabled || currentIndex >= stepKeys.length - 1;
2182
+ const onClick = React21.useCallback(
2183
+ async (event) => {
2184
+ propsRef.current.onClick?.(event);
2185
+ if (event.defaultPrevented || isDisabled) return;
2186
+ const nextIndex = Math.min(currentIndex + 1, stepKeys.length - 1);
2187
+ const nextStepValue = stepKeys[nextIndex];
2188
+ if (nextStepValue) {
2189
+ await store.setStateWithValidation(nextStepValue, "next");
2190
+ }
2191
+ },
2192
+ [propsRef, isDisabled, currentIndex, stepKeys, store]
2193
+ );
2194
+ const NextPrimitive = asChild ? SlotPrimitive.Slot : "button";
2195
+ return /* @__PURE__ */ jsx25(
2196
+ NextPrimitive,
2197
+ {
2198
+ type: "button",
2199
+ "data-slot": "stepper-next",
2200
+ disabled: isDisabled,
2201
+ ...nextProps,
2202
+ onClick
2203
+ }
2204
+ );
2205
+ }
2206
+
2207
+ // src/EntityTable/EntityTable.tsx
2208
+ import {
2209
+ useCallback as useCallback2,
2210
+ useEffect as useEffect3,
2211
+ useMemo as useMemo2,
2212
+ useRef as useRef4,
2213
+ useState as useState2
2214
+ } from "react";
2215
+ import {
2216
+ flexRender,
2217
+ getCoreRowModel,
2218
+ useReactTable
2219
+ } from "@tanstack/react-table";
2220
+ import { ChevronRight as ChevronRight2 } from "lucide-react";
2221
+ import { cn as cn25 } from "@petrarca/sonnet-core";
2222
+
2223
+ // src/EntityTable/tableSchema/mergeUiSchema.ts
2224
+ function resolveCellRenderer(property, uiEntry) {
2225
+ return uiEntry?.["x-ui-cell"] ?? property["x-ui-cell"];
2226
+ }
2227
+ function resolveCellOptions(property, uiEntry) {
2228
+ return {
2229
+ ...property["x-ui-cell-options"] ?? {},
2230
+ ...uiEntry?.["x-ui-cell-options"] ?? {}
2231
+ };
2232
+ }
2233
+ function mergeColumnConfig(key, property, uiSchema) {
2234
+ const uiEntry = uiSchema?.[key];
2235
+ const merged = {
2236
+ ...property["x-ui-column"] ?? {},
2237
+ ...uiEntry?.["x-ui-column"] ?? {}
2238
+ };
2239
+ return {
2240
+ order: merged.order,
2241
+ hidden: merged.hidden ?? false,
2242
+ width: merged.width,
2243
+ minWidth: merged.minWidth,
2244
+ label: merged.label,
2245
+ cellRenderer: resolveCellRenderer(property, uiEntry),
2246
+ cellOptions: resolveCellOptions(property, uiEntry)
2247
+ };
2248
+ }
2249
+
2250
+ // src/EntityTable/tableSchema/cellRegistry.ts
2251
+ import React22 from "react";
2252
+ import { warnLog } from "@petrarca/sonnet-core";
2253
+
2254
+ // src/EntityTable/tableSchema/cellRenderers.tsx
2255
+ import { formatDate, formatDateTime } from "@petrarca/sonnet-core";
2256
+ import { Fragment, jsx as jsx26, jsxs as jsxs7 } from "react/jsx-runtime";
2257
+ function resolveValue(value, options) {
2258
+ const key = options.valueKey;
2259
+ if (key && value != null && typeof value === "object") {
2260
+ return value[key];
2261
+ }
2262
+ return value;
2263
+ }
2264
+ function cx(base, options) {
2265
+ return options.nowrap ? [base, "whitespace-nowrap"].filter(Boolean).join(" ") : base;
2266
+ }
2267
+ function TextCell({
2268
+ value,
2269
+ options
2270
+ }) {
2271
+ const text = resolveValue(value, options);
2272
+ return /* @__PURE__ */ jsx26("span", { className: cx("", options), children: text == null ? "\u2014" : String(text) });
2273
+ }
2274
+ function MutedCell({
2275
+ value,
2276
+ options
2277
+ }) {
2278
+ const text = resolveValue(value, options);
2279
+ return /* @__PURE__ */ jsx26("span", { className: cx("text-muted-foreground", options), children: text == null ? "\u2014" : String(text) });
2280
+ }
2281
+ function BoldCell({
2282
+ value,
2283
+ options
2284
+ }) {
2285
+ const text = resolveValue(value, options);
2286
+ return /* @__PURE__ */ jsx26("span", { className: cx("font-medium", options), children: text == null ? "\u2014" : String(text) });
2287
+ }
2288
+ function CodeCell({
2289
+ value,
2290
+ options
2291
+ }) {
2292
+ const text = resolveValue(value, options);
2293
+ return /* @__PURE__ */ jsx26("span", { className: cx("font-mono text-xs", options), children: text == null ? "\u2014" : String(text) });
2294
+ }
2295
+ function BadgeCell({
2296
+ value,
2297
+ options
2298
+ }) {
2299
+ if (value == null)
2300
+ return /* @__PURE__ */ jsx26("span", { className: "text-muted-foreground", children: "\u2014" });
2301
+ const key = String(value);
2302
+ const colors = options.colors;
2303
+ const labels = options.labels;
2304
+ const color = colors?.[key];
2305
+ const label = labels?.[key] ?? key;
2306
+ return /* @__PURE__ */ jsx26(Badge, { badgeColor: color, children: label });
2307
+ }
2308
+ function DateCell({
2309
+ value,
2310
+ options
2311
+ }) {
2312
+ return /* @__PURE__ */ jsx26("span", { className: cx("text-muted-foreground", options), children: formatDate(value) });
2313
+ }
2314
+ function DateTimeCell({
2315
+ value,
2316
+ options
2317
+ }) {
2318
+ return /* @__PURE__ */ jsx26("span", { className: cx("text-muted-foreground", options), children: formatDateTime(value) });
2319
+ }
2320
+ function BooleanCell({ value }) {
2321
+ return /* @__PURE__ */ jsx26("span", { className: value ? "text-green-600" : "text-muted-foreground", children: value ? "Yes" : "No" });
2322
+ }
2323
+ function NumberCell({ value }) {
2324
+ const text = value == null ? "\u2014" : String(value);
2325
+ return /* @__PURE__ */ jsx26("span", { className: "tabular-nums", children: text });
2326
+ }
2327
+ function TruncateCell({
2328
+ value,
2329
+ options
2330
+ }) {
2331
+ const resolved = resolveValue(value, options);
2332
+ const text = resolved == null ? "\u2014" : String(resolved);
2333
+ return /* @__PURE__ */ jsx26("span", { className: "block truncate max-w-xs", title: text, children: text });
2334
+ }
2335
+ function OverflowListCell({
2336
+ value,
2337
+ options
2338
+ }) {
2339
+ const items = Array.isArray(value) ? value : [];
2340
+ if (items.length === 0)
2341
+ return /* @__PURE__ */ jsx26("span", { className: "text-muted-foreground", children: "\u2014" });
2342
+ const displayKey = options.displayKey;
2343
+ const fallbackKey = options.fallbackKey;
2344
+ const prefixKey = options.prefixKey;
2345
+ const first = items[0];
2346
+ const label = displayKey && first[displayKey] || fallbackKey && first[fallbackKey] || "";
2347
+ return /* @__PURE__ */ jsxs7(Fragment, { children: [
2348
+ prefixKey && /* @__PURE__ */ jsxs7("span", { className: "text-muted-foreground", children: [
2349
+ String(first[prefixKey]),
2350
+ ":",
2351
+ " "
2352
+ ] }),
2353
+ label,
2354
+ items.length > 1 && /* @__PURE__ */ jsxs7("span", { className: "text-muted-foreground ml-1", children: [
2355
+ "+",
2356
+ items.length - 1
2357
+ ] })
2358
+ ] });
2359
+ }
2360
+ function JoinCell({
2361
+ value,
2362
+ options
2363
+ }) {
2364
+ const sep = options.separator ?? ", ";
2365
+ if (!Array.isArray(value) || value.length === 0)
2366
+ return /* @__PURE__ */ jsx26("span", { className: "text-muted-foreground", children: "\u2014" });
2367
+ return /* @__PURE__ */ jsx26("span", { className: "text-muted-foreground", children: value.join(sep) });
2368
+ }
2369
+
2370
+ // src/EntityTable/tableSchema/cellRegistry.ts
2371
+ var CELL_RENDERERS = {
2372
+ text: TextCell,
2373
+ muted: MutedCell,
2374
+ bold: BoldCell,
2375
+ code: CodeCell,
2376
+ badge: BadgeCell,
2377
+ date: DateCell,
2378
+ datetime: DateTimeCell,
2379
+ boolean: BooleanCell,
2380
+ number: NumberCell,
2381
+ truncate: TruncateCell,
2382
+ "overflow-list": OverflowListCell,
2383
+ join: JoinCell
2384
+ };
2385
+ function inferCellRenderer(type, format) {
2386
+ if (type === "boolean") return "boolean";
2387
+ if (type === "number" || type === "integer") return "number";
2388
+ if (type === "string") {
2389
+ if (format === "date-time") return "datetime";
2390
+ if (format === "date") return "date";
2391
+ }
2392
+ return "text";
2393
+ }
2394
+ function resolveCellRenderer2(name, localRenderers) {
2395
+ return localRenderers?.[name] ?? CELL_RENDERERS[name] ?? TextCell;
2396
+ }
2397
+ function createRenderer(render) {
2398
+ return ({ row, options }) => React22.createElement(React22.Fragment, null, render(row, options));
2399
+ }
2400
+ function validateRendererNames(renderers) {
2401
+ for (const name of Object.keys(renderers)) {
2402
+ if (!name.startsWith("x-")) {
2403
+ warnLog(
2404
+ `[EntityTable] Local renderer "${name}" should use the x- prefix (e.g. "x-${name}"). Built-in renderer names are unprefixed.`
2405
+ );
2406
+ }
2407
+ }
2408
+ }
2409
+
2410
+ // src/EntityTable/tableSchema/columnResolver.ts
2411
+ function resolveColumns(schema, uiSchema) {
2412
+ const properties = schema.properties ?? {};
2413
+ const entries = Object.entries(properties).map(([key, property]) => {
2414
+ const config = mergeColumnConfig(key, property, uiSchema);
2415
+ return { key, property, config };
2416
+ }).filter(({ config }) => !config.hidden);
2417
+ const ordered = entries.filter(({ config }) => config.order !== void 0).sort((a, b) => a.config.order - b.config.order);
2418
+ const unordered = entries.filter(({ config }) => config.order === void 0).sort((a, b) => a.key.localeCompare(b.key));
2419
+ const sorted = [...ordered, ...unordered];
2420
+ return sorted.map(({ key, property, config }) => {
2421
+ const cellRenderer = config.cellRenderer ?? inferCellRenderer(property.type, property.format);
2422
+ const label = config.label ?? property.title ?? keyToLabel(key);
2423
+ return {
2424
+ key,
2425
+ label,
2426
+ property,
2427
+ cellRenderer,
2428
+ cellOptions: config.cellOptions,
2429
+ width: config.width,
2430
+ minWidth: config.minWidth
2431
+ };
2432
+ });
2433
+ }
2434
+ function keyToLabel(key) {
2435
+ return key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2436
+ }
2437
+
2438
+ // src/EntityTable/EntityTable.tsx
2439
+ import { jsx as jsx27, jsxs as jsxs8 } from "react/jsx-runtime";
2440
+ var coreRowModel = getCoreRowModel();
2441
+ function resolveTableDefaults(props) {
2442
+ return {
2443
+ isFiltered: props.isFiltered ?? false,
2444
+ selectionMode: props.selectionMode ?? false
2445
+ };
2446
+ }
2447
+ function buildColumnDefs(resolved, localRenderers) {
2448
+ return resolved.map((col) => {
2449
+ const Renderer = resolveCellRenderer2(col.cellRenderer, localRenderers);
2450
+ const options = col.cellOptions;
2451
+ const colDef = {
2452
+ id: col.key,
2453
+ accessorKey: col.key,
2454
+ header: col.label,
2455
+ cell: ({
2456
+ getValue,
2457
+ row
2458
+ }) => /* @__PURE__ */ jsx27(
2459
+ Renderer,
2460
+ {
2461
+ value: getValue(),
2462
+ row: row.original,
2463
+ options
2464
+ }
2465
+ )
2466
+ };
2467
+ if (col.width !== void 0) colDef.size = col.width;
2468
+ if (col.minWidth !== void 0) colDef.minSize = col.minWidth;
2469
+ return colDef;
2470
+ });
2471
+ }
2472
+ function buildSelectColumn() {
2473
+ return {
2474
+ id: "_select",
2475
+ size: 40,
2476
+ header: ({ table: t }) => /* @__PURE__ */ jsx27(
2477
+ Checkbox,
2478
+ {
2479
+ checked: t.getIsAllPageRowsSelected() || (t.getIsSomePageRowsSelected() ? "indeterminate" : false),
2480
+ onCheckedChange: (value) => t.toggleAllPageRowsSelected(!!value),
2481
+ "aria-label": "Select all"
2482
+ }
2483
+ ),
2484
+ cell: ({ row }) => /* @__PURE__ */ jsx27(
2485
+ Checkbox,
2486
+ {
2487
+ checked: row.getIsSelected(),
2488
+ onCheckedChange: (value) => row.toggleSelected(!!value),
2489
+ onClick: (e) => e.stopPropagation(),
2490
+ "aria-label": "Select row"
2491
+ }
2492
+ )
2493
+ };
2494
+ }
2495
+ function buildTableOptions(opts) {
2496
+ const base = {
2497
+ data: opts.dataRows,
2498
+ columns: opts.columns,
2499
+ getCoreRowModel: coreRowModel,
2500
+ state: opts.tableState
2501
+ };
2502
+ const selectionOpts = opts.selectionMode ? { enableRowSelection: true, onRowSelectionChange: opts.setRowSelection } : {};
2503
+ const paginationOpts = opts.isPaginated ? {
2504
+ manualPagination: true,
2505
+ rowCount: opts.data?.meta.total ?? 0,
2506
+ onPaginationChange: opts.onPaginationChange
2507
+ } : {};
2508
+ return { ...base, ...selectionOpts, ...paginationOpts };
2509
+ }
2510
+ function useEntityTableState(props, selectionMode) {
2511
+ const {
2512
+ schema,
2513
+ uiSchema,
2514
+ renderers,
2515
+ data,
2516
+ pagination,
2517
+ onPaginationChange,
2518
+ onSelectionChange
2519
+ } = props;
2520
+ const isPaginated = !!(pagination && onPaginationChange);
2521
+ const dataRows = useMemo2(() => data?.data ?? [], [data]);
2522
+ const total = data?.meta.total;
2523
+ const pageIndex = pagination?.pageIndex ?? 0;
2524
+ const pageSize = pagination?.pageSize ?? 1;
2525
+ useEffect3(() => {
2526
+ if (!isPaginated || total == null || !onPaginationChange) return;
2527
+ const maxPage = Math.max(0, Math.ceil(total / pageSize) - 1);
2528
+ if (pageIndex > maxPage) {
2529
+ onPaginationChange((prev) => ({ ...prev, pageIndex: maxPage }));
2530
+ }
2531
+ }, [total, isPaginated, pageIndex, pageSize, onPaginationChange]);
2532
+ const [rowSelection, setRowSelection] = useState2({});
2533
+ useEffect3(() => {
2534
+ setRowSelection({});
2535
+ }, [data]);
2536
+ const [activeRowIndex, setActiveRowIndex] = useState2(-1);
2537
+ const containerRef = useRef4(null);
2538
+ const dataColumns = useMemo2(() => {
2539
+ if (renderers) validateRendererNames(renderers);
2540
+ return buildColumnDefs(resolveColumns(schema, uiSchema), renderers);
2541
+ }, [schema, uiSchema, renderers]);
2542
+ const selectColumn = useMemo2(
2543
+ () => selectionMode ? buildSelectColumn() : null,
2544
+ [selectionMode]
2545
+ );
2546
+ const columns = useMemo2(
2547
+ () => selectColumn ? [selectColumn, ...dataColumns] : dataColumns,
2548
+ [selectColumn, dataColumns]
2549
+ );
2550
+ const onSelectionChangeRef = useRef4(onSelectionChange);
2551
+ onSelectionChangeRef.current = onSelectionChange;
2552
+ useEffect3(() => {
2553
+ if (!selectionMode || !onSelectionChangeRef.current) return;
2554
+ const selected = Object.keys(rowSelection).filter((k) => rowSelection[k]).map(Number).map((i) => dataRows[i]).filter((r) => r !== void 0);
2555
+ onSelectionChangeRef.current(selected);
2556
+ }, [rowSelection, selectionMode, dataRows]);
2557
+ const tableState = useMemo2(
2558
+ () => ({
2559
+ ...isPaginated ? { pagination } : {},
2560
+ ...selectionMode ? { rowSelection } : {}
2561
+ }),
2562
+ [isPaginated, pagination, selectionMode, rowSelection]
2563
+ );
2564
+ const tableOptions = buildTableOptions({
2565
+ dataRows,
2566
+ columns,
2567
+ tableState,
2568
+ selectionMode,
2569
+ setRowSelection,
2570
+ isPaginated,
2571
+ data,
2572
+ onPaginationChange
2573
+ });
2574
+ const table = useReactTable(tableOptions);
2575
+ useEffect3(() => {
2576
+ if (activeRowIndex < 0 || !containerRef.current) return;
2577
+ const rows = containerRef.current.querySelectorAll("tbody tr");
2578
+ rows[activeRowIndex]?.scrollIntoView({ block: "nearest" });
2579
+ }, [activeRowIndex]);
2580
+ return {
2581
+ table,
2582
+ dataRows,
2583
+ isPaginated,
2584
+ rowSelection,
2585
+ setRowSelection,
2586
+ activeRowIndex,
2587
+ setActiveRowIndex,
2588
+ containerRef,
2589
+ columns
2590
+ };
2591
+ }
2592
+ function useTableKeyboard(table, activeRowIndex, setActiveRowIndex, selectionMode, onRowClick) {
2593
+ return useCallback2(
2594
+ (e) => {
2595
+ const tableRows = table.getRowModel().rows;
2596
+ if (tableRows.length === 0) return;
2597
+ switch (e.key) {
2598
+ case "ArrowDown": {
2599
+ e.preventDefault();
2600
+ setActiveRowIndex((prev) => Math.min(prev + 1, tableRows.length - 1));
2601
+ break;
2602
+ }
2603
+ case "ArrowUp": {
2604
+ e.preventDefault();
2605
+ setActiveRowIndex((prev) => Math.max(prev - 1, 0));
2606
+ break;
2607
+ }
2608
+ case "Enter": {
2609
+ handleEnterKey(
2610
+ e,
2611
+ tableRows,
2612
+ selectionMode,
2613
+ activeRowIndex,
2614
+ onRowClick
2615
+ );
2616
+ break;
2617
+ }
2618
+ case " ": {
2619
+ handleSpaceKey(e, tableRows, selectionMode, activeRowIndex);
2620
+ break;
2621
+ }
2622
+ }
2623
+ },
2624
+ [activeRowIndex, onRowClick, selectionMode, table, setActiveRowIndex]
2625
+ );
2626
+ }
2627
+ function handleEnterKey(e, tableRows, selectionMode, activeRowIndex, onRowClick) {
2628
+ e.preventDefault();
2629
+ if (selectionMode || activeRowIndex < 0 || !onRowClick) return;
2630
+ const activeRow = tableRows[activeRowIndex];
2631
+ if (activeRow) onRowClick(activeRow.original);
2632
+ }
2633
+ function handleSpaceKey(e, tableRows, selectionMode, activeRowIndex) {
2634
+ if (!selectionMode || activeRowIndex < 0) return;
2635
+ e.preventDefault();
2636
+ tableRows[activeRowIndex]?.toggleSelected();
2637
+ }
2638
+ function resolveTrailingCols(rowActions, onRowClick, selectionMode) {
2639
+ const hasRowActions = !!(rowActions && rowActions.length > 0);
2640
+ const hasChevron = !!(onRowClick && !selectionMode && !hasRowActions);
2641
+ return {
2642
+ hasRowActions,
2643
+ hasChevron,
2644
+ hasTrailingCol: hasRowActions || hasChevron
2645
+ };
2646
+ }
2647
+ function StatusRows({
2648
+ isLoading,
2649
+ isError,
2650
+ errorMessage,
2651
+ entityLabel,
2652
+ isFiltered,
2653
+ emptyMessage,
2654
+ isEmpty,
2655
+ colCount
2656
+ }) {
2657
+ if (isLoading) {
2658
+ return /* @__PURE__ */ jsx27("tr", { children: /* @__PURE__ */ jsx27(
2659
+ "td",
2660
+ {
2661
+ colSpan: colCount,
2662
+ className: "px-4 py-8 text-center text-muted-foreground",
2663
+ children: "Loading..."
2664
+ }
2665
+ ) });
2666
+ }
2667
+ if (isError) {
2668
+ return /* @__PURE__ */ jsx27("tr", { children: /* @__PURE__ */ jsx27(
2669
+ "td",
2670
+ {
2671
+ colSpan: colCount,
2672
+ className: "px-4 py-8 text-center text-destructive",
2673
+ children: errorMessage ?? `Failed to load ${entityLabel}.`
2674
+ }
2675
+ ) });
2676
+ }
2677
+ if (isEmpty) {
2678
+ return /* @__PURE__ */ jsx27("tr", { children: /* @__PURE__ */ jsx27(
2679
+ "td",
2680
+ {
2681
+ colSpan: colCount,
2682
+ className: "px-4 py-8 text-center text-muted-foreground",
2683
+ children: resolveEmptyMessage(emptyMessage, isFiltered, entityLabel)
2684
+ }
2685
+ ) });
2686
+ }
2687
+ return null;
2688
+ }
2689
+ function resolveEmptyMessage(emptyMessage, isFiltered, entityLabel) {
2690
+ if (emptyMessage) return emptyMessage;
2691
+ if (isFiltered) return `No ${entityLabel} match your search.`;
2692
+ return `No ${entityLabel} yet.`;
2693
+ }
2694
+ function RowActionCell({
2695
+ actions,
2696
+ rowOriginal
2697
+ }) {
2698
+ return /* @__PURE__ */ jsx27("td", { className: "px-4 py-3 w-24 text-right", children: /* @__PURE__ */ jsx27("div", { className: "flex items-center justify-end gap-1", children: actions.map((action) => /* @__PURE__ */ jsx27(
2699
+ ActionButton,
2700
+ {
2701
+ action,
2702
+ rowOriginal
2703
+ },
2704
+ action.label
2705
+ )) }) });
2706
+ }
2707
+ function ActionButton({
2708
+ action,
2709
+ rowOriginal
2710
+ }) {
2711
+ const isHidden = action.hidden?.(rowOriginal);
2712
+ if (isHidden) return null;
2713
+ const isDisabled = action.disabled?.(rowOriginal);
2714
+ const Icon = action.icon;
2715
+ return /* @__PURE__ */ jsx27(
2716
+ "button",
2717
+ {
2718
+ title: action.label,
2719
+ disabled: isDisabled,
2720
+ onClick: (e) => {
2721
+ e.stopPropagation();
2722
+ action.onClick(rowOriginal);
2723
+ },
2724
+ className: cn25(
2725
+ "inline-flex items-center justify-center h-7 w-7 rounded-md transition-colors",
2726
+ action.variant === "destructive" ? "text-destructive hover:bg-destructive/10" : "text-muted-foreground hover:bg-accent",
2727
+ isDisabled ? "opacity-30 cursor-not-allowed group-hover/row:opacity-30" : "opacity-0 group-hover/row:opacity-100 focus:opacity-100"
2728
+ ),
2729
+ children: Icon ? /* @__PURE__ */ jsx27(Icon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx27("span", { className: "text-xs", children: action.label })
2730
+ },
2731
+ action.label
2732
+ );
2733
+ }
2734
+ function DataRow({
2735
+ row,
2736
+ index,
2737
+ selectionMode,
2738
+ activeRowIndex,
2739
+ onRowClick,
2740
+ setActiveRowIndex,
2741
+ containerRef,
2742
+ hasRowActions,
2743
+ hasChevron,
2744
+ rowActions
2745
+ }) {
2746
+ return /* @__PURE__ */ jsxs8(
2747
+ "tr",
2748
+ {
2749
+ onClick: () => {
2750
+ handleRowClick(
2751
+ row,
2752
+ index,
2753
+ selectionMode,
2754
+ onRowClick,
2755
+ setActiveRowIndex,
2756
+ containerRef
2757
+ );
2758
+ },
2759
+ className: cn25(
2760
+ "border-b last:border-b-0 transition-colors group/row",
2761
+ onRowClick && !selectionMode && "hover:bg-accent/50 cursor-pointer",
2762
+ selectionMode && "cursor-default",
2763
+ row.getIsSelected() && "bg-primary/10",
2764
+ index === activeRowIndex && selectionMode && "bg-accent"
2765
+ ),
2766
+ children: [
2767
+ row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx27("td", { className: "px-4 py-3", children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id)),
2768
+ hasRowActions && /* @__PURE__ */ jsx27(RowActionCell, { actions: rowActions, rowOriginal: row.original }),
2769
+ hasChevron && /* @__PURE__ */ jsx27("td", { className: "px-4 py-3 w-10", children: /* @__PURE__ */ jsx27(ChevronRight2, { className: "h-4 w-4 text-muted-foreground" }) })
2770
+ ]
2771
+ },
2772
+ row.id
2773
+ );
2774
+ }
2775
+ function handleRowClick(row, index, selectionMode, onRowClick, setActiveRowIndex, containerRef) {
2776
+ if (selectionMode) {
2777
+ row.toggleSelected();
2778
+ setActiveRowIndex(index);
2779
+ containerRef.current?.focus();
2780
+ } else if (onRowClick) {
2781
+ onRowClick(row.original);
2782
+ }
2783
+ }
2784
+ function TableFooter({
2785
+ isPaginated,
2786
+ data,
2787
+ dataRows,
2788
+ entityLabel,
2789
+ table
2790
+ }) {
2791
+ if (!data?.meta) return null;
2792
+ if (isPaginated) {
2793
+ return /* @__PURE__ */ jsx27(PaginationFooter, { table, entityLabel });
2794
+ }
2795
+ return /* @__PURE__ */ jsxs8("p", { className: "text-xs text-muted-foreground mt-3", children: [
2796
+ "Showing ",
2797
+ dataRows.length,
2798
+ " of ",
2799
+ data.meta.total,
2800
+ " ",
2801
+ entityLabel
2802
+ ] });
2803
+ }
2804
+ function EntityTable(props) {
2805
+ const {
2806
+ data,
2807
+ isLoading,
2808
+ isError,
2809
+ errorMessage,
2810
+ entityLabel,
2811
+ onRowClick,
2812
+ rowActions
2813
+ } = props;
2814
+ const { isFiltered, selectionMode } = resolveTableDefaults(props);
2815
+ const {
2816
+ table,
2817
+ dataRows,
2818
+ isPaginated,
2819
+ activeRowIndex,
2820
+ setActiveRowIndex,
2821
+ containerRef,
2822
+ columns
2823
+ } = useEntityTableState(props, selectionMode);
2824
+ const handleKeyDown = useTableKeyboard(
2825
+ table,
2826
+ activeRowIndex,
2827
+ setActiveRowIndex,
2828
+ selectionMode,
2829
+ onRowClick
2830
+ );
2831
+ const { hasRowActions, hasChevron, hasTrailingCol } = resolveTrailingCols(
2832
+ rowActions,
2833
+ onRowClick,
2834
+ selectionMode
2835
+ );
2836
+ const colCount = columns.length + (hasTrailingCol ? 1 : 0);
2837
+ return /* @__PURE__ */ jsxs8("div", { children: [
2838
+ /* @__PURE__ */ jsx27(
2839
+ "div",
2840
+ {
2841
+ ref: selectionMode ? containerRef : void 0,
2842
+ tabIndex: selectionMode ? 0 : void 0,
2843
+ onKeyDown: selectionMode ? handleKeyDown : void 0,
2844
+ className: cn25("rounded-lg border", selectionMode && "outline-none"),
2845
+ children: /* @__PURE__ */ jsxs8("table", { className: "w-full text-sm", children: [
2846
+ /* @__PURE__ */ jsx27("thead", { children: /* @__PURE__ */ jsxs8("tr", { className: "border-b bg-muted/40", children: [
2847
+ table.getFlatHeaders().map((header) => /* @__PURE__ */ jsx27(
2848
+ "th",
2849
+ {
2850
+ className: "text-left text-xs font-medium text-muted-foreground px-4 py-2.5",
2851
+ style: header.column.columnDef.size !== void 0 ? { width: header.column.columnDef.size } : void 0,
2852
+ children: header.isPlaceholder ? null : flexRender(
2853
+ header.column.columnDef.header,
2854
+ header.getContext()
2855
+ )
2856
+ },
2857
+ header.id
2858
+ )),
2859
+ hasRowActions && /* @__PURE__ */ jsx27(
2860
+ "th",
2861
+ {
2862
+ "aria-label": "Actions",
2863
+ scope: "col",
2864
+ className: "w-24 text-right text-xs font-medium text-muted-foreground px-4 py-2.5"
2865
+ }
2866
+ ),
2867
+ hasChevron && /* @__PURE__ */ jsx27("th", { "aria-label": "Open", scope: "col", className: "w-10" })
2868
+ ] }) }),
2869
+ /* @__PURE__ */ jsxs8("tbody", { children: [
2870
+ /* @__PURE__ */ jsx27(
2871
+ StatusRows,
2872
+ {
2873
+ isLoading,
2874
+ isError,
2875
+ errorMessage,
2876
+ entityLabel,
2877
+ isFiltered,
2878
+ emptyMessage: props.emptyMessage,
2879
+ isEmpty: !isLoading && !isError && dataRows.length === 0,
2880
+ colCount
2881
+ }
2882
+ ),
2883
+ table.getRowModel().rows.map((row, index) => /* @__PURE__ */ jsx27(
2884
+ DataRow,
2885
+ {
2886
+ row,
2887
+ index,
2888
+ selectionMode,
2889
+ activeRowIndex,
2890
+ onRowClick,
2891
+ setActiveRowIndex,
2892
+ containerRef,
2893
+ hasRowActions,
2894
+ hasChevron,
2895
+ rowActions
2896
+ },
2897
+ row.id
2898
+ ))
2899
+ ] })
2900
+ ] })
2901
+ }
2902
+ ),
2903
+ /* @__PURE__ */ jsx27(
2904
+ TableFooter,
2905
+ {
2906
+ isPaginated,
2907
+ data,
2908
+ dataRows,
2909
+ entityLabel,
2910
+ table
2911
+ }
2912
+ )
2913
+ ] });
2914
+ }
2915
+ function PaginationFooter({
2916
+ table,
2917
+ entityLabel
2918
+ }) {
2919
+ const { pageIndex, pageSize } = table.getState().pagination;
2920
+ const rowCount = table.getRowCount();
2921
+ const pageCount = table.getPageCount();
2922
+ const from = rowCount === 0 ? 0 : pageIndex * pageSize + 1;
2923
+ const to = Math.min((pageIndex + 1) * pageSize, rowCount);
2924
+ return /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between mt-3", children: [
2925
+ /* @__PURE__ */ jsx27("p", { className: "text-xs text-muted-foreground", children: rowCount === 0 ? `No ${entityLabel}` : `Showing ${from}\u2013${to} of ${rowCount} ${entityLabel}` }),
2926
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-1", children: [
2927
+ /* @__PURE__ */ jsx27(
2928
+ "button",
2929
+ {
2930
+ type: "button",
2931
+ onClick: () => table.previousPage(),
2932
+ disabled: !table.getCanPreviousPage(),
2933
+ className: "px-2 py-1 text-xs rounded border border-border text-muted-foreground hover:text-foreground hover:bg-accent transition-colors disabled:opacity-40 disabled:pointer-events-none",
2934
+ children: "Previous"
2935
+ }
2936
+ ),
2937
+ /* @__PURE__ */ jsx27("span", { className: "text-xs text-muted-foreground px-2", children: pageCount > 0 ? `${pageIndex + 1} / ${pageCount}` : "--" }),
2938
+ /* @__PURE__ */ jsx27(
2939
+ "button",
2940
+ {
2941
+ type: "button",
2942
+ onClick: () => table.nextPage(),
2943
+ disabled: !table.getCanNextPage(),
2944
+ className: "px-2 py-1 text-xs rounded border border-border text-muted-foreground hover:text-foreground hover:bg-accent transition-colors disabled:opacity-40 disabled:pointer-events-none",
2945
+ children: "Next"
2946
+ }
2947
+ )
2948
+ ] })
2949
+ ] });
2950
+ }
2951
+
2952
+ // src/EntitySelect/EntitySelect.tsx
2953
+ import * as React24 from "react";
2954
+ import { Check as Check4, ChevronsUpDown, Loader2 } from "lucide-react";
2955
+ import { cn as cn26 } from "@petrarca/sonnet-core";
2956
+ import {
2957
+ useEntityOptions
2958
+ } from "@petrarca/sonnet-core/hooks";
2959
+ import { Fragment as Fragment2, jsx as jsx28, jsxs as jsxs9 } from "react/jsx-runtime";
2960
+ function emptyStateMessage({
2961
+ mode,
2962
+ search,
2963
+ minChars,
2964
+ isLoading,
2965
+ hasSearched,
2966
+ emptyMessage
2967
+ }) {
2968
+ if (isLoading) return "Loading...";
2969
+ if (mode === "eager") return emptyMessage;
2970
+ if (search.length === 0) return "Start typing to search...";
2971
+ if (mode === "typeahead" && search.length < minChars)
2972
+ return `Type at least ${minChars} character${minChars > 1 ? "s" : ""} to search...`;
2973
+ if (mode === "explicit" && !hasSearched) return "Press Enter to search...";
2974
+ return emptyMessage;
2975
+ }
2976
+ function useHasSearched(submit) {
2977
+ const [hasSearched, setHasSearched] = React24.useState(false);
2978
+ const wrappedSubmit = React24.useCallback(() => {
2979
+ setHasSearched(true);
2980
+ submit();
2981
+ }, [submit]);
2982
+ return [hasSearched, wrappedSubmit];
2983
+ }
2984
+ function resolveEntitySelectDefaults(props) {
2985
+ return {
2986
+ mode: props.mode ?? "eager",
2987
+ minChars: props.minChars ?? 1,
2988
+ placeholder: props.placeholder ?? "Select...",
2989
+ searchPlaceholder: props.searchPlaceholder ?? "Search...",
2990
+ emptyMessage: props.emptyMessage ?? "No results found",
2991
+ disabled: props.disabled ?? false
2992
+ };
2993
+ }
2994
+ function EntitySelectLabel({
2995
+ id,
2996
+ label,
2997
+ required,
2998
+ description
2999
+ }) {
3000
+ const hasLabel = label !== void 0 && label !== false;
3001
+ return /* @__PURE__ */ jsxs9(Fragment2, { children: [
3002
+ hasLabel && /* @__PURE__ */ jsxs9(
3003
+ "label",
3004
+ {
3005
+ htmlFor: id,
3006
+ className: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
3007
+ children: [
3008
+ label,
3009
+ required && /* @__PURE__ */ jsx28("span", { className: "ml-1 text-destructive", children: "*" })
3010
+ ]
3011
+ }
3012
+ ),
3013
+ description && /* @__PURE__ */ jsx28("p", { className: "text-sm text-muted-foreground", children: description })
3014
+ ] });
3015
+ }
3016
+ function EntitySelectDropdown({
3017
+ searchPlaceholder,
3018
+ search,
3019
+ setSearch,
3020
+ mode,
3021
+ submit,
3022
+ minChars,
3023
+ isLoading,
3024
+ hasSearched,
3025
+ emptyMessage,
3026
+ options,
3027
+ value,
3028
+ handleSelect
3029
+ }) {
3030
+ return /* @__PURE__ */ jsxs9(Command, { shouldFilter: false, children: [
3031
+ /* @__PURE__ */ jsx28(
3032
+ CommandInput,
3033
+ {
3034
+ placeholder: searchPlaceholder,
3035
+ value: search,
3036
+ onValueChange: setSearch,
3037
+ onKeyDown: mode === "explicit" ? (e) => {
3038
+ if (e.key === "Enter") {
3039
+ e.preventDefault();
3040
+ submit();
3041
+ }
3042
+ } : void 0
3043
+ }
3044
+ ),
3045
+ /* @__PURE__ */ jsxs9(CommandList, { children: [
3046
+ /* @__PURE__ */ jsx28(CommandEmpty, { children: emptyStateMessage({
3047
+ mode,
3048
+ search,
3049
+ minChars,
3050
+ isLoading,
3051
+ hasSearched,
3052
+ emptyMessage
3053
+ }) }),
3054
+ /* @__PURE__ */ jsx28(CommandGroup, { children: options.map((option) => /* @__PURE__ */ jsxs9(
3055
+ CommandItem,
3056
+ {
3057
+ value: option.value,
3058
+ onSelect: handleSelect,
3059
+ children: [
3060
+ /* @__PURE__ */ jsx28(
3061
+ Check4,
3062
+ {
3063
+ className: cn26(
3064
+ "mr-2 h-4 w-4",
3065
+ value === option.value ? "opacity-100" : "opacity-0"
3066
+ )
3067
+ }
3068
+ ),
3069
+ option.label
3070
+ ]
3071
+ },
3072
+ option.value
3073
+ )) })
3074
+ ] })
3075
+ ] });
3076
+ }
3077
+ function EntitySelect(props) {
3078
+ const {
3079
+ fetcher,
3080
+ queryKey,
3081
+ value,
3082
+ onChange,
3083
+ onChangeOption,
3084
+ onBlur,
3085
+ label,
3086
+ required,
3087
+ description,
3088
+ error,
3089
+ className,
3090
+ id
3091
+ } = props;
3092
+ const {
3093
+ mode,
3094
+ minChars,
3095
+ placeholder,
3096
+ searchPlaceholder,
3097
+ emptyMessage,
3098
+ disabled
3099
+ } = resolveEntitySelectDefaults(props);
3100
+ const [open, setOpen] = React24.useState(false);
3101
+ const [selectedLabel, setSelectedLabel] = React24.useState(null);
3102
+ const {
3103
+ options,
3104
+ isLoading,
3105
+ search,
3106
+ setSearch,
3107
+ submit: rawSubmit
3108
+ } = useEntityOptions({ fetcher, queryKey, mode, minChars });
3109
+ const [hasSearched, submit] = useHasSearched(rawSubmit);
3110
+ React24.useEffect(() => {
3111
+ if (!value) {
3112
+ setSelectedLabel(null);
3113
+ return;
3114
+ }
3115
+ const found = options.find((opt) => opt.value === value);
3116
+ if (found) {
3117
+ setSelectedLabel(found.label);
3118
+ }
3119
+ }, [value, options]);
3120
+ const handleSelect = React24.useCallback(
3121
+ (selectedValue) => {
3122
+ const opt = options.find((o) => o.value === selectedValue);
3123
+ if (opt) setSelectedLabel(opt.label);
3124
+ const newValue = selectedValue === value ? null : selectedValue;
3125
+ if (newValue === null) setSelectedLabel(null);
3126
+ onChange?.(newValue);
3127
+ onChangeOption?.(newValue === null ? null : opt ?? null);
3128
+ setOpen(false);
3129
+ setSearch("");
3130
+ },
3131
+ [options, value, onChange, onChangeOption, setSearch]
3132
+ );
3133
+ const handleOpenChange = React24.useCallback(
3134
+ (newOpen) => {
3135
+ setOpen(newOpen);
3136
+ if (!newOpen) {
3137
+ setSearch("");
3138
+ onBlur?.();
3139
+ }
3140
+ },
3141
+ [onBlur, setSearch]
3142
+ );
3143
+ return /* @__PURE__ */ jsxs9("div", { className: cn26("space-y-2", className), children: [
3144
+ /* @__PURE__ */ jsx28(
3145
+ EntitySelectLabel,
3146
+ {
3147
+ id,
3148
+ label,
3149
+ required,
3150
+ description
3151
+ }
3152
+ ),
3153
+ /* @__PURE__ */ jsxs9(Popover, { open, onOpenChange: handleOpenChange, children: [
3154
+ /* @__PURE__ */ jsx28(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs9(
3155
+ Button,
3156
+ {
3157
+ id,
3158
+ variant: "outline",
3159
+ role: "combobox",
3160
+ "aria-expanded": open,
3161
+ className: cn26(
3162
+ "w-full justify-between",
3163
+ !selectedLabel && "text-muted-foreground",
3164
+ error && "border-destructive"
3165
+ ),
3166
+ disabled,
3167
+ children: [
3168
+ /* @__PURE__ */ jsx28("span", { className: "truncate", children: selectedLabel ?? placeholder }),
3169
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1", children: [
3170
+ isLoading && /* @__PURE__ */ jsx28(Loader2, { className: "h-4 w-4 animate-spin opacity-50" }),
3171
+ /* @__PURE__ */ jsx28(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50" })
3172
+ ] })
3173
+ ]
3174
+ }
3175
+ ) }),
3176
+ /* @__PURE__ */ jsx28(
3177
+ PopoverContent,
3178
+ {
3179
+ className: "w-[--radix-popover-trigger-width] p-0",
3180
+ align: "start",
3181
+ children: /* @__PURE__ */ jsx28(
3182
+ EntitySelectDropdown,
3183
+ {
3184
+ searchPlaceholder,
3185
+ search,
3186
+ setSearch,
3187
+ mode,
3188
+ submit,
3189
+ minChars,
3190
+ isLoading,
3191
+ hasSearched,
3192
+ emptyMessage,
3193
+ options,
3194
+ value,
3195
+ handleSelect
3196
+ }
3197
+ )
3198
+ }
3199
+ )
3200
+ ] }),
3201
+ error && /* @__PURE__ */ jsx28("p", { className: "text-sm font-medium text-destructive", children: error })
3202
+ ] });
3203
+ }
3204
+
3205
+ // src/EntityTree/EntityTree.tsx
3206
+ import {
3207
+ forwardRef as forwardRef19,
3208
+ useImperativeHandle as useImperativeHandle2,
3209
+ useMemo as useMemo4,
3210
+ useRef as useRef6
3211
+ } from "react";
3212
+ import { Pencil } from "lucide-react";
3213
+ import { cn as cn28 } from "@petrarca/sonnet-core";
3214
+
3215
+ // src/TreeView/TreeView.tsx
3216
+ import {
3217
+ forwardRef as forwardRef18,
3218
+ useCallback as useCallback4,
3219
+ useEffect as useEffect5,
3220
+ useId as useId2,
3221
+ useImperativeHandle,
3222
+ useMemo as useMemo3,
3223
+ useRef as useRef5,
3224
+ useState as useState4
3225
+ } from "react";
3226
+ import { ChevronRight as ChevronRight3 } from "lucide-react";
3227
+ import { cn as cn27 } from "@petrarca/sonnet-core";
3228
+ import { jsx as jsx29, jsxs as jsxs10 } from "react/jsx-runtime";
3229
+ function flatten(nodes, expandedIds, depth = 0, parentId = null, result = []) {
3230
+ for (const node of nodes) {
3231
+ result.push({ node, depth, parentId });
3232
+ if (expandedIds.has(node.id) && node.children) {
3233
+ flatten(node.children, expandedIds, depth + 1, node.id, result);
3234
+ }
3235
+ }
3236
+ return result;
3237
+ }
3238
+ var UNCONSTRAINED = /* @__PURE__ */ Symbol.for("tree-view:unconstrained");
3239
+ function ToggleIcon({
3240
+ hasChildren,
3241
+ isLoading,
3242
+ isExpanded
3243
+ }) {
3244
+ if (!hasChildren) {
3245
+ return /* @__PURE__ */ jsx29("span", { className: "block w-1.5 h-1.5 rounded-full bg-border mx-auto" });
3246
+ }
3247
+ if (isLoading) {
3248
+ return /* @__PURE__ */ jsx29("span", { className: "block w-3 h-3 rounded-full border-2 border-muted-foreground/40 border-t-foreground animate-spin" });
3249
+ }
3250
+ return /* @__PURE__ */ jsx29(
3251
+ ChevronRight3,
3252
+ {
3253
+ className: cn27(
3254
+ "h-3.5 w-3.5 text-muted-foreground transition-transform",
3255
+ isExpanded && "rotate-90"
3256
+ )
3257
+ }
3258
+ );
3259
+ }
3260
+ function NodeRow({
3261
+ flat,
3262
+ expandedIds,
3263
+ selectedIds,
3264
+ isSelectable,
3265
+ isFocused,
3266
+ indentPx,
3267
+ treeId,
3268
+ onExpand,
3269
+ onCollapse,
3270
+ onNodeClick,
3271
+ onSelectionChange,
3272
+ onFocus,
3273
+ renderNode
3274
+ }) {
3275
+ const { node, depth } = flat;
3276
+ const isExpanded = expandedIds.has(node.id);
3277
+ const isSelected = selectedIds.has(node.id);
3278
+ const handleToggle = useCallback4(
3279
+ (e) => {
3280
+ e.stopPropagation();
3281
+ if (isExpanded) {
3282
+ onCollapse(node.id);
3283
+ } else if (node.hasChildren) {
3284
+ onExpand(node.id);
3285
+ }
3286
+ },
3287
+ [isExpanded, node.id, node.hasChildren, onExpand, onCollapse]
3288
+ );
3289
+ const handleClick = useCallback4(() => {
3290
+ onFocus(node.id);
3291
+ onNodeClick?.(node);
3292
+ }, [node, onFocus, onNodeClick]);
3293
+ const handleCheckChange = useCallback4(
3294
+ (e) => {
3295
+ onSelectionChange?.(node.id, e.target.checked);
3296
+ },
3297
+ [node.id, onSelectionChange]
3298
+ );
3299
+ return /* @__PURE__ */ jsxs10(
3300
+ "li",
3301
+ {
3302
+ id: `${treeId}-node-${node.id}`,
3303
+ role: "treeitem",
3304
+ "aria-expanded": node.hasChildren ? isExpanded : void 0,
3305
+ "aria-selected": onSelectionChange ? isSelected : void 0,
3306
+ "aria-busy": node.isLoading,
3307
+ tabIndex: isFocused ? 0 : -1,
3308
+ className: cn27(
3309
+ "flex items-center gap-1 px-2 py-1.5 rounded-sm text-sm select-none",
3310
+ "cursor-pointer transition-colors",
3311
+ "hover:bg-accent/60",
3312
+ isFocused && "bg-accent ring-1 ring-ring ring-inset outline-none",
3313
+ isSelected && "bg-primary/10"
3314
+ ),
3315
+ style: { paddingLeft: depth * indentPx + 8 },
3316
+ onClick: handleClick,
3317
+ children: [
3318
+ /* @__PURE__ */ jsx29(
3319
+ "span",
3320
+ {
3321
+ className: "shrink-0 flex items-center justify-center w-4 h-4",
3322
+ onClick: handleToggle,
3323
+ "aria-hidden": true,
3324
+ children: /* @__PURE__ */ jsx29(
3325
+ ToggleIcon,
3326
+ {
3327
+ hasChildren: node.hasChildren,
3328
+ isLoading: node.isLoading,
3329
+ isExpanded
3330
+ }
3331
+ )
3332
+ }
3333
+ ),
3334
+ onSelectionChange && isSelectable && /* @__PURE__ */ jsx29(
3335
+ "input",
3336
+ {
3337
+ type: "checkbox",
3338
+ className: "shrink-0 h-3.5 w-3.5 rounded",
3339
+ checked: isSelected,
3340
+ onChange: handleCheckChange,
3341
+ onClick: (e) => e.stopPropagation(),
3342
+ "aria-label": `Select ${node.id}`,
3343
+ tabIndex: -1
3344
+ }
3345
+ ),
3346
+ /* @__PURE__ */ jsx29("span", { className: "flex-1 min-w-0", children: renderNode(node, depth) }),
3347
+ node.isError && /* @__PURE__ */ jsx29("span", { className: "shrink-0 text-xs text-destructive", "aria-live": "polite", children: "Failed to load" })
3348
+ ]
3349
+ }
3350
+ );
3351
+ }
3352
+ function TreeViewInner({
3353
+ nodes,
3354
+ expandedIds,
3355
+ onExpand,
3356
+ onCollapse,
3357
+ onNodeClick,
3358
+ onNodeActivate,
3359
+ renderNode,
3360
+ selectedIds,
3361
+ onSelectionChange,
3362
+ constrainSelectionToSiblings,
3363
+ indentPx = 20,
3364
+ className
3365
+ }, ref) {
3366
+ const treeId = useId2();
3367
+ const [focusedId, setFocusedId] = useState4(null);
3368
+ const listRef = useRef5(null);
3369
+ const [constrainedParent, setConstrainedParent] = useState4(UNCONSTRAINED);
3370
+ const selectionSize = selectedIds?.size ?? 0;
3371
+ useEffect5(() => {
3372
+ if (selectionSize === 0) setConstrainedParent(UNCONSTRAINED);
3373
+ }, [selectionSize]);
3374
+ useImperativeHandle(
3375
+ ref,
3376
+ () => ({
3377
+ focus() {
3378
+ const ul = listRef.current;
3379
+ if (!ul) return;
3380
+ const target = focusedId ? ul.querySelector(
3381
+ `[id$="-node-${CSS.escape(focusedId)}"]`
3382
+ ) : ul.querySelector('[role="treeitem"]');
3383
+ target?.focus();
3384
+ }
3385
+ }),
3386
+ [focusedId]
3387
+ );
3388
+ const flatNodes = useMemo3(
3389
+ () => flatten(nodes, expandedIds),
3390
+ [nodes, expandedIds]
3391
+ );
3392
+ const parentById = useMemo3(() => {
3393
+ const map = /* @__PURE__ */ new Map();
3394
+ for (const f of flatNodes) map.set(f.node.id, f.parentId);
3395
+ return map;
3396
+ }, [flatNodes]);
3397
+ const selectableSet = useMemo3(() => {
3398
+ if (!constrainSelectionToSiblings || constrainedParent === UNCONSTRAINED) {
3399
+ return void 0;
3400
+ }
3401
+ const ids = /* @__PURE__ */ new Set();
3402
+ for (const f of flatNodes) {
3403
+ if (f.parentId === constrainedParent) ids.add(f.node.id);
3404
+ }
3405
+ return ids;
3406
+ }, [constrainSelectionToSiblings, constrainedParent, flatNodes]);
3407
+ const handleSelectionChange = useCallback4(
3408
+ (nodeId, selected) => {
3409
+ if (constrainSelectionToSiblings && selected && constrainedParent === UNCONSTRAINED) {
3410
+ setConstrainedParent(parentById.get(nodeId) ?? null);
3411
+ }
3412
+ onSelectionChange?.(nodeId, selected);
3413
+ },
3414
+ [
3415
+ constrainSelectionToSiblings,
3416
+ constrainedParent,
3417
+ parentById,
3418
+ onSelectionChange
3419
+ ]
3420
+ );
3421
+ const focusedIndex = flatNodes.findIndex((f) => f.node.id === focusedId);
3422
+ const moveFocus = useCallback4(
3423
+ (delta) => {
3424
+ if (flatNodes.length === 0) return;
3425
+ const next = Math.max(
3426
+ 0,
3427
+ Math.min(flatNodes.length - 1, focusedIndex + delta)
3428
+ );
3429
+ const target = flatNodes[next];
3430
+ if (target) {
3431
+ setFocusedId(target.node.id);
3432
+ const el = listRef.current?.querySelector(
3433
+ `#${CSS.escape(`${treeId}-node-${target.node.id}`)}`
3434
+ );
3435
+ el?.scrollIntoView({ block: "nearest" });
3436
+ el?.focus();
3437
+ }
3438
+ },
3439
+ [flatNodes, focusedIndex, treeId]
3440
+ );
3441
+ const handleArrowRight = useCallback4(
3442
+ (current) => {
3443
+ if (current.node.hasChildren && !expandedIds.has(current.node.id)) {
3444
+ onExpand(current.node.id);
3445
+ } else if (current.node.children && current.node.children.length > 0) {
3446
+ moveFocus(1);
3447
+ }
3448
+ },
3449
+ [expandedIds, onExpand, moveFocus]
3450
+ );
3451
+ const handleArrowLeft = useCallback4(
3452
+ (current) => {
3453
+ if (expandedIds.has(current.node.id)) {
3454
+ onCollapse(current.node.id);
3455
+ return;
3456
+ }
3457
+ if (current.parentId === null) return;
3458
+ const parentIdx = flatNodes.findIndex(
3459
+ (f) => f.node.id === current.parentId
3460
+ );
3461
+ if (parentIdx < 0) return;
3462
+ const parentFlat = flatNodes[parentIdx];
3463
+ if (!parentFlat) return;
3464
+ setFocusedId(parentFlat.node.id);
3465
+ const el = listRef.current?.querySelector(
3466
+ `#${CSS.escape(`${treeId}-node-${parentFlat.node.id}`)}`
3467
+ );
3468
+ el?.focus();
3469
+ },
3470
+ [expandedIds, onCollapse, flatNodes, treeId]
3471
+ );
3472
+ const getFocusedNode = useCallback4(() => {
3473
+ if (focusedIndex < 0) return null;
3474
+ return flatNodes[focusedIndex] ?? null;
3475
+ }, [flatNodes, focusedIndex]);
3476
+ const activateNode = useCallback4(
3477
+ (flat) => {
3478
+ if (flat) onNodeActivate?.(flat.node);
3479
+ },
3480
+ [onNodeActivate]
3481
+ );
3482
+ const handleKeyDown = useCallback4(
3483
+ (e) => {
3484
+ switch (e.key) {
3485
+ case "ArrowDown":
3486
+ e.preventDefault();
3487
+ moveFocus(1);
3488
+ break;
3489
+ case "ArrowUp":
3490
+ e.preventDefault();
3491
+ moveFocus(-1);
3492
+ break;
3493
+ case "ArrowRight": {
3494
+ e.preventDefault();
3495
+ const current = getFocusedNode();
3496
+ if (current) handleArrowRight(current);
3497
+ break;
3498
+ }
3499
+ case "ArrowLeft": {
3500
+ e.preventDefault();
3501
+ const current = getFocusedNode();
3502
+ if (current) handleArrowLeft(current);
3503
+ break;
3504
+ }
3505
+ case "Enter":
3506
+ case " ":
3507
+ e.preventDefault();
3508
+ activateNode(getFocusedNode());
3509
+ break;
3510
+ default:
3511
+ break;
3512
+ }
3513
+ },
3514
+ [
3515
+ moveFocus,
3516
+ handleArrowRight,
3517
+ handleArrowLeft,
3518
+ getFocusedNode,
3519
+ activateNode
3520
+ ]
3521
+ );
3522
+ if (nodes.length === 0) {
3523
+ return /* @__PURE__ */ jsx29(
3524
+ "div",
3525
+ {
3526
+ className: cn27(
3527
+ "py-8 text-center text-sm text-muted-foreground",
3528
+ className
3529
+ ),
3530
+ children: "No items."
3531
+ }
3532
+ );
3533
+ }
3534
+ return /* @__PURE__ */ jsx29(
3535
+ "ul",
3536
+ {
3537
+ ref: listRef,
3538
+ role: "tree",
3539
+ "aria-label": "Tree",
3540
+ className: cn27("outline-none", className),
3541
+ onKeyDown: handleKeyDown,
3542
+ children: flatNodes.map((flat) => /* @__PURE__ */ jsx29(
3543
+ NodeRow,
3544
+ {
3545
+ flat,
3546
+ expandedIds,
3547
+ selectedIds: selectedIds ?? /* @__PURE__ */ new Set(),
3548
+ isSelectable: !selectableSet || selectableSet.has(flat.node.id),
3549
+ isFocused: flat.node.id === focusedId,
3550
+ indentPx,
3551
+ treeId,
3552
+ onExpand,
3553
+ onCollapse,
3554
+ onNodeClick,
3555
+ onSelectionChange: onSelectionChange ? handleSelectionChange : void 0,
3556
+ onFocus: setFocusedId,
3557
+ renderNode
3558
+ },
3559
+ flat.node.id
3560
+ ))
3561
+ }
3562
+ );
3563
+ }
3564
+ var TreeView = forwardRef18(TreeViewInner);
3565
+
3566
+ // src/EntityTree/EntityTree.tsx
3567
+ import { jsx as jsx30, jsxs as jsxs11 } from "react/jsx-runtime";
3568
+ function buildCellRow(resolved, activeNodeIdRef, onNodeEdit, localRenderers) {
3569
+ return function renderCells(node) {
3570
+ const isActive = node.id === activeNodeIdRef.current;
3571
+ return /* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-4 min-w-0 w-full group/row", children: [
3572
+ resolved.map((col) => {
3573
+ const Renderer = resolveCellRenderer2(
3574
+ col.cellRenderer,
3575
+ localRenderers
3576
+ );
3577
+ const value = node.data[col.key];
3578
+ return /* @__PURE__ */ jsx30(
3579
+ "span",
3580
+ {
3581
+ className: "shrink-0",
3582
+ style: col.width !== void 0 ? { width: col.width } : void 0,
3583
+ children: /* @__PURE__ */ jsx30(
3584
+ Renderer,
3585
+ {
3586
+ value,
3587
+ row: node.data,
3588
+ options: col.cellOptions
3589
+ }
3590
+ )
3591
+ },
3592
+ col.key
3593
+ );
3594
+ }),
3595
+ onNodeEdit && /* @__PURE__ */ jsx30("span", { className: "ml-auto shrink-0", children: /* @__PURE__ */ jsx30(
3596
+ "button",
3597
+ {
3598
+ type: "button",
3599
+ onClick: (e) => {
3600
+ e.stopPropagation();
3601
+ onNodeEdit(node);
3602
+ },
3603
+ "aria-label": "Edit",
3604
+ className: cn28(
3605
+ "p-1 rounded hover:bg-background text-muted-foreground hover:text-foreground transition-colors",
3606
+ isActive ? "opacity-100" : "opacity-0 group-hover/row:opacity-100"
3607
+ ),
3608
+ children: /* @__PURE__ */ jsx30(Pencil, { className: "h-3.5 w-3.5" })
3609
+ }
3610
+ ) })
3611
+ ] });
3612
+ };
3613
+ }
3614
+ function resolveEntityTreeDefaults(props) {
3615
+ return {
3616
+ isLoading: props.isLoading ?? false,
3617
+ isError: props.isError ?? false,
3618
+ entityLabel: props.entityLabel ?? "items",
3619
+ selectionMode: props.selectionMode ?? false
3620
+ };
3621
+ }
3622
+ function renderTreeStatus({
3623
+ isLoading,
3624
+ isError,
3625
+ errorMessage,
3626
+ entityLabel,
3627
+ nodes,
3628
+ className
3629
+ }) {
3630
+ if (isLoading && nodes.length === 0) {
3631
+ return /* @__PURE__ */ jsx30(
3632
+ "div",
3633
+ {
3634
+ className: cn28(
3635
+ "py-8 text-center text-sm text-muted-foreground",
3636
+ className
3637
+ ),
3638
+ children: "Loading\\u2026"
3639
+ }
3640
+ );
3641
+ }
3642
+ if (isError) {
3643
+ return /* @__PURE__ */ jsx30(
3644
+ "div",
3645
+ {
3646
+ className: cn28("py-8 text-center text-sm text-destructive", className),
3647
+ children: errorMessage ?? `Failed to load ${entityLabel}.`
3648
+ }
3649
+ );
3650
+ }
3651
+ if (!isLoading && nodes.length === 0) {
3652
+ return /* @__PURE__ */ jsxs11(
3653
+ "div",
3654
+ {
3655
+ className: cn28(
3656
+ "py-8 text-center text-sm text-muted-foreground",
3657
+ className
3658
+ ),
3659
+ children: [
3660
+ "No ",
3661
+ entityLabel,
3662
+ " yet."
3663
+ ]
3664
+ }
3665
+ );
3666
+ }
3667
+ return null;
3668
+ }
3669
+ function resolveRenderNode(renderNodeOverride, defaultRenderNode) {
3670
+ if (!renderNodeOverride) return defaultRenderNode;
3671
+ return (node, depth) => {
3672
+ const override = renderNodeOverride(node, depth);
3673
+ if (override !== null) return override;
3674
+ return defaultRenderNode(node);
3675
+ };
3676
+ }
3677
+ function resolveSelectionProps(selectionMode, props) {
3678
+ return {
3679
+ effectiveOnNodeEdit: selectionMode ? void 0 : props.onNodeEdit,
3680
+ onNodeActivate: selectionMode ? void 0 : props.onNodeEdit,
3681
+ selectedIds: selectionMode ? props.selectedIds : void 0,
3682
+ onSelectionChange: selectionMode ? props.onSelectionChange : void 0,
3683
+ constrainSelectionToSiblings: selectionMode ? props.constrainSelectionToSiblings : void 0
3684
+ };
3685
+ }
3686
+ function EntityTreeInner(props, ref) {
3687
+ const {
3688
+ schema,
3689
+ uiSchema,
3690
+ renderers,
3691
+ nodes,
3692
+ expandedIds,
3693
+ onExpand,
3694
+ onCollapse,
3695
+ errorMessage,
3696
+ onNodeSelect,
3697
+ onNodeEdit,
3698
+ activeNodeId,
3699
+ selectedIds,
3700
+ onSelectionChange,
3701
+ constrainSelectionToSiblings,
3702
+ renderNodeOverride,
3703
+ indentPx,
3704
+ className
3705
+ } = props;
3706
+ const { isLoading, isError, entityLabel, selectionMode } = resolveEntityTreeDefaults(props);
3707
+ const treeRef = useRef6(null);
3708
+ useImperativeHandle2(ref, () => ({
3709
+ focus() {
3710
+ treeRef.current?.focus();
3711
+ }
3712
+ }));
3713
+ const resolved = useMemo4(() => {
3714
+ if (renderers) validateRendererNames(renderers);
3715
+ return resolveColumns(schema, uiSchema);
3716
+ }, [schema, uiSchema, renderers]);
3717
+ const activeNodeIdRef = useRef6(activeNodeId);
3718
+ activeNodeIdRef.current = activeNodeId;
3719
+ const selection = resolveSelectionProps(selectionMode, {
3720
+ onNodeEdit,
3721
+ selectedIds,
3722
+ onSelectionChange,
3723
+ constrainSelectionToSiblings
3724
+ });
3725
+ const defaultRenderNode = useMemo4(
3726
+ () => buildCellRow(
3727
+ resolved,
3728
+ activeNodeIdRef,
3729
+ selection.effectiveOnNodeEdit,
3730
+ renderers
3731
+ ),
3732
+ [resolved, selection.effectiveOnNodeEdit, renderers]
3733
+ );
3734
+ const renderNode = useMemo4(
3735
+ () => resolveRenderNode(renderNodeOverride, defaultRenderNode),
3736
+ [renderNodeOverride, defaultRenderNode]
3737
+ );
3738
+ const statusView = renderTreeStatus({
3739
+ isLoading,
3740
+ isError,
3741
+ errorMessage,
3742
+ entityLabel,
3743
+ nodes,
3744
+ className
3745
+ });
3746
+ if (statusView) return statusView;
3747
+ return /* @__PURE__ */ jsx30("div", { className: cn28("rounded-lg border", className), children: /* @__PURE__ */ jsx30(
3748
+ TreeView,
3749
+ {
3750
+ ref: treeRef,
3751
+ nodes,
3752
+ expandedIds,
3753
+ onExpand,
3754
+ onCollapse,
3755
+ onNodeClick: onNodeSelect,
3756
+ onNodeActivate: selection.onNodeActivate,
3757
+ renderNode,
3758
+ selectedIds: selection.selectedIds,
3759
+ onSelectionChange: selection.onSelectionChange,
3760
+ constrainSelectionToSiblings: selection.constrainSelectionToSiblings,
3761
+ indentPx,
3762
+ className: "p-1"
3763
+ }
3764
+ ) });
3765
+ }
3766
+ var EntityTree = forwardRef19(EntityTreeInner);
3767
+
3768
+ // src/SearchInput/SearchInput.tsx
3769
+ import React29, { useMemo as useMemo6, useRef as useRef9, useState as useState7, useEffect as useEffect9 } from "react";
3770
+ import { Search as Search2, X as X3, ChevronDown } from "lucide-react";
3771
+ import { cn as cn30 } from "@petrarca/sonnet-core";
3772
+ import { getFieldTitle as getFieldTitle2 } from "@petrarca/sonnet-core/schema";
3773
+ import { isEmptyFilterExpr } from "@petrarca/sonnet-core/search";
3774
+
3775
+ // src/SearchInput/useSearchInput.ts
3776
+ import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef7, useState as useState5 } from "react";
3777
+ import { collectTerms } from "@petrarca/sonnet-core/search";
3778
+
3779
+ // src/SearchInput/schemaAdapter.ts
3780
+ import {
3781
+ getFieldTitle,
3782
+ getFieldHelpText,
3783
+ getFieldPlaceholder
3784
+ } from "@petrarca/sonnet-core/schema";
3785
+ function buildFacetDescriptors(schema) {
3786
+ const properties = schema.properties ?? {};
3787
+ const keys = Object.keys(properties);
3788
+ if (keys.length === 0) return [];
3789
+ const requiredSet = new Set(schema.required ?? []);
3790
+ const order = schema["x-ui-order"];
3791
+ const ordered = applyOrder(keys, order);
3792
+ return ordered.map((key) => {
3793
+ const property = properties[key];
3794
+ return {
3795
+ key,
3796
+ label: getFieldTitle(key, property),
3797
+ required: requiredSet.has(key),
3798
+ description: getFieldHelpText(property),
3799
+ placeholder: getFieldPlaceholder(property),
3800
+ property
3801
+ };
3802
+ });
3803
+ }
3804
+ function applyOrder(keys, order) {
3805
+ if (!order || order.length === 0) return keys;
3806
+ const keySet = new Set(keys);
3807
+ const ordered = [];
3808
+ for (const key of order) {
3809
+ if (keySet.has(key)) {
3810
+ ordered.push(key);
3811
+ keySet.delete(key);
3812
+ }
3813
+ }
3814
+ for (const key of keys) {
3815
+ if (keySet.has(key)) {
3816
+ ordered.push(key);
3817
+ }
3818
+ }
3819
+ return ordered;
3820
+ }
3821
+
3822
+ // src/SearchInput/useSearchInput.ts
3823
+ function buildSimpleExpr(text, searchFields) {
3824
+ const trimmed = text.trim();
3825
+ if (!trimmed) return { type: "and", children: [] };
3826
+ if (searchFields && searchFields.length > 0) {
3827
+ const terms = searchFields.map((key) => ({
3828
+ type: "term",
3829
+ key,
3830
+ value: trimmed
3831
+ }));
3832
+ if (terms.length === 1) {
3833
+ return { type: "and", children: terms };
3834
+ }
3835
+ return { type: "and", children: [{ type: "or", children: terms }] };
3836
+ }
3837
+ return {
3838
+ type: "and",
3839
+ children: [{ type: "term", key: "search", value: trimmed }]
3840
+ };
3841
+ }
3842
+ function useSearchInput({
3843
+ value,
3844
+ onChange,
3845
+ mode = "explicit",
3846
+ debounceMs = 300,
3847
+ schema,
3848
+ minChars = 0,
3849
+ searchFields
3850
+ }) {
3851
+ const allFacets = useMemo5(
3852
+ () => schema ? buildFacetDescriptors(schema) : [],
3853
+ [schema]
3854
+ );
3855
+ const isFaceted = allFacets.length > 0;
3856
+ const initialInput = !isFaceted ? (() => {
3857
+ const terms = collectTerms(value);
3858
+ return terms.length === 1 && terms[0].key === "search" ? terms[0].value : "";
3859
+ })() : "";
3860
+ const [inputValue, setInputValue] = useState5(initialInput);
3861
+ const [pendingFacet, setPendingFacet] = useState5(
3862
+ null
3863
+ );
3864
+ const [draftTerms, setDraftTerms] = useState5(
3865
+ () => isFaceted ? collectTerms(value) : []
3866
+ );
3867
+ const valueTerms = useMemo5(
3868
+ () => !isFaceted ? collectTerms(value) : [],
3869
+ [value, isFaceted]
3870
+ );
3871
+ const activeTerms = isFaceted ? draftTerms : valueTerms;
3872
+ const activeFieldKeys = useMemo5(
3873
+ () => new Set(activeTerms.map((t) => t.key)),
3874
+ [activeTerms]
3875
+ );
3876
+ const filteredFacets = useMemo5(() => {
3877
+ if (!isFaceted || pendingFacet || inputValue.endsWith(" ")) return [];
3878
+ const available = allFacets.filter((f) => !activeFieldKeys.has(f.key));
3879
+ if (!inputValue.trim()) return available;
3880
+ const lower = inputValue.toLowerCase();
3881
+ return available.filter((f) => f.label.toLowerCase().startsWith(lower));
3882
+ }, [inputValue, pendingFacet, isFaceted, allFacets, activeFieldKeys]);
3883
+ const onChangeRef = useRef7(onChange);
3884
+ onChangeRef.current = onChange;
3885
+ const draftTermsRef = useRef7(draftTerms);
3886
+ draftTermsRef.current = draftTerms;
3887
+ const pendingFacetRef = useRef7(pendingFacet);
3888
+ pendingFacetRef.current = pendingFacet;
3889
+ const inputValueRef = useRef7(inputValue);
3890
+ inputValueRef.current = inputValue;
3891
+ const isFacetedRef = useRef7(isFaceted);
3892
+ isFacetedRef.current = isFaceted;
3893
+ const allFacetsRef = useRef7(allFacets);
3894
+ allFacetsRef.current = allFacets;
3895
+ const filteredFacetsRef = useRef7(filteredFacets);
3896
+ filteredFacetsRef.current = filteredFacets;
3897
+ const minCharsRef = useRef7(minChars);
3898
+ minCharsRef.current = minChars;
3899
+ useEffect6(() => {
3900
+ if (!isFaceted) return;
3901
+ const terms = collectTerms(value);
3902
+ if (terms.length === 0) {
3903
+ setDraftTerms([]);
3904
+ setInputValue("");
3905
+ setPendingFacet(null);
3906
+ }
3907
+ }, [value, isFaceted]);
3908
+ const searchFieldsRef = useRef7(searchFields);
3909
+ searchFieldsRef.current = searchFields;
3910
+ const isMountedRef = useRef7(false);
3911
+ useEffect6(() => {
3912
+ if (!isMountedRef.current) {
3913
+ isMountedRef.current = true;
3914
+ return;
3915
+ }
3916
+ if (mode !== "debounce" || isFaceted) return;
3917
+ if (inputValue.trim().length < minCharsRef.current) return;
3918
+ const timer = setTimeout(() => {
3919
+ onChangeRef.current(buildSimpleExpr(inputValue, searchFieldsRef.current));
3920
+ }, debounceMs);
3921
+ return () => clearTimeout(timer);
3922
+ }, [inputValue, mode, debounceMs, isFaceted]);
3923
+ const submitDraft = useCallback5((terms) => {
3924
+ onChangeRef.current({ type: "and", children: terms });
3925
+ }, []);
3926
+ const allRequiredSatisfied = useCallback5((terms) => {
3927
+ const requiredKeys = allFacetsRef.current.filter((f) => f.required).map((f) => f.key);
3928
+ if (requiredKeys.length === 0) return true;
3929
+ const presentKeys = new Set(terms.map((t) => t.key));
3930
+ return requiredKeys.every((k) => presentKeys.has(k));
3931
+ }, []);
3932
+ const addChip = useCallback5((text) => {
3933
+ const trimmed = text.trim();
3934
+ if (!trimmed) return;
3935
+ const facet = pendingFacetRef.current ?? allFacetsRef.current[0] ?? null;
3936
+ if (!facet) return;
3937
+ const newTerm = {
3938
+ type: "term",
3939
+ key: facet.key,
3940
+ value: trimmed
3941
+ };
3942
+ const nextTerms = [...draftTermsRef.current, newTerm];
3943
+ setDraftTerms(nextTerms);
3944
+ setInputValue("");
3945
+ setPendingFacet(null);
3946
+ }, []);
3947
+ const commitFacetValue = addChip;
3948
+ const cancelPendingFacet = useCallback5(() => {
3949
+ setInputValue("");
3950
+ setPendingFacet(null);
3951
+ }, []);
3952
+ const handleInputChange = useCallback5(
3953
+ (e) => {
3954
+ setInputValue(e.target.value);
3955
+ },
3956
+ []
3957
+ );
3958
+ const tryAcceptSingleMatch = useCallback5(
3959
+ (e) => {
3960
+ if (!isFacetedRef.current || pendingFacetRef.current || filteredFacetsRef.current.length !== 1 || !inputValueRef.current.trim()) {
3961
+ return false;
3962
+ }
3963
+ e.preventDefault();
3964
+ setPendingFacet(filteredFacetsRef.current[0]);
3965
+ setInputValue("");
3966
+ return true;
3967
+ },
3968
+ []
3969
+ );
3970
+ const handleEnterFaceted = useCallback5(() => {
3971
+ const trimmed = inputValueRef.current.trim();
3972
+ if (trimmed) {
3973
+ addChip(trimmed);
3974
+ return false;
3975
+ }
3976
+ if (!pendingFacetRef.current) {
3977
+ if (allRequiredSatisfied(draftTermsRef.current)) {
3978
+ submitDraft(draftTermsRef.current);
3979
+ } else {
3980
+ return true;
3981
+ }
3982
+ }
3983
+ return false;
3984
+ }, [addChip, submitDraft, allRequiredSatisfied]);
3985
+ const handleEnterSimple = useCallback5(() => {
3986
+ if (inputValueRef.current.trim().length >= minCharsRef.current) {
3987
+ onChangeRef.current(
3988
+ buildSimpleExpr(inputValueRef.current, searchFieldsRef.current)
3989
+ );
3990
+ }
3991
+ }, []);
3992
+ const handleBackspaceEmpty = useCallback5(() => {
3993
+ if (isFacetedRef.current) {
3994
+ if (pendingFacetRef.current) {
3995
+ setPendingFacet(null);
3996
+ } else if (draftTermsRef.current.length > 0) {
3997
+ setDraftTerms((prev) => prev.slice(0, -1));
3998
+ }
3999
+ } else {
4000
+ onChangeRef.current({ type: "and", children: [] });
4001
+ }
4002
+ }, []);
4003
+ const handleKeyDown = useCallback5(
4004
+ (e) => {
4005
+ if ((e.key === "Tab" || e.key === "Enter") && tryAcceptSingleMatch(e)) {
4006
+ return false;
4007
+ }
4008
+ if (e.key === "Enter") {
4009
+ e.preventDefault();
4010
+ if (isFacetedRef.current) {
4011
+ return handleEnterFaceted();
4012
+ }
4013
+ handleEnterSimple();
4014
+ return false;
4015
+ }
4016
+ if (e.key === "Backspace" && inputValueRef.current === "") {
4017
+ handleBackspaceEmpty();
4018
+ }
4019
+ return false;
4020
+ },
4021
+ [
4022
+ tryAcceptSingleMatch,
4023
+ handleEnterFaceted,
4024
+ handleEnterSimple,
4025
+ handleBackspaceEmpty
4026
+ ]
4027
+ );
4028
+ const handleCommit = useCallback5(() => {
4029
+ if (isFacetedRef.current) {
4030
+ const trimmed = inputValueRef.current.trim();
4031
+ if (trimmed) {
4032
+ addChip(trimmed);
4033
+ } else if (!pendingFacetRef.current) {
4034
+ if (allRequiredSatisfied(draftTermsRef.current)) {
4035
+ submitDraft(draftTermsRef.current);
4036
+ }
4037
+ }
4038
+ } else if (inputValueRef.current.trim().length >= minCharsRef.current) {
4039
+ onChangeRef.current(
4040
+ buildSimpleExpr(inputValueRef.current, searchFieldsRef.current)
4041
+ );
4042
+ }
4043
+ }, [addChip, submitDraft, allRequiredSatisfied]);
4044
+ const handleRemoveTerm = useCallback5((index) => {
4045
+ const next = draftTermsRef.current.filter((_, i) => i !== index);
4046
+ setDraftTerms(next);
4047
+ onChangeRef.current({ type: "and", children: next });
4048
+ }, []);
4049
+ const handleClear = useCallback5(() => {
4050
+ setInputValue("");
4051
+ setPendingFacet(null);
4052
+ setDraftTerms([]);
4053
+ onChangeRef.current({ type: "and", children: [] });
4054
+ }, []);
4055
+ const selectFacet = useCallback5(
4056
+ (f) => setPendingFacet(f),
4057
+ []
4058
+ );
4059
+ return {
4060
+ inputValue,
4061
+ pendingFacet,
4062
+ isFaceted,
4063
+ filteredFacets,
4064
+ allFacets,
4065
+ selectFacet,
4066
+ handleInputChange,
4067
+ handleKeyDown,
4068
+ handleCommit,
4069
+ handleRemoveTerm,
4070
+ handleClear,
4071
+ activeTerms,
4072
+ commitFacetValue,
4073
+ cancelPendingFacet
4074
+ };
4075
+ }
4076
+
4077
+ // src/SearchInput/widgets/TextSearchWidget.tsx
4078
+ import { useRef as useRef8, useEffect as useEffect7 } from "react";
4079
+ import { jsx as jsx31 } from "react/jsx-runtime";
4080
+ function TextSearchWidget({
4081
+ value,
4082
+ onChange,
4083
+ onCommit,
4084
+ onCancel,
4085
+ placeholder,
4086
+ autoFocus
4087
+ }) {
4088
+ const inputRef = useRef8(null);
4089
+ useEffect7(() => {
4090
+ if (autoFocus) inputRef.current?.focus();
4091
+ }, [autoFocus]);
4092
+ return /* @__PURE__ */ jsx31(
4093
+ Input,
4094
+ {
4095
+ ref: inputRef,
4096
+ value,
4097
+ onChange: (e) => onChange(e.target.value),
4098
+ onKeyDown: (e) => {
4099
+ if (e.key === "Enter") {
4100
+ e.preventDefault();
4101
+ const trimmed = value.trim();
4102
+ if (trimmed) onCommit(trimmed);
4103
+ } else if (e.key === "Escape") {
4104
+ e.preventDefault();
4105
+ onCancel();
4106
+ } else if (e.key === "Backspace" && value === "") {
4107
+ e.preventDefault();
4108
+ onCancel();
4109
+ }
4110
+ },
4111
+ placeholder,
4112
+ className: "border-0 shadow-none focus-visible:ring-0 h-auto p-0 text-sm bg-transparent"
4113
+ }
4114
+ );
4115
+ }
4116
+
4117
+ // src/SearchInput/widgets/EnumSearchWidget.tsx
4118
+ import { useEffect as useEffect8, useState as useState6 } from "react";
4119
+ import { cn as cn29 } from "@petrarca/sonnet-core";
4120
+ import { jsx as jsx32, jsxs as jsxs12 } from "react/jsx-runtime";
4121
+ function EnumSearchWidget({
4122
+ property,
4123
+ options: widgetOptions,
4124
+ onCommit,
4125
+ onCancel,
4126
+ placeholder,
4127
+ autoFocus
4128
+ }) {
4129
+ const [open, setOpen] = useState6(false);
4130
+ const [search, setSearch] = useState6("");
4131
+ const [highlightedIndex, setHighlightedIndex] = useState6(0);
4132
+ const enumValues = property.enum ?? [];
4133
+ const enumNames = widgetOptions.enumNames ?? {};
4134
+ const items = enumValues.map((val) => ({
4135
+ value: val,
4136
+ label: enumNames[val] ?? val
4137
+ }));
4138
+ const filtered = search ? items.filter(
4139
+ (item) => item.label.toLowerCase().includes(search.toLowerCase())
4140
+ ) : items;
4141
+ useEffect8(() => {
4142
+ setHighlightedIndex(0);
4143
+ }, [filtered.length, search]);
4144
+ useEffect8(() => {
4145
+ if (autoFocus) {
4146
+ requestAnimationFrame(() => setOpen(true));
4147
+ }
4148
+ }, [autoFocus]);
4149
+ function handleCommit(val) {
4150
+ onCommit(val);
4151
+ setOpen(false);
4152
+ setSearch("");
4153
+ }
4154
+ function handleOpenChange(next) {
4155
+ setOpen(next);
4156
+ if (!next) setSearch("");
4157
+ }
4158
+ function handleKeyDown(e) {
4159
+ if (e.key === "Escape") {
4160
+ e.preventDefault();
4161
+ e.stopPropagation();
4162
+ setOpen(false);
4163
+ onCancel();
4164
+ return;
4165
+ }
4166
+ if (e.key === "ArrowDown") {
4167
+ e.preventDefault();
4168
+ setHighlightedIndex((i) => Math.min(i + 1, filtered.length - 1));
4169
+ return;
4170
+ }
4171
+ if (e.key === "ArrowUp") {
4172
+ e.preventDefault();
4173
+ setHighlightedIndex((i) => Math.max(i - 1, 0));
4174
+ return;
4175
+ }
4176
+ if (e.key === "Enter") {
4177
+ e.preventDefault();
4178
+ e.stopPropagation();
4179
+ const item = filtered[highlightedIndex];
4180
+ if (item) handleCommit(item.value);
4181
+ return;
4182
+ }
4183
+ }
4184
+ return /* @__PURE__ */ jsxs12(Popover, { open, onOpenChange: handleOpenChange, children: [
4185
+ /* @__PURE__ */ jsx32(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx32(
4186
+ "button",
4187
+ {
4188
+ type: "button",
4189
+ className: "text-sm text-muted-foreground hover:text-foreground transition-colors truncate text-left",
4190
+ onClick: () => setOpen(true),
4191
+ children: placeholder ?? "Select..."
4192
+ }
4193
+ ) }),
4194
+ /* @__PURE__ */ jsxs12(
4195
+ PopoverContent,
4196
+ {
4197
+ className: "w-48 p-1",
4198
+ align: "start",
4199
+ onOpenAutoFocus: (e) => e.preventDefault(),
4200
+ children: [
4201
+ /* @__PURE__ */ jsx32(
4202
+ "input",
4203
+ {
4204
+ autoFocus: true,
4205
+ value: search,
4206
+ onChange: (e) => setSearch(e.target.value),
4207
+ onKeyDown: handleKeyDown,
4208
+ placeholder: "Search...",
4209
+ className: "w-full px-2 py-1.5 text-sm bg-transparent outline-none border-b border-border mb-1 placeholder:text-muted-foreground"
4210
+ }
4211
+ ),
4212
+ /* @__PURE__ */ jsxs12("div", { children: [
4213
+ filtered.length === 0 && /* @__PURE__ */ jsx32("p", { className: "px-2 py-1.5 text-sm text-muted-foreground", children: "No matches" }),
4214
+ filtered.map((item, i) => /* @__PURE__ */ jsx32(
4215
+ "button",
4216
+ {
4217
+ type: "button",
4218
+ className: cn29(
4219
+ "w-full text-left px-2 py-1.5 text-sm rounded transition-colors",
4220
+ i === highlightedIndex ? "bg-accent text-accent-foreground" : "hover:bg-accent hover:text-accent-foreground"
4221
+ ),
4222
+ onMouseDown: (e) => {
4223
+ e.preventDefault();
4224
+ handleCommit(item.value);
4225
+ },
4226
+ onMouseEnter: () => setHighlightedIndex(i),
4227
+ children: item.label
4228
+ },
4229
+ item.value
4230
+ ))
4231
+ ] })
4232
+ ]
4233
+ }
4234
+ )
4235
+ ] });
4236
+ }
4237
+
4238
+ // src/SearchInput/widgets/resolveSearchWidget.ts
4239
+ function resolveSearchWidget(property, registry) {
4240
+ const widgetName = property["x-ui-widget"];
4241
+ if (widgetName && registry[widgetName]) {
4242
+ return registry[widgetName];
4243
+ }
4244
+ if (property.enum && property.enum.length > 0 && registry["enum"]) {
4245
+ return registry["enum"];
4246
+ }
4247
+ return registry["text"];
4248
+ }
4249
+
4250
+ // src/SearchInput/widgets/index.ts
4251
+ var DEFAULT_SEARCH_WIDGETS = {
4252
+ text: TextSearchWidget,
4253
+ enum: EnumSearchWidget
4254
+ };
4255
+
4256
+ // src/SearchInput/SearchInput.tsx
4257
+ import { Fragment as Fragment3, jsx as jsx33, jsxs as jsxs13 } from "react/jsx-runtime";
4258
+ function resolveSearchDefaults(props) {
4259
+ return {
4260
+ mode: props.mode ?? "explicit",
4261
+ debounceMs: props.debounceMs ?? 300,
4262
+ minChars: props.minChars ?? 0,
4263
+ showSearchButton: props.showSearchButton ?? false,
4264
+ disabled: props.disabled ?? false
4265
+ };
4266
+ }
4267
+ function FacetPicker({
4268
+ pickerVisible,
4269
+ hasFacetsToShow,
4270
+ filteredFacets,
4271
+ highlightedIndex,
4272
+ setPickerOpen,
4273
+ setHighlightedIndex,
4274
+ acceptFacet,
4275
+ inputRef
4276
+ }) {
4277
+ return /* @__PURE__ */ jsxs13(Popover, { open: pickerVisible, onOpenChange: setPickerOpen, modal: false, children: [
4278
+ /* @__PURE__ */ jsx33(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx33(
4279
+ "button",
4280
+ {
4281
+ type: "button",
4282
+ className: "inline-flex items-center gap-0.5 text-xs text-muted-foreground hover:text-foreground transition-colors shrink-0",
4283
+ tabIndex: -1,
4284
+ onClick: (e) => {
4285
+ e.stopPropagation();
4286
+ setPickerOpen((o) => !o);
4287
+ inputRef.current?.focus();
4288
+ },
4289
+ children: /* @__PURE__ */ jsx33(ChevronDown, { className: "h-3 w-3" })
4290
+ }
4291
+ ) }),
4292
+ /* @__PURE__ */ jsx33(
4293
+ PopoverContent,
4294
+ {
4295
+ className: cn30("w-44 p-1", !hasFacetsToShow && "hidden"),
4296
+ align: "start",
4297
+ onOpenAutoFocus: (e) => e.preventDefault(),
4298
+ onFocusOutside: (e) => e.preventDefault(),
4299
+ children: filteredFacets.map((facet, i) => /* @__PURE__ */ jsx33(
4300
+ "button",
4301
+ {
4302
+ type: "button",
4303
+ className: cn30(
4304
+ "w-full text-left px-2 py-1.5 text-sm rounded transition-colors",
4305
+ i === highlightedIndex ? "bg-accent text-accent-foreground" : "hover:bg-accent hover:text-accent-foreground"
4306
+ ),
4307
+ onMouseDown: (e) => {
4308
+ e.preventDefault();
4309
+ e.stopPropagation();
4310
+ acceptFacet(facet);
4311
+ },
4312
+ onMouseEnter: () => setHighlightedIndex(i),
4313
+ children: facet.label
4314
+ },
4315
+ facet.key
4316
+ ))
4317
+ }
4318
+ )
4319
+ ] });
4320
+ }
4321
+ function ValueEntry({
4322
+ pendingFacet,
4323
+ PendingWidget,
4324
+ pendingWidgetOptions,
4325
+ inputValue,
4326
+ handleInputChange,
4327
+ commitFacetValue,
4328
+ cancelPendingFacet,
4329
+ resolvedPlaceholder,
4330
+ disabled,
4331
+ inputRef,
4332
+ onInputKeyDown,
4333
+ onInputChange,
4334
+ onInputFocus
4335
+ }) {
4336
+ if (pendingFacet && PendingWidget) {
4337
+ return /* @__PURE__ */ jsx33(
4338
+ PendingWidget,
4339
+ {
4340
+ property: pendingFacet.property,
4341
+ options: pendingWidgetOptions,
4342
+ value: inputValue,
4343
+ onChange: (v) => handleInputChange({
4344
+ target: { value: v }
4345
+ }),
4346
+ onCommit: (v) => {
4347
+ commitFacetValue(v);
4348
+ requestAnimationFrame(() => inputRef.current?.focus());
4349
+ },
4350
+ onCancel: () => {
4351
+ cancelPendingFacet();
4352
+ requestAnimationFrame(() => inputRef.current?.focus());
4353
+ },
4354
+ placeholder: pendingFacet.placeholder ?? resolvedPlaceholder,
4355
+ autoFocus: true
4356
+ }
4357
+ );
4358
+ }
4359
+ return /* @__PURE__ */ jsx33(
4360
+ Input,
4361
+ {
4362
+ ref: inputRef,
4363
+ value: inputValue,
4364
+ onChange: onInputChange,
4365
+ onKeyDown: onInputKeyDown,
4366
+ onFocus: onInputFocus,
4367
+ placeholder: resolvedPlaceholder,
4368
+ disabled,
4369
+ autoComplete: "off",
4370
+ className: "border-0 shadow-none focus-visible:ring-0 h-auto p-0 text-sm bg-transparent"
4371
+ }
4372
+ );
4373
+ }
4374
+ function handlePickerArrowDown(ctx) {
4375
+ if (!ctx.isFaceted || ctx.pendingFacet) return false;
4376
+ ctx.setPickerNavigated(true);
4377
+ if (!ctx.pickerVisible) {
4378
+ ctx.setPickerOpen(true);
4379
+ } else {
4380
+ ctx.setHighlightedIndex(
4381
+ (i) => Math.min(i + 1, ctx.filteredFacets.length - 1)
4382
+ );
4383
+ }
4384
+ return true;
4385
+ }
4386
+ function handlePickerEnterSelect(ctx) {
4387
+ if (!ctx.hasFacetsToShow) return false;
4388
+ if (!ctx.pickerNavigated && !ctx.inputValue.trim()) return false;
4389
+ const clamped = Math.min(ctx.highlightedIndex, ctx.filteredFacets.length - 1);
4390
+ if (clamped >= 0 && ctx.filteredFacets[clamped]) {
4391
+ ctx.setPickerNavigated(false);
4392
+ ctx.acceptFacet(ctx.filteredFacets[clamped]);
4393
+ return true;
4394
+ }
4395
+ return false;
4396
+ }
4397
+ function handleInputKeyDown(e, ctx) {
4398
+ if (e.key === "ArrowDown" && handlePickerArrowDown(ctx)) {
4399
+ e.preventDefault();
4400
+ return;
4401
+ }
4402
+ if (e.key === "ArrowUp" && ctx.hasFacetsToShow) {
4403
+ e.preventDefault();
4404
+ ctx.setPickerNavigated(true);
4405
+ ctx.setHighlightedIndex((i) => Math.max(i - 1, 0));
4406
+ return;
4407
+ }
4408
+ if (e.key === "Enter" && handlePickerEnterSelect(ctx)) {
4409
+ e.preventDefault();
4410
+ return;
4411
+ }
4412
+ const reopenPicker = ctx.handleKeyDown(e);
4413
+ if (e.key === "Enter") {
4414
+ ctx.setPickerNavigated(false);
4415
+ ctx.setPickerOpen(!!reopenPicker);
4416
+ }
4417
+ }
4418
+ function resolvePlaceholder(isFaceted, hasActiveTerms, hasPendingFacet, placeholder) {
4419
+ const defaultPlaceholder = isFaceted ? "Add filter..." : "Search...";
4420
+ if (isFaceted && (hasActiveTerms || hasPendingFacet)) return "Add filter...";
4421
+ return placeholder ?? defaultPlaceholder;
4422
+ }
4423
+ function ActiveChips({
4424
+ terms,
4425
+ schema,
4426
+ onRemove
4427
+ }) {
4428
+ return /* @__PURE__ */ jsx33(Fragment3, { children: terms.map((term, i) => {
4429
+ const property = schema?.properties?.[term.key];
4430
+ const label = property ? getFieldTitle2(term.key, property) : term.key;
4431
+ return /* @__PURE__ */ jsx33(
4432
+ FilterChip,
4433
+ {
4434
+ label: `${label}: ${term.value}`,
4435
+ onRemove: () => onRemove(i)
4436
+ },
4437
+ `${term.key}:${term.value}`
4438
+ );
4439
+ }) });
4440
+ }
4441
+ function resolveWidgetForFacet(pendingFacet, registry) {
4442
+ if (!pendingFacet) return { Widget: null, options: {} };
4443
+ return {
4444
+ Widget: resolveSearchWidget(pendingFacet.property, registry),
4445
+ options: pendingFacet.property["x-ui-options"] ?? {}
4446
+ };
4447
+ }
4448
+ function SearchActions({
4449
+ isEmpty,
4450
+ showSearchButton,
4451
+ mode,
4452
+ onClear,
4453
+ onCommit
4454
+ }) {
4455
+ return /* @__PURE__ */ jsxs13(Fragment3, { children: [
4456
+ !isEmpty && /* @__PURE__ */ jsx33(
4457
+ "button",
4458
+ {
4459
+ type: "button",
4460
+ onClick: (e) => {
4461
+ e.stopPropagation();
4462
+ onClear();
4463
+ },
4464
+ className: "text-muted-foreground hover:text-foreground transition-colors shrink-0",
4465
+ "aria-label": "Clear search",
4466
+ children: /* @__PURE__ */ jsx33(X3, { className: "h-4 w-4" })
4467
+ }
4468
+ ),
4469
+ showSearchButton && mode === "explicit" && /* @__PURE__ */ jsx33(
4470
+ Button,
4471
+ {
4472
+ type: "button",
4473
+ size: "sm",
4474
+ variant: "ghost",
4475
+ className: "h-6 px-2 shrink-0",
4476
+ onClick: (e) => {
4477
+ e.stopPropagation();
4478
+ onCommit();
4479
+ },
4480
+ children: "Search"
4481
+ }
4482
+ )
4483
+ ] });
4484
+ }
4485
+ function mergeWidgetRegistry(custom) {
4486
+ return custom ? { ...DEFAULT_SEARCH_WIDGETS, ...custom } : DEFAULT_SEARCH_WIDGETS;
4487
+ }
4488
+ function SearchInput(props) {
4489
+ const {
4490
+ value,
4491
+ onChange,
4492
+ schema,
4493
+ widgets: customWidgets,
4494
+ searchFields,
4495
+ placeholder,
4496
+ className
4497
+ } = props;
4498
+ const { mode, debounceMs, minChars, showSearchButton, disabled } = resolveSearchDefaults(props);
4499
+ const inputRef = useRef9(null);
4500
+ const containerRef = useRef9(null);
4501
+ const [pickerOpen, setPickerOpen] = useState7(false);
4502
+ const [highlightedIndex, setHighlightedIndex] = useState7(-1);
4503
+ const [pickerNavigated, setPickerNavigated] = useState7(false);
4504
+ useEffect9(() => {
4505
+ if (!pickerOpen) return;
4506
+ function handleMouseDown(e) {
4507
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
4508
+ setPickerOpen(false);
4509
+ }
4510
+ }
4511
+ document.addEventListener("mousedown", handleMouseDown);
4512
+ return () => document.removeEventListener("mousedown", handleMouseDown);
4513
+ }, [pickerOpen]);
4514
+ const widgetRegistry = useMemo6(
4515
+ () => mergeWidgetRegistry(customWidgets),
4516
+ [customWidgets]
4517
+ );
4518
+ const {
4519
+ inputValue,
4520
+ pendingFacet,
4521
+ isFaceted,
4522
+ filteredFacets,
4523
+ selectFacet,
4524
+ handleInputChange,
4525
+ handleKeyDown,
4526
+ handleCommit,
4527
+ handleRemoveTerm,
4528
+ handleClear,
4529
+ activeTerms,
4530
+ commitFacetValue,
4531
+ cancelPendingFacet
4532
+ } = useSearchInput({
4533
+ value,
4534
+ onChange,
4535
+ mode,
4536
+ debounceMs,
4537
+ minChars,
4538
+ schema,
4539
+ searchFields
4540
+ });
4541
+ const isEmpty = isEmptyFilterExpr(value) && inputValue === "";
4542
+ useEffect9(() => {
4543
+ setHighlightedIndex(-1);
4544
+ }, [filteredFacets, pickerOpen]);
4545
+ const resolvedPlaceholder = resolvePlaceholder(
4546
+ isFaceted,
4547
+ activeTerms.length > 0,
4548
+ pendingFacet !== null,
4549
+ placeholder
4550
+ );
4551
+ const showFacetControls = isFaceted && !pendingFacet;
4552
+ const pickerVisible = showFacetControls && pickerOpen;
4553
+ const hasFacetsToShow = pickerVisible && filteredFacets.length > 0;
4554
+ const acceptFacet = React29.useCallback(
4555
+ (facet) => {
4556
+ selectFacet(facet);
4557
+ setPickerOpen(false);
4558
+ inputRef.current?.focus();
4559
+ },
4560
+ [selectFacet]
4561
+ );
4562
+ const { Widget: PendingWidget, options: pendingWidgetOptions } = resolveWidgetForFacet(pendingFacet, widgetRegistry);
4563
+ const keyDownCtx = {
4564
+ isFaceted,
4565
+ pendingFacet,
4566
+ pickerVisible,
4567
+ hasFacetsToShow,
4568
+ filteredFacets,
4569
+ highlightedIndex,
4570
+ inputValue,
4571
+ pickerNavigated,
4572
+ setPickerNavigated,
4573
+ setPickerOpen,
4574
+ setHighlightedIndex,
4575
+ acceptFacet,
4576
+ handleKeyDown
4577
+ };
4578
+ return /* @__PURE__ */ jsxs13(
4579
+ "div",
4580
+ {
4581
+ ref: containerRef,
4582
+ className: cn30(
4583
+ "flex flex-wrap items-center gap-1.5 rounded-md border border-input bg-background px-2 py-1.5 text-sm min-h-9",
4584
+ disabled ? "opacity-50 cursor-not-allowed" : "cursor-text",
4585
+ className
4586
+ ),
4587
+ onClick: () => !disabled && inputRef.current?.focus(),
4588
+ onBlur: (e) => {
4589
+ const relatedTarget = e.relatedTarget;
4590
+ if (relatedTarget && !e.currentTarget.contains(relatedTarget)) {
4591
+ setPickerOpen(false);
4592
+ }
4593
+ },
4594
+ children: [
4595
+ /* @__PURE__ */ jsx33(Search2, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
4596
+ isFaceted && /* @__PURE__ */ jsx33(
4597
+ ActiveChips,
4598
+ {
4599
+ terms: activeTerms,
4600
+ schema,
4601
+ onRemove: handleRemoveTerm
4602
+ }
4603
+ ),
4604
+ pendingFacet && /* @__PURE__ */ jsxs13("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground", children: [
4605
+ pendingFacet.label,
4606
+ ":"
4607
+ ] }),
4608
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1 flex-1 min-w-[120px]", children: [
4609
+ showFacetControls && /* @__PURE__ */ jsx33(
4610
+ FacetPicker,
4611
+ {
4612
+ pickerVisible,
4613
+ hasFacetsToShow,
4614
+ filteredFacets,
4615
+ highlightedIndex,
4616
+ setPickerOpen,
4617
+ setHighlightedIndex,
4618
+ acceptFacet,
4619
+ inputRef
4620
+ }
4621
+ ),
4622
+ /* @__PURE__ */ jsx33(
4623
+ ValueEntry,
4624
+ {
4625
+ pendingFacet,
4626
+ PendingWidget,
4627
+ pendingWidgetOptions,
4628
+ inputValue,
4629
+ handleInputChange,
4630
+ commitFacetValue,
4631
+ cancelPendingFacet,
4632
+ resolvedPlaceholder,
4633
+ disabled,
4634
+ inputRef,
4635
+ onInputKeyDown: (e) => handleInputKeyDown(e, keyDownCtx),
4636
+ onInputChange: (e) => {
4637
+ handleInputChange(e);
4638
+ setPickerNavigated(false);
4639
+ },
4640
+ onInputFocus: () => {
4641
+ if (isFaceted && !pendingFacet) setPickerNavigated(false);
4642
+ }
4643
+ }
4644
+ )
4645
+ ] }),
4646
+ /* @__PURE__ */ jsx33(
4647
+ SearchActions,
4648
+ {
4649
+ isEmpty,
4650
+ showSearchButton,
4651
+ mode,
4652
+ onClear: handleClear,
4653
+ onCommit: handleCommit
4654
+ }
4655
+ )
4656
+ ]
4657
+ }
4658
+ );
4659
+ }
4660
+ function FilterChip({ label, onRemove }) {
4661
+ return /* @__PURE__ */ jsxs13(
4662
+ Badge,
4663
+ {
4664
+ variant: "secondary",
4665
+ className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium rounded-full",
4666
+ children: [
4667
+ label,
4668
+ /* @__PURE__ */ jsx33(
4669
+ "button",
4670
+ {
4671
+ type: "button",
4672
+ onClick: (e) => {
4673
+ e.stopPropagation();
4674
+ onRemove();
4675
+ },
4676
+ className: "ml-0.5 hover:text-destructive transition-colors",
4677
+ "aria-label": `Remove filter ${label}`,
4678
+ children: /* @__PURE__ */ jsx33(X3, { className: "h-3 w-3" })
4679
+ }
4680
+ )
4681
+ ]
4682
+ }
4683
+ );
4684
+ }
4685
+
4686
+ // src/Clipboard/ClipboardButton.tsx
4687
+ import { Copy } from "lucide-react";
4688
+ import { jsx as jsx34 } from "react/jsx-runtime";
4689
+ function ClipboardButton({ hasItems, onClick }) {
4690
+ return /* @__PURE__ */ jsx34(
4691
+ Button,
4692
+ {
4693
+ variant: "ghost",
4694
+ size: "icon",
4695
+ onClick,
4696
+ disabled: !hasItems,
4697
+ style: {
4698
+ opacity: hasItems ? 1 : 0.4,
4699
+ cursor: hasItems ? "pointer" : "not-allowed"
4700
+ },
4701
+ children: /* @__PURE__ */ jsx34(Copy, { size: 16 })
4702
+ }
4703
+ );
4704
+ }
4705
+ var ClipboardButton_default = ClipboardButton;
4706
+
4707
+ // src/Clipboard/ClipboardItem.tsx
4708
+ import { X as X4, Plus } from "lucide-react";
4709
+ import { jsx as jsx35, jsxs as jsxs14 } from "react/jsx-runtime";
4710
+ function ClipboardItemComponent({ item, onAddItem, onRemove }) {
4711
+ const handleAddClick = (e) => {
4712
+ const keepInClipboard = e.shiftKey;
4713
+ onAddItem(item, keepInClipboard);
4714
+ };
4715
+ return /* @__PURE__ */ jsx35(
4716
+ "div",
4717
+ {
4718
+ className: "p-3 rounded mb-2",
4719
+ style: {
4720
+ borderLeft: `4px solid ${item.color}`,
4721
+ backgroundColor: "#f8f9fa"
4722
+ },
4723
+ children: /* @__PURE__ */ jsxs14(SimpleGroup, { justify: "space-between", wrap: "nowrap", align: "flex-start", children: [
4724
+ /* @__PURE__ */ jsxs14("div", { className: "flex-1 min-w-0 overflow-hidden", children: [
4725
+ /* @__PURE__ */ jsx35("p", { className: "text-sm font-semibold truncate", children: item.label }),
4726
+ /* @__PURE__ */ jsx35("p", { className: "text-xs text-muted-foreground truncate", children: item.displayName }),
4727
+ /* @__PURE__ */ jsxs14("p", { className: "text-xs text-muted-foreground font-mono", children: [
4728
+ "#",
4729
+ item.entityId
4730
+ ] })
4731
+ ] }),
4732
+ /* @__PURE__ */ jsxs14(SimpleGroup, { gap: 4, wrap: "nowrap", style: { flexShrink: 0 }, children: [
4733
+ /* @__PURE__ */ jsxs14(
4734
+ Button,
4735
+ {
4736
+ size: "sm",
4737
+ variant: "secondary",
4738
+ onClick: handleAddClick,
4739
+ title: "Click to add and remove from clipboard, Shift+Click to keep in clipboard",
4740
+ children: [
4741
+ /* @__PURE__ */ jsx35(Plus, { size: 16 }),
4742
+ "Add"
4743
+ ]
4744
+ }
4745
+ ),
4746
+ /* @__PURE__ */ jsx35(
4747
+ Button,
4748
+ {
4749
+ size: "sm",
4750
+ variant: "ghost",
4751
+ onClick: () => onRemove(item.id),
4752
+ title: "Remove from clipboard",
4753
+ children: /* @__PURE__ */ jsx35(X4, { size: 16 })
4754
+ }
4755
+ )
4756
+ ] })
4757
+ ] })
4758
+ }
4759
+ );
4760
+ }
4761
+ var ClipboardItem_default = ClipboardItemComponent;
4762
+
4763
+ // src/Clipboard/ClipboardMenu.tsx
4764
+ import { Trash2 } from "lucide-react";
4765
+
4766
+ // src/Clipboard/clipboardStore.ts
4767
+ import { create } from "zustand";
4768
+ import { persist } from "zustand/middleware";
4769
+ import { devLog } from "@petrarca/sonnet-core";
4770
+ function getItemKey(item) {
4771
+ return `${item.type}:${item.entityId}:${item.label}`;
4772
+ }
4773
+ function getInputKey(input) {
4774
+ return `${input.type}:${input.entityId}:${input.label}`;
4775
+ }
4776
+ function uuid() {
4777
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
4778
+ const r = Math.random() * 16 | 0;
4779
+ const v = c === "x" ? r : r & 3 | 8;
4780
+ return v.toString(16);
4781
+ });
4782
+ }
4783
+ var MAX_CLIPBOARD_SIZE = 100;
4784
+ var useClipboard = create()(
4785
+ persist(
4786
+ (set, get) => ({
4787
+ items: [],
4788
+ addItems: (inputs) => {
4789
+ const currentItems = get().items;
4790
+ const existingKeys = new Set(currentItems.map(getItemKey));
4791
+ const newItems = inputs.map(
4792
+ (input) => ({
4793
+ id: uuid(),
4794
+ type: input.type,
4795
+ entityId: input.entityId,
4796
+ label: input.label,
4797
+ displayName: input.displayName,
4798
+ color: input.color
4799
+ })
4800
+ ).filter((item) => !existingKeys.has(getInputKey(item)));
4801
+ if (newItems.length === 0) {
4802
+ devLog(
4803
+ "[ClipboardStore] addItems - all items were duplicates, skipped"
4804
+ );
4805
+ return;
4806
+ }
4807
+ let updatedItems = [...currentItems, ...newItems];
4808
+ if (updatedItems.length > MAX_CLIPBOARD_SIZE) {
4809
+ const overflow = updatedItems.length - MAX_CLIPBOARD_SIZE;
4810
+ updatedItems = updatedItems.slice(overflow);
4811
+ devLog(
4812
+ "[ClipboardStore] addItems - size limit exceeded, removed oldest",
4813
+ { overflow }
4814
+ );
4815
+ }
4816
+ devLog("[ClipboardStore] addItems", {
4817
+ added: newItems.length,
4818
+ total: updatedItems.length,
4819
+ skippedDuplicates: inputs.length - newItems.length
4820
+ });
4821
+ set({ items: updatedItems });
4822
+ },
4823
+ removeItem: (itemId) => {
4824
+ const currentItems = get().items;
4825
+ const updatedItems = currentItems.filter((item) => item.id !== itemId);
4826
+ if (updatedItems.length === currentItems.length) {
4827
+ devLog("[ClipboardStore] removeItem - item not found", { itemId });
4828
+ return;
4829
+ }
4830
+ devLog("[ClipboardStore] removeItem", {
4831
+ itemId,
4832
+ remainingCount: updatedItems.length
4833
+ });
4834
+ set({ items: updatedItems });
4835
+ },
4836
+ clear: () => {
4837
+ const currentCount = get().items.length;
4838
+ devLog("[ClipboardStore] clear", { clearedCount: currentCount });
4839
+ set({ items: [] });
4840
+ }
4841
+ }),
4842
+ {
4843
+ name: "clipboard-items",
4844
+ version: 2
4845
+ }
4846
+ )
4847
+ );
4848
+ var clipboardStore_default = useClipboard;
4849
+
4850
+ // src/Clipboard/ClipboardMenu.tsx
4851
+ import { jsx as jsx36, jsxs as jsxs15 } from "react/jsx-runtime";
4852
+ function ClipboardMenu({ onAddItem }) {
4853
+ const { items, removeItem, clear } = clipboardStore_default();
4854
+ if (items.length === 0) {
4855
+ return /* @__PURE__ */ jsxs15("div", { style: { padding: "16px", textAlign: "center", width: "300px" }, children: [
4856
+ /* @__PURE__ */ jsx36("p", { className: "text-sm text-muted-foreground", children: "No items in clipboard" }),
4857
+ /* @__PURE__ */ jsx36("p", { className: "text-xs text-muted-foreground mt-1", children: 'Right-click a node and select "Copy"' })
4858
+ ] });
4859
+ }
4860
+ return /* @__PURE__ */ jsxs15(
4861
+ "div",
4862
+ {
4863
+ style: {
4864
+ width: "380px",
4865
+ maxWidth: "90vw",
4866
+ display: "flex",
4867
+ flexDirection: "column",
4868
+ maxHeight: "500px"
4869
+ },
4870
+ children: [
4871
+ /* @__PURE__ */ jsx36(ScrollArea, { className: "flex-1 p-3 min-h-0", children: /* @__PURE__ */ jsx36(SimpleStack, { gap: 0, children: items.map((item) => /* @__PURE__ */ jsx36(
4872
+ ClipboardItem_default,
4873
+ {
4874
+ item,
4875
+ onAddItem,
4876
+ onRemove: removeItem
4877
+ },
4878
+ item.id
4879
+ )) }) }),
4880
+ /* @__PURE__ */ jsx36(Separator2, {}),
4881
+ /* @__PURE__ */ jsx36("div", { style: { padding: "8px 12px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs15(
4882
+ Button,
4883
+ {
4884
+ className: "w-full",
4885
+ variant: "destructive",
4886
+ size: "sm",
4887
+ onClick: clear,
4888
+ children: [
4889
+ /* @__PURE__ */ jsx36(Trash2, { size: 16 }),
4890
+ "Clear All (",
4891
+ items.length,
4892
+ ")"
4893
+ ]
4894
+ }
4895
+ ) })
4896
+ ]
4897
+ }
4898
+ );
4899
+ }
4900
+ var ClipboardMenu_default = ClipboardMenu;
4901
+ export {
4902
+ Alert,
4903
+ AlertDescription,
4904
+ AlertTitle,
4905
+ Avatar,
4906
+ AvatarFallback,
4907
+ AvatarImage,
4908
+ Badge,
4909
+ Button,
4910
+ CELL_RENDERERS,
4911
+ Card,
4912
+ CardContent,
4913
+ CardDescription,
4914
+ CardFooter,
4915
+ CardHeader,
4916
+ CardTitle,
4917
+ Checkbox,
4918
+ ClipboardButton_default as ClipboardButton,
4919
+ ClipboardItem_default as ClipboardItem,
4920
+ ClipboardMenu_default as ClipboardMenu,
4921
+ Collapsible,
4922
+ CollapsibleContent2 as CollapsibleContent,
4923
+ CollapsibleTrigger2 as CollapsibleTrigger,
4924
+ Command,
4925
+ CommandDialog,
4926
+ CommandEmpty,
4927
+ CommandGroup,
4928
+ CommandInput,
4929
+ CommandItem,
4930
+ CommandList,
4931
+ CommandSeparator,
4932
+ CommandShortcut,
4933
+ Dialog,
4934
+ DialogClose,
4935
+ DialogContent,
4936
+ DialogDescription,
4937
+ DialogFooter,
4938
+ DialogHeader,
4939
+ DialogOverlay,
4940
+ DialogPortal,
4941
+ DialogTitle,
4942
+ DialogTrigger,
4943
+ DropdownMenu,
4944
+ DropdownMenuCheckboxItem,
4945
+ DropdownMenuContent,
4946
+ DropdownMenuGroup,
4947
+ DropdownMenuItem,
4948
+ DropdownMenuLabel,
4949
+ DropdownMenuPortal,
4950
+ DropdownMenuRadioGroup,
4951
+ DropdownMenuRadioItem,
4952
+ DropdownMenuSeparator,
4953
+ DropdownMenuShortcut,
4954
+ DropdownMenuSub,
4955
+ DropdownMenuSubContent,
4956
+ DropdownMenuSubTrigger,
4957
+ DropdownMenuTrigger,
4958
+ EntitySelect,
4959
+ EntityTable,
4960
+ EntityTree,
4961
+ Input,
4962
+ InputGroup,
4963
+ InputGroupAddon,
4964
+ InputGroupInput,
4965
+ InputGroupText,
4966
+ InputGroupTextarea,
4967
+ Label2 as Label,
4968
+ Popover,
4969
+ PopoverContent,
4970
+ PopoverTrigger,
4971
+ ScrollArea,
4972
+ ScrollBar,
4973
+ SearchInput,
4974
+ Separator2 as Separator,
4975
+ Sheet,
4976
+ SheetBody,
4977
+ SheetClose,
4978
+ SheetContent,
4979
+ SheetDescription,
4980
+ SheetFooter,
4981
+ SheetHeader,
4982
+ SheetOverlay,
4983
+ SheetTitle,
4984
+ SheetTrigger,
4985
+ SimpleGroup,
4986
+ SimpleStack,
4987
+ SimpleTooltip,
4988
+ Skeleton,
4989
+ Spinner,
4990
+ Stepper,
4991
+ StepperContent,
4992
+ StepperDescription,
4993
+ StepperIndicator,
4994
+ StepperItem,
4995
+ StepperList,
4996
+ StepperNext,
4997
+ StepperPrev,
4998
+ StepperSeparator,
4999
+ StepperTitle,
5000
+ StepperTrigger,
5001
+ Tabs,
5002
+ TabsContent,
5003
+ TabsList,
5004
+ TabsTrigger,
5005
+ Textarea,
5006
+ Tooltip,
5007
+ TooltipContent,
5008
+ TooltipProvider,
5009
+ TooltipTrigger,
5010
+ TreeView,
5011
+ badgeVariants,
5012
+ buttonVariants,
5013
+ createRenderer,
5014
+ useStore as useStepper
5015
+ };
5016
+ //# sourceMappingURL=index.js.map