@yca-software/yca-react-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +129 -0
  2. package/dist/admin/index.d.ts +10 -0
  3. package/dist/admin/index.js +3 -0
  4. package/dist/admin/index.js.map +1 -0
  5. package/dist/admin-BVYdWtEy.d.ts +3 -0
  6. package/dist/api/index.d.ts +68 -0
  7. package/dist/api/index.js +3 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/auth/index.d.ts +49 -0
  10. package/dist/auth/index.js +3 -0
  11. package/dist/auth/index.js.map +1 -0
  12. package/dist/chunk-2HJO2ICF.js +339 -0
  13. package/dist/chunk-2HJO2ICF.js.map +1 -0
  14. package/dist/chunk-3AYG73DK.js +174 -0
  15. package/dist/chunk-3AYG73DK.js.map +1 -0
  16. package/dist/chunk-3SCZ4Z6P.js +26 -0
  17. package/dist/chunk-3SCZ4Z6P.js.map +1 -0
  18. package/dist/chunk-3ZLODBRJ.js +21 -0
  19. package/dist/chunk-3ZLODBRJ.js.map +1 -0
  20. package/dist/chunk-6LO5O4G6.js +224 -0
  21. package/dist/chunk-6LO5O4G6.js.map +1 -0
  22. package/dist/chunk-APZVW5SW.js +75 -0
  23. package/dist/chunk-APZVW5SW.js.map +1 -0
  24. package/dist/chunk-EVZBADFR.js +583 -0
  25. package/dist/chunk-EVZBADFR.js.map +1 -0
  26. package/dist/chunk-GXWVFQCK.js +52 -0
  27. package/dist/chunk-GXWVFQCK.js.map +1 -0
  28. package/dist/chunk-KG4JVAKS.js +13 -0
  29. package/dist/chunk-KG4JVAKS.js.map +1 -0
  30. package/dist/chunk-KZH56VPP.js +183 -0
  31. package/dist/chunk-KZH56VPP.js.map +1 -0
  32. package/dist/chunk-LP7Q75C6.js +96 -0
  33. package/dist/chunk-LP7Q75C6.js.map +1 -0
  34. package/dist/chunk-NL4NAHXG.js +3 -0
  35. package/dist/chunk-NL4NAHXG.js.map +1 -0
  36. package/dist/chunk-PLSNCPEC.js +2507 -0
  37. package/dist/chunk-PLSNCPEC.js.map +1 -0
  38. package/dist/chunk-QFKVPVFC.js +1391 -0
  39. package/dist/chunk-QFKVPVFC.js.map +1 -0
  40. package/dist/chunk-TSXUUD64.js +64 -0
  41. package/dist/chunk-TSXUUD64.js.map +1 -0
  42. package/dist/chunk-UCJ76BEC.js +32 -0
  43. package/dist/chunk-UCJ76BEC.js.map +1 -0
  44. package/dist/chunk-WFTIYYII.js +3 -0
  45. package/dist/chunk-WFTIYYII.js.map +1 -0
  46. package/dist/components/forms/index.d.ts +101 -0
  47. package/dist/components/forms/index.js +7 -0
  48. package/dist/components/forms/index.js.map +1 -0
  49. package/dist/components/marketing/index.d.ts +473 -0
  50. package/dist/components/marketing/index.js +5 -0
  51. package/dist/components/marketing/index.js.map +1 -0
  52. package/dist/components/spa/index.d.ts +275 -0
  53. package/dist/components/spa/index.js +8 -0
  54. package/dist/components/spa/index.js.map +1 -0
  55. package/dist/components/ui/index.d.ts +420 -0
  56. package/dist/components/ui/index.js +6 -0
  57. package/dist/components/ui/index.js.map +1 -0
  58. package/dist/constants/index.d.ts +2 -0
  59. package/dist/constants/index.js +4 -0
  60. package/dist/constants/index.js.map +1 -0
  61. package/dist/cookies-ZS_QYOR7.d.ts +8 -0
  62. package/dist/dateRangePickerTranslations-B99F2WQA.d.ts +9 -0
  63. package/dist/errors/index.d.ts +48 -0
  64. package/dist/errors/index.js +3 -0
  65. package/dist/errors/index.js.map +1 -0
  66. package/dist/forms-VpLvEFob.d.ts +18 -0
  67. package/dist/hooks/index.d.ts +18 -0
  68. package/dist/hooks/index.js +4 -0
  69. package/dist/hooks/index.js.map +1 -0
  70. package/dist/index.d.ts +42 -0
  71. package/dist/index.js +19 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/lib/index.d.ts +49 -0
  74. package/dist/lib/index.js +7 -0
  75. package/dist/lib/index.js.map +1 -0
  76. package/dist/pagination-CFqoqiAG.d.ts +10 -0
  77. package/dist/radix-overlays-BlCr-uem.d.ts +10 -0
  78. package/dist/styles.css +9 -0
  79. package/dist/theme/marketing.css +750 -0
  80. package/dist/theme/tokens.css +115 -0
  81. package/dist/types/index.d.ts +2 -0
  82. package/dist/types/index.js +3 -0
  83. package/dist/types/index.js.map +1 -0
  84. package/dist/types-BuNHOJ1h.d.ts +58 -0
  85. package/dist/types-CN73TWSY.d.ts +51 -0
  86. package/dist/useAdminListPage-C4ZTTllP.d.ts +26 -0
  87. package/package.json +152 -0
@@ -0,0 +1,2507 @@
1
+ import { buttonVariants, Input, Button } from './chunk-3AYG73DK.js';
2
+ import { normalizeDate, DISPLAY_FORMAT, preventDismissOnPortaledOverlay, INPUT_FORMAT, INPUT_FORMAT_ALT } from './chunk-TSXUUD64.js';
3
+ import { cn, surfaceOverlay, controlFocus, controlInvalid, controlBase, surfaceCard } from './chunk-GXWVFQCK.js';
4
+ import { cva } from 'class-variance-authority';
5
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
+ import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
7
+ import * as React6 from 'react';
8
+ import { useRef, useId, useState, useEffect } from 'react';
9
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
10
+ import { Check, ChevronLeft, ChevronRight, Loader2, Calendar as Calendar$1, XIcon, ChevronUp, ChevronDown, X, CheckSquare, FileText, ImagePlus, UploadCloud } from 'lucide-react';
11
+ import { DayPicker } from 'react-day-picker';
12
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
13
+ import { format, parse } from 'date-fns';
14
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
15
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
16
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
17
+ import { Slot } from '@radix-ui/react-slot';
18
+ import { FormProvider, Controller, useFormContext, useFormState } from 'react-hook-form';
19
+ import * as LabelPrimitive from '@radix-ui/react-label';
20
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
21
+ import * as SeparatorPrimitive from '@radix-ui/react-separator';
22
+ import * as SwitchPrimitive from '@radix-ui/react-switch';
23
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
24
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
25
+
26
+ var alertVariants = cva(
27
+ "relative w-full rounded-xl border border-border/45 px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start shadow-[var(--shadow-surface)] [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
28
+ {
29
+ variants: {
30
+ variant: {
31
+ default: "bg-card text-card-foreground *:data-[slot=alert-description]:text-muted-foreground",
32
+ destructive: "bg-destructive/90 dark:bg-destructive text-destructive-foreground border-destructive/50 dark:border-destructive/70 [&>svg]:text-destructive-foreground *:data-[slot=alert-description]:text-destructive-foreground"
33
+ }
34
+ },
35
+ defaultVariants: {
36
+ variant: "default"
37
+ }
38
+ }
39
+ );
40
+ function Alert({
41
+ className,
42
+ variant,
43
+ ...props
44
+ }) {
45
+ return /* @__PURE__ */ jsx(
46
+ "div",
47
+ {
48
+ "data-slot": "alert",
49
+ role: "alert",
50
+ className: cn(alertVariants({ variant }), className),
51
+ ...props
52
+ }
53
+ );
54
+ }
55
+ function AlertDescription({ className, ...props }) {
56
+ return /* @__PURE__ */ jsx(
57
+ "div",
58
+ {
59
+ "data-slot": "alert-description",
60
+ className: cn(
61
+ "col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
62
+ className
63
+ ),
64
+ ...props
65
+ }
66
+ );
67
+ }
68
+ var AlertDialog = AlertDialogPrimitive.Root;
69
+ var AlertDialogTrigger = AlertDialogPrimitive.Trigger;
70
+ var AlertDialogPortal = AlertDialogPrimitive.Portal;
71
+ var AlertDialogOverlay = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
72
+ AlertDialogPrimitive.Overlay,
73
+ {
74
+ className: cn(
75
+ "fixed inset-0 z-110 bg-foreground/20 backdrop-blur-[2px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
76
+ className
77
+ ),
78
+ ...props,
79
+ ref
80
+ }
81
+ ));
82
+ AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
83
+ var AlertDialogContent = React6.forwardRef(({ className, onOverlayClick, overlayClassName, ...props }, ref) => /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [
84
+ /* @__PURE__ */ jsx(AlertDialogOverlay, { onClick: onOverlayClick, className: overlayClassName }),
85
+ /* @__PURE__ */ jsx(
86
+ AlertDialogPrimitive.Content,
87
+ {
88
+ ref,
89
+ className: cn(
90
+ surfaceOverlay,
91
+ "bg-background fixed left-[50%] top-[50%] z-110 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 p-6 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%]",
92
+ className
93
+ ),
94
+ ...props
95
+ }
96
+ )
97
+ ] }));
98
+ AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
99
+ var AlertDialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-2 text-center sm:text-left", className), ...props });
100
+ AlertDialogHeader.displayName = "AlertDialogHeader";
101
+ var AlertDialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx(
102
+ "div",
103
+ {
104
+ className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
105
+ ...props
106
+ }
107
+ );
108
+ AlertDialogFooter.displayName = "AlertDialogFooter";
109
+ var AlertDialogTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
110
+ AlertDialogPrimitive.Title,
111
+ {
112
+ ref,
113
+ className: cn("text-lg font-semibold", className),
114
+ ...props
115
+ }
116
+ ));
117
+ AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
118
+ var AlertDialogDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
119
+ AlertDialogPrimitive.Description,
120
+ {
121
+ ref,
122
+ className: cn("text-sm text-muted-foreground", className),
123
+ ...props
124
+ }
125
+ ));
126
+ AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
127
+ var AlertDialogAction = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
128
+ AlertDialogPrimitive.Action,
129
+ {
130
+ ref,
131
+ "data-slot": "alert-dialog-action",
132
+ className: cn(buttonVariants(), className),
133
+ ...props
134
+ }
135
+ ));
136
+ AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
137
+ var AlertDialogCancel = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
138
+ AlertDialogPrimitive.Cancel,
139
+ {
140
+ ref,
141
+ "data-slot": "alert-dialog-cancel",
142
+ className: cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className),
143
+ ...props
144
+ }
145
+ ));
146
+ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
147
+ var Avatar = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
148
+ AvatarPrimitive.Root,
149
+ {
150
+ ref,
151
+ className: cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className),
152
+ ...props
153
+ }
154
+ ));
155
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
156
+ var AvatarImage = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
157
+ AvatarPrimitive.Image,
158
+ {
159
+ ref,
160
+ className: cn("aspect-square h-full w-full", className),
161
+ ...props
162
+ }
163
+ ));
164
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
165
+ var AvatarFallback = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
166
+ AvatarPrimitive.Fallback,
167
+ {
168
+ ref,
169
+ className: cn(
170
+ "flex h-full w-full items-center justify-center rounded-full bg-muted",
171
+ className
172
+ ),
173
+ ...props
174
+ }
175
+ ));
176
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
177
+ var badgeVariants = cva(
178
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold whitespace-nowrap transition-colors",
179
+ {
180
+ variants: {
181
+ variant: {
182
+ default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
183
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
184
+ destructive: "border-transparent bg-destructive text-white hover:bg-destructive/80",
185
+ outline: "border-border/50 text-foreground bg-background/80"
186
+ }
187
+ },
188
+ defaultVariants: {
189
+ variant: "default"
190
+ }
191
+ }
192
+ );
193
+ function Badge({
194
+ className,
195
+ variant,
196
+ ...props
197
+ }) {
198
+ return /* @__PURE__ */ jsx("span", { "data-slot": "badge", className: cn(badgeVariants({ variant }), className), ...props });
199
+ }
200
+ function Calendar({
201
+ className,
202
+ classNames,
203
+ showOutsideDays = true,
204
+ weekStartsOn,
205
+ ...props
206
+ }) {
207
+ return /* @__PURE__ */ jsx(
208
+ DayPicker,
209
+ {
210
+ "data-slot": "calendar",
211
+ showOutsideDays,
212
+ weekStartsOn: weekStartsOn ?? 1,
213
+ navLayout: "around",
214
+ className: cn("p-3", className),
215
+ classNames: {
216
+ months: "flex flex-col items-stretch justify-center gap-4 sm:flex-row sm:items-start sm:gap-6",
217
+ month: "relative min-w-0 space-y-3",
218
+ month_caption: "flex items-center justify-center w-full h-9 pt-1 px-10",
219
+ caption_label: "text-sm font-medium text-center pointer-events-none",
220
+ nav: "contents",
221
+ button_previous: cn(
222
+ buttonVariants({ variant: "outline", size: "icon-sm" }),
223
+ "absolute left-0 top-1 z-10 h-8 w-8 bg-transparent p-0 opacity-70 hover:opacity-100"
224
+ ),
225
+ button_next: cn(
226
+ buttonVariants({ variant: "outline", size: "icon-sm" }),
227
+ "absolute right-0 top-1 z-10 h-8 w-8 bg-transparent p-0 opacity-70 hover:opacity-100"
228
+ ),
229
+ month_grid: "w-full border-collapse",
230
+ weekdays: "",
231
+ weekday: "text-muted-foreground w-10 rounded-md font-normal text-[0.75rem] text-center p-1",
232
+ weeks: "mt-1",
233
+ week: "",
234
+ day: "relative h-10 w-10 text-center text-sm p-0 align-top focus-within:relative focus-within:z-20",
235
+ day_button: cn(
236
+ "day-button inline-flex size-10 items-center justify-center rounded-md text-sm font-normal transition-colors cursor-pointer",
237
+ "hover:bg-accent hover:text-accent-foreground",
238
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
239
+ "aria-disabled:text-muted-foreground/60 aria-disabled:opacity-50 aria-disabled:cursor-not-allowed"
240
+ ),
241
+ selected: "bg-primary/10 text-primary [&_.day-button]:bg-primary [&_.day-button]:text-primary-foreground",
242
+ today: "text-primary [&_.day-button]:border [&_.day-button]:border-primary [&_.day-button]:rounded-md [&.selected]:bg-primary [&.selected]:text-primary-foreground",
243
+ outside: "text-muted-foreground/60 [&.selected]:bg-accent/40 [&.selected]:text-accent-foreground",
244
+ range_middle: "bg-primary/15 text-foreground [&_.day-button]:bg-primary/15 [&_.day-button]:text-foreground [&_.day-button]:rounded-none",
245
+ range_end: "rounded-r-md text-primary-foreground [&_.day-button]:bg-primary [&_.day-button]:text-primary-foreground [&_.day-button]:rounded-r-md [&_.day-button]:rounded-l-none [&.range_start_.day-button]:!rounded-md",
246
+ range_start: "rounded-l-md text-primary-foreground [&_.day-button]:bg-primary [&_.day-button]:text-primary-foreground [&_.day-button]:rounded-l-md [&_.day-button]:rounded-r-none [&.range_end_.day-button]:!rounded-md",
247
+ disabled: "text-muted-foreground/60 opacity-50 [&_.day-button]:cursor-not-allowed",
248
+ ...classNames
249
+ },
250
+ components: {
251
+ Chevron: ({ orientation }) => orientation === "left" ? /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-4", "aria-hidden": true })
252
+ },
253
+ ...props
254
+ }
255
+ );
256
+ }
257
+ var Checkbox = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
258
+ CheckboxPrimitive.Root,
259
+ {
260
+ ref,
261
+ "data-slot": "checkbox",
262
+ className: cn(
263
+ "peer size-4 shrink-0 rounded-[5px] border border-border/55 bg-muted/30 shadow-[var(--shadow-surface)] transition-colors",
264
+ controlFocus,
265
+ controlInvalid,
266
+ "cursor-pointer disabled:cursor-not-allowed disabled:opacity-50",
267
+ "data-[state=checked]:bg-primary data-[state=checked]:border-primary data-[state=checked]:text-primary-foreground",
268
+ "data-[state=indeterminate]:bg-primary data-[state=indeterminate]:border-primary data-[state=indeterminate]:text-primary-foreground",
269
+ className
270
+ ),
271
+ ...props,
272
+ children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: /* @__PURE__ */ jsx(Check, { className: "size-2.5", strokeWidth: 3 }) })
273
+ }
274
+ ));
275
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
276
+ function ConfirmDialog({
277
+ open,
278
+ onOpenChange,
279
+ title,
280
+ description,
281
+ descriptionNote,
282
+ cancelLabel = "Cancel",
283
+ confirmLabel,
284
+ variant = "default",
285
+ onConfirm,
286
+ isPending = false,
287
+ confirmAriaLabel,
288
+ className,
289
+ closeOnOutsideClick = false
290
+ }) {
291
+ const confirmRef = useRef(null);
292
+ const isDestructive = variant === "destructive";
293
+ const confirmClassName = isDestructive ? "bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/20" : void 0;
294
+ const handleConfirm = () => {
295
+ if (isPending) return;
296
+ onConfirm();
297
+ };
298
+ return /* @__PURE__ */ jsx(AlertDialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
299
+ AlertDialogContent,
300
+ {
301
+ "data-slot": "confirm-dialog-content",
302
+ className: cn("gap-4 sm:gap-6", className),
303
+ onOpenAutoFocus: (event) => {
304
+ event.preventDefault();
305
+ confirmRef.current?.focus();
306
+ },
307
+ onKeyDown: (event) => {
308
+ if (event.key !== "Enter" || isPending) return;
309
+ const target = event.target;
310
+ if (target.closest('[data-slot="alert-dialog-cancel"]')) return;
311
+ if (target.closest('[data-slot="alert-dialog-action"]')) return;
312
+ event.preventDefault();
313
+ handleConfirm();
314
+ },
315
+ ...closeOnOutsideClick && {
316
+ onOverlayClick: () => onOpenChange(false)
317
+ },
318
+ children: [
319
+ /* @__PURE__ */ jsxs(AlertDialogHeader, { className: "gap-2", children: [
320
+ /* @__PURE__ */ jsx(AlertDialogTitle, { className: "text-base sm:text-lg", children: title }),
321
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
322
+ /* @__PURE__ */ jsx(AlertDialogDescription, { className: "text-sm", children: description }),
323
+ descriptionNote && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: descriptionNote })
324
+ ] })
325
+ ] }),
326
+ /* @__PURE__ */ jsxs(AlertDialogFooter, { className: "flex flex-col-reverse gap-2 pt-2 sm:flex-row sm:justify-end sm:gap-2 sm:pt-0", children: [
327
+ /* @__PURE__ */ jsx(
328
+ AlertDialogCancel,
329
+ {
330
+ onClick: () => onOpenChange(false),
331
+ disabled: isPending,
332
+ className: "m-0 w-full sm:w-auto",
333
+ children: cancelLabel
334
+ }
335
+ ),
336
+ /* @__PURE__ */ jsxs(
337
+ AlertDialogAction,
338
+ {
339
+ ref: confirmRef,
340
+ onClick: handleConfirm,
341
+ disabled: isPending,
342
+ "aria-label": confirmAriaLabel ?? confirmLabel,
343
+ className: cn("m-0 w-full sm:w-auto", confirmClassName),
344
+ children: [
345
+ isPending && /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin", "aria-hidden": true }),
346
+ confirmLabel
347
+ ]
348
+ }
349
+ )
350
+ ] })
351
+ ]
352
+ }
353
+ ) });
354
+ }
355
+ function Popover({ ...props }) {
356
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
357
+ }
358
+ function PopoverTrigger({ ...props }) {
359
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
360
+ }
361
+ function PopoverContent({
362
+ className,
363
+ align = "start",
364
+ sideOffset = 4,
365
+ ...props
366
+ }) {
367
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
368
+ PopoverPrimitive.Content,
369
+ {
370
+ "data-slot": "popover-content",
371
+ align,
372
+ sideOffset,
373
+ className: cn(
374
+ surfaceOverlay,
375
+ "z-110 w-auto min-w-48 p-3 outline-none",
376
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
377
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
378
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
379
+ "data-[side=bottom]:slide-in-from-top-2",
380
+ "data-[side=top]:slide-in-from-bottom-2",
381
+ "data-[side=left]:slide-in-from-right-2",
382
+ "data-[side=right]:slide-in-from-left-2",
383
+ className
384
+ ),
385
+ ...props
386
+ }
387
+ ) });
388
+ }
389
+ function DatePicker({
390
+ value,
391
+ onChange,
392
+ minDate,
393
+ maxDate,
394
+ placeholder = "Pick a date",
395
+ disabled = false,
396
+ locale,
397
+ className,
398
+ "aria-label": ariaLabel
399
+ }) {
400
+ const [open, setOpen] = React6.useState(false);
401
+ const normalizedMin = normalizeDate(minDate);
402
+ const normalizedMax = normalizeDate(maxDate);
403
+ const formatOpts = React6.useMemo(() => locale ? { locale } : void 0, [locale]);
404
+ const disabledMatchers = React6.useMemo(() => {
405
+ const toStartOfDay = (d) => {
406
+ const copy = new Date(d);
407
+ copy.setHours(0, 0, 0, 0);
408
+ return copy.getTime();
409
+ };
410
+ const matchers = [];
411
+ if (normalizedMin) {
412
+ matchers.push((date) => toStartOfDay(date) < toStartOfDay(normalizedMin));
413
+ }
414
+ if (normalizedMax) {
415
+ matchers.push((date) => toStartOfDay(date) > toStartOfDay(normalizedMax));
416
+ }
417
+ return matchers;
418
+ }, [normalizedMin, normalizedMax]);
419
+ const handleSelect = (date) => {
420
+ const day = date ? normalizeDate(date) : void 0;
421
+ onChange(day ?? void 0);
422
+ setOpen(false);
423
+ };
424
+ return /* @__PURE__ */ jsxs(Popover, { modal: false, open, onOpenChange: setOpen, children: [
425
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
426
+ "div",
427
+ {
428
+ role: "button",
429
+ tabIndex: disabled ? -1 : 0,
430
+ onKeyDown: (e) => {
431
+ if (!disabled && (e.key === "Enter" || e.key === " ")) {
432
+ e.preventDefault();
433
+ setOpen((o) => !o);
434
+ }
435
+ },
436
+ className: cn(
437
+ controlBase,
438
+ controlFocus,
439
+ "flex w-full cursor-pointer items-center overflow-hidden",
440
+ disabled && "pointer-events-none opacity-50",
441
+ className
442
+ ),
443
+ children: [
444
+ /* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 shrink-0 items-center justify-center border-r border-border/40 bg-muted/25 text-muted-foreground", children: /* @__PURE__ */ jsx(Calendar$1, { className: "size-4", "aria-hidden": true }) }),
445
+ /* @__PURE__ */ jsx(
446
+ Input,
447
+ {
448
+ type: "text",
449
+ readOnly: true,
450
+ value: value ? format(value, DISPLAY_FORMAT, formatOpts) : "",
451
+ placeholder,
452
+ onClick: () => !disabled && setOpen(true),
453
+ className: cn(
454
+ "h-9 min-w-0 flex-1 cursor-pointer rounded-l-none border-0 bg-transparent py-2 pl-3 pr-3 text-base shadow-none focus-visible:ring-0 md:text-sm capitalize",
455
+ !value && "text-muted-foreground"
456
+ ),
457
+ "aria-label": ariaLabel
458
+ }
459
+ )
460
+ ]
461
+ }
462
+ ) }),
463
+ /* @__PURE__ */ jsx(PopoverContent, { className: "w-auto p-0 z-[120]", align: "start", children: /* @__PURE__ */ jsx(
464
+ Calendar,
465
+ {
466
+ mode: "single",
467
+ selected: value,
468
+ onSelect: handleSelect,
469
+ disabled: (date) => disabledMatchers.some((m) => m(date)),
470
+ locale
471
+ }
472
+ ) })
473
+ ] });
474
+ }
475
+ function Dialog({ ...props }) {
476
+ return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
477
+ }
478
+ function DialogTrigger({ ...props }) {
479
+ return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
480
+ }
481
+ function DialogPortal({ ...props }) {
482
+ return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
483
+ }
484
+ function DialogClose({ ...props }) {
485
+ return /* @__PURE__ */ jsx(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
486
+ }
487
+ function DialogOverlay({
488
+ className,
489
+ ...props
490
+ }) {
491
+ return /* @__PURE__ */ jsx(
492
+ DialogPrimitive.Overlay,
493
+ {
494
+ "data-slot": "dialog-overlay",
495
+ className: cn(
496
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-110 bg-foreground/20 backdrop-blur-[2px]",
497
+ className
498
+ ),
499
+ ...props
500
+ }
501
+ );
502
+ }
503
+ function DialogContent({
504
+ className,
505
+ children,
506
+ showCloseButton = true,
507
+ overlayClassName,
508
+ onPointerDownOutside,
509
+ onInteractOutside,
510
+ onFocusOutside,
511
+ ...props
512
+ }) {
513
+ return /* @__PURE__ */ jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
514
+ /* @__PURE__ */ jsx(DialogOverlay, { className: overlayClassName }),
515
+ /* @__PURE__ */ jsxs(
516
+ DialogPrimitive.Content,
517
+ {
518
+ "data-slot": "dialog-content",
519
+ onPointerDownOutside: (event) => {
520
+ preventDismissOnPortaledOverlay(event);
521
+ if (!event.defaultPrevented) {
522
+ onPointerDownOutside?.(event);
523
+ }
524
+ },
525
+ onInteractOutside: (event) => {
526
+ preventDismissOnPortaledOverlay(event);
527
+ if (!event.defaultPrevented) {
528
+ onInteractOutside?.(event);
529
+ }
530
+ },
531
+ onFocusOutside: (event) => {
532
+ preventDismissOnPortaledOverlay(event);
533
+ if (!event.defaultPrevented) {
534
+ onFocusOutside?.(event);
535
+ }
536
+ },
537
+ className: cn(
538
+ surfaceOverlay,
539
+ "bg-background 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 fixed top-[50%] left-[50%] z-110 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 p-6 duration-200 outline-none sm:max-w-lg",
540
+ className
541
+ ),
542
+ ...props,
543
+ children: [
544
+ children,
545
+ showCloseButton && /* @__PURE__ */ jsxs(
546
+ DialogPrimitive.Close,
547
+ {
548
+ "data-slot": "dialog-close",
549
+ className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none cursor-pointer [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
550
+ children: [
551
+ /* @__PURE__ */ jsx(XIcon, {}),
552
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
553
+ ]
554
+ }
555
+ )
556
+ ]
557
+ }
558
+ )
559
+ ] });
560
+ }
561
+ function DialogHeader({ className, ...props }) {
562
+ return /* @__PURE__ */ jsx(
563
+ "div",
564
+ {
565
+ "data-slot": "dialog-header",
566
+ className: cn("flex w-full flex-col items-center gap-2 text-center", className),
567
+ ...props
568
+ }
569
+ );
570
+ }
571
+ function DialogFooter({ className, ...props }) {
572
+ return /* @__PURE__ */ jsx(
573
+ "div",
574
+ {
575
+ "data-slot": "dialog-footer",
576
+ className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
577
+ ...props
578
+ }
579
+ );
580
+ }
581
+ function DialogTitle({ className, ...props }) {
582
+ return /* @__PURE__ */ jsx(
583
+ DialogPrimitive.Title,
584
+ {
585
+ "data-slot": "dialog-title",
586
+ className: cn("w-full text-lg leading-none font-semibold text-center", className),
587
+ ...props
588
+ }
589
+ );
590
+ }
591
+ function DialogDescription({
592
+ className,
593
+ ...props
594
+ }) {
595
+ return /* @__PURE__ */ jsx(
596
+ DialogPrimitive.Description,
597
+ {
598
+ "data-slot": "dialog-description",
599
+ className: cn("w-full text-muted-foreground text-sm text-center", className),
600
+ ...props
601
+ }
602
+ );
603
+ }
604
+
605
+ // src/components/ui/date-range-picker/constants.ts
606
+ var DATE_RANGE_MOBILE_MAX_PX = 640;
607
+ var DATE_RANGE_MOBILE_MQ = `(max-width: ${DATE_RANGE_MOBILE_MAX_PX - 1}px)`;
608
+ var DATE_RANGE_WIDE_MIN_PX = 768;
609
+ var DATE_RANGE_WIDE_MQ = `(min-width: ${DATE_RANGE_WIDE_MIN_PX}px)`;
610
+ var DEFAULT_PRESET_IDS = [
611
+ { id: "today" },
612
+ { id: "yesterday" },
613
+ { id: "last7" },
614
+ { id: "last14" },
615
+ { id: "last30" },
616
+ { id: "thisWeek" },
617
+ { id: "lastWeek" },
618
+ { id: "thisMonth" },
619
+ { id: "lastMonth" }
620
+ ];
621
+ var DEFAULT_PRESET_LABELS = {
622
+ today: "Today",
623
+ yesterday: "Yesterday",
624
+ last7: "Last 7 days",
625
+ last14: "Last 14 days",
626
+ last30: "Last 30 days",
627
+ thisWeek: "This week",
628
+ lastWeek: "Last week",
629
+ thisMonth: "This month",
630
+ lastMonth: "Last month"
631
+ };
632
+ var DEFAULT_TRANSLATIONS = {
633
+ applyButton: "Apply",
634
+ cancelButton: "Cancel",
635
+ startLabel: "Start",
636
+ endLabel: "End",
637
+ placeholder: "YYYY/MM/DD",
638
+ ariaLabel: "Date range",
639
+ presetLabels: DEFAULT_PRESET_LABELS,
640
+ presetsHeading: "Quick ranges"
641
+ };
642
+ function DateRangePickerActionFooter({
643
+ visible,
644
+ isMobileLayout,
645
+ cancelLabel,
646
+ applyLabel,
647
+ onCancel,
648
+ onApply,
649
+ className
650
+ }) {
651
+ if (!visible) return null;
652
+ return /* @__PURE__ */ jsxs(
653
+ "div",
654
+ {
655
+ className: cn(
656
+ "flex w-full items-center justify-end gap-2 border-t border-border/50 bg-muted/15 px-4 py-3",
657
+ isMobileLayout && "mt-auto shrink-0 bg-background pb-[max(1rem,env(safe-area-inset-bottom))] pt-4",
658
+ className
659
+ ),
660
+ children: [
661
+ /* @__PURE__ */ jsx(
662
+ Button,
663
+ {
664
+ type: "button",
665
+ variant: "ghost",
666
+ size: "sm",
667
+ className: cn(isMobileLayout && "min-h-10 flex-1 sm:min-h-9 sm:flex-initial"),
668
+ onClick: onCancel,
669
+ children: cancelLabel
670
+ }
671
+ ),
672
+ /* @__PURE__ */ jsx(
673
+ Button,
674
+ {
675
+ type: "button",
676
+ size: "sm",
677
+ className: cn(isMobileLayout && "min-h-10 flex-1 sm:min-h-9 sm:flex-initial"),
678
+ onClick: onApply,
679
+ children: applyLabel
680
+ }
681
+ )
682
+ ]
683
+ }
684
+ );
685
+ }
686
+ function DateRangePickerFieldsCalendar({
687
+ calendarMonths,
688
+ draft,
689
+ displayedMonth,
690
+ onMonthChange,
691
+ onSelect,
692
+ disabledMatchers,
693
+ locale,
694
+ startInputId,
695
+ endInputId,
696
+ startLabel,
697
+ endLabel,
698
+ startInputText,
699
+ endInputText,
700
+ effectivePlaceholder,
701
+ onStartInputChange,
702
+ onEndInputChange,
703
+ onCommitStart,
704
+ onCommitEnd
705
+ }) {
706
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
707
+ /* @__PURE__ */ jsxs(
708
+ "div",
709
+ {
710
+ className: cn(
711
+ "grid w-full grid-cols-1 gap-3 rounded-xl border border-border/45 bg-muted/20 p-3 sm:grid-cols-2",
712
+ calendarMonths === 2 ? "max-w-none" : "max-w-md"
713
+ ),
714
+ children: [
715
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
716
+ /* @__PURE__ */ jsx("label", { htmlFor: startInputId, className: "text-xs font-medium text-muted-foreground", children: startLabel }),
717
+ /* @__PURE__ */ jsx(
718
+ Input,
719
+ {
720
+ id: startInputId,
721
+ type: "text",
722
+ value: startInputText,
723
+ onChange: (e) => onStartInputChange(e.target.value),
724
+ onBlur: onCommitStart,
725
+ onKeyDown: (e) => {
726
+ if (e.key === "Enter") {
727
+ e.preventDefault();
728
+ onCommitStart();
729
+ }
730
+ },
731
+ placeholder: effectivePlaceholder,
732
+ className: "h-9 font-mono text-sm tabular-nums"
733
+ }
734
+ )
735
+ ] }),
736
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
737
+ /* @__PURE__ */ jsx("label", { htmlFor: endInputId, className: "text-xs font-medium text-muted-foreground", children: endLabel }),
738
+ /* @__PURE__ */ jsx(
739
+ Input,
740
+ {
741
+ id: endInputId,
742
+ type: "text",
743
+ value: endInputText,
744
+ onChange: (e) => onEndInputChange(e.target.value),
745
+ onBlur: onCommitEnd,
746
+ onKeyDown: (e) => {
747
+ if (e.key === "Enter") {
748
+ e.preventDefault();
749
+ onCommitEnd();
750
+ }
751
+ },
752
+ placeholder: effectivePlaceholder,
753
+ className: "h-9 font-mono text-sm tabular-nums"
754
+ }
755
+ )
756
+ ] })
757
+ ]
758
+ }
759
+ ),
760
+ /* @__PURE__ */ jsx("div", { className: cn(surfaceCard, "flex w-full justify-center p-1"), children: /* @__PURE__ */ jsx(
761
+ Calendar,
762
+ {
763
+ mode: "range",
764
+ numberOfMonths: calendarMonths,
765
+ month: displayedMonth,
766
+ onMonthChange,
767
+ selected: draft,
768
+ onSelect,
769
+ disabled: disabledMatchers,
770
+ locale,
771
+ className: cn(calendarMonths === 2 && "p-2")
772
+ }
773
+ ) })
774
+ ] });
775
+ }
776
+ function rangesMatch(a, b) {
777
+ const af = normalizeDate(a?.from)?.getTime();
778
+ const at = normalizeDate(a?.to)?.getTime();
779
+ const bf = normalizeDate(b.from)?.getTime();
780
+ const bt = normalizeDate(b.to)?.getTime();
781
+ return af === bf && at === bt;
782
+ }
783
+ function parseDate(part) {
784
+ const p = part.trim();
785
+ if (!p) return null;
786
+ const ref = /* @__PURE__ */ new Date();
787
+ for (const fmt of [INPUT_FORMAT, INPUT_FORMAT_ALT, DISPLAY_FORMAT]) {
788
+ try {
789
+ const d = parse(p, fmt, ref);
790
+ if (!Number.isNaN(d.getTime())) return d;
791
+ } catch {
792
+ }
793
+ }
794
+ return null;
795
+ }
796
+ function parseInputToRange(text) {
797
+ const trimmed = text.trim();
798
+ if (!trimmed) return { from: void 0, to: void 0 };
799
+ const parts = trimmed.split(/\s*[–-]\s*/).map((p) => p.trim());
800
+ try {
801
+ if (parts.length >= 2) {
802
+ const from = parseDate(parts[0]);
803
+ const to = parseDate(parts[1]);
804
+ if (from && to) return { from, to };
805
+ if (from) return { from, to: void 0 };
806
+ } else if (parts.length === 1 && parts[0]) {
807
+ const from = parseDate(parts[0]);
808
+ if (from) return { from, to: void 0 };
809
+ }
810
+ } catch {
811
+ }
812
+ return null;
813
+ }
814
+ function formatRangeLabel(value, placeholder, formatOpts) {
815
+ const from = value?.from;
816
+ const to = value?.to;
817
+ if (from && to) {
818
+ return `${format(from, DISPLAY_FORMAT, formatOpts)} \u2013 ${format(to, DISPLAY_FORMAT, formatOpts)}`;
819
+ }
820
+ if (from) {
821
+ return format(from, DISPLAY_FORMAT, formatOpts);
822
+ }
823
+ return placeholder;
824
+ }
825
+ function DateRangePickerPresetList({
826
+ presets,
827
+ draft,
828
+ layout,
829
+ presetsHeading,
830
+ onPreset
831
+ }) {
832
+ if (presets.length === 0) return null;
833
+ if (layout === "mobile-row") {
834
+ return /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-border/50 bg-muted/20 px-2 py-2", children: /* @__PURE__ */ jsx("div", { className: "flex gap-1 overflow-x-auto overscroll-x-contain px-1 py-1 [scrollbar-width:thin] [-webkit-overflow-scrolling:touch]", children: presets.map((preset) => {
835
+ const active = rangesMatch(draft, preset.getRange());
836
+ return /* @__PURE__ */ jsx(
837
+ Button,
838
+ {
839
+ type: "button",
840
+ variant: "ghost",
841
+ size: "sm",
842
+ className: cn(
843
+ "h-9 shrink-0 whitespace-nowrap rounded-lg px-2.5 text-sm font-normal",
844
+ active && "bg-accent font-medium text-accent-foreground"
845
+ ),
846
+ onClick: () => onPreset(preset.getRange),
847
+ children: preset.label
848
+ },
849
+ preset.id
850
+ );
851
+ }) }) });
852
+ }
853
+ return /* @__PURE__ */ jsx("div", { className: "w-[11.5rem] shrink-0 border-r border-border/50 bg-muted/20", children: /* @__PURE__ */ jsxs("div", { className: "flex max-h-[min(420px,70vh)] flex-col gap-0.5 overflow-y-auto p-2 [scrollbar-width:thin]", children: [
854
+ presetsHeading ? /* @__PURE__ */ jsx("p", { className: "px-2 pb-1 pt-0.5 text-[0.65rem] font-semibold uppercase tracking-wider text-muted-foreground", children: presetsHeading }) : null,
855
+ presets.map((preset) => {
856
+ const active = rangesMatch(draft, preset.getRange());
857
+ return /* @__PURE__ */ jsx(
858
+ Button,
859
+ {
860
+ type: "button",
861
+ variant: "ghost",
862
+ size: "sm",
863
+ className: cn(
864
+ "h-9 w-full shrink-0 justify-start rounded-lg px-2.5 text-left text-sm font-normal",
865
+ active && "bg-accent font-medium text-accent-foreground"
866
+ ),
867
+ onClick: () => onPreset(preset.getRange),
868
+ children: preset.label
869
+ },
870
+ preset.id
871
+ );
872
+ })
873
+ ] }) });
874
+ }
875
+ function DateRangePickerTrigger({
876
+ className,
877
+ inputText,
878
+ effectivePlaceholder,
879
+ isEmpty,
880
+ ariaLabel,
881
+ onOpen,
882
+ onInputChange,
883
+ onInputFocus,
884
+ onInputBlur
885
+ }) {
886
+ return /* @__PURE__ */ jsxs(
887
+ "div",
888
+ {
889
+ role: "button",
890
+ tabIndex: 0,
891
+ onClick: onOpen,
892
+ onKeyDown: (e) => {
893
+ if (e.key === "Enter" || e.key === " ") {
894
+ e.preventDefault();
895
+ onOpen();
896
+ }
897
+ },
898
+ className: cn(
899
+ controlBase,
900
+ "flex w-full min-w-[17rem] max-w-full cursor-pointer items-center overflow-hidden focus-within:ring-[3px] focus-within:ring-ring/40",
901
+ className
902
+ ),
903
+ children: [
904
+ /* @__PURE__ */ jsx("span", { className: "flex h-10 w-10 shrink-0 items-center justify-center border-r border-border/40 bg-muted/25 text-muted-foreground", children: /* @__PURE__ */ jsx(Calendar$1, { className: "size-4", "aria-hidden": "true" }) }),
905
+ /* @__PURE__ */ jsx(
906
+ Input,
907
+ {
908
+ type: "text",
909
+ value: inputText,
910
+ onChange: (e) => onInputChange(e.target.value),
911
+ onFocus: onInputFocus,
912
+ onBlur: onInputBlur,
913
+ onClick: onOpen,
914
+ onKeyDown: (e) => {
915
+ if (e.key === "Enter") {
916
+ e.target.blur();
917
+ }
918
+ },
919
+ placeholder: effectivePlaceholder,
920
+ "data-empty": isEmpty || void 0,
921
+ className: cn(
922
+ "h-10 min-w-0 flex-1 cursor-pointer rounded-none border-0 bg-transparent py-2 pl-3 pr-3 text-sm shadow-none focus-visible:ring-0 whitespace-nowrap",
923
+ isEmpty && "text-muted-foreground"
924
+ ),
925
+ title: !isEmpty ? inputText : void 0,
926
+ "aria-label": ariaLabel
927
+ }
928
+ )
929
+ ]
930
+ }
931
+ );
932
+ }
933
+
934
+ // src/components/ui/date-range-picker/useDateRangePresets.ts
935
+ function getPresetRange(presetId) {
936
+ const today = /* @__PURE__ */ new Date();
937
+ today.setHours(23, 59, 59, 999);
938
+ const from = new Date(today);
939
+ from.setHours(0, 0, 0, 0);
940
+ const to = new Date(today);
941
+ switch (presetId) {
942
+ case "today":
943
+ return { from, to };
944
+ case "yesterday":
945
+ from.setDate(from.getDate() - 1);
946
+ to.setDate(to.getDate() - 1);
947
+ return { from, to };
948
+ case "last7":
949
+ from.setDate(from.getDate() - 6);
950
+ return { from, to };
951
+ case "last14":
952
+ from.setDate(from.getDate() - 13);
953
+ return { from, to };
954
+ case "last30":
955
+ from.setDate(from.getDate() - 29);
956
+ return { from, to };
957
+ case "thisWeek": {
958
+ const day = from.getDay();
959
+ const mondayOffset = day === 0 ? -6 : 1 - day;
960
+ from.setDate(from.getDate() + mondayOffset);
961
+ return { from, to };
962
+ }
963
+ case "lastWeek": {
964
+ const day = from.getDay();
965
+ const mondayOffset = day === 0 ? -6 : 1 - day;
966
+ const thisMonday = from.getDate() + mondayOffset;
967
+ from.setDate(thisMonday - 7);
968
+ to.setDate(thisMonday - 1);
969
+ to.setHours(23, 59, 59, 999);
970
+ return { from, to };
971
+ }
972
+ case "thisMonth":
973
+ from.setDate(1);
974
+ return { from, to };
975
+ case "lastMonth":
976
+ from.setMonth(from.getMonth() - 1);
977
+ from.setDate(1);
978
+ to.setDate(0);
979
+ to.setHours(23, 59, 59, 999);
980
+ return { from, to };
981
+ default:
982
+ return { from, to };
983
+ }
984
+ }
985
+ function useMediaQuery(query, fallback = false) {
986
+ const subscribe = React6.useCallback(
987
+ (onChange) => {
988
+ const mql = window.matchMedia(query);
989
+ mql.addEventListener("change", onChange);
990
+ return () => mql.removeEventListener("change", onChange);
991
+ },
992
+ [query]
993
+ );
994
+ return React6.useSyncExternalStore(
995
+ subscribe,
996
+ () => window.matchMedia(query).matches,
997
+ () => fallback
998
+ );
999
+ }
1000
+ function useIsDatePickerMobileLayout() {
1001
+ return useMediaQuery(DATE_RANGE_MOBILE_MQ, false);
1002
+ }
1003
+ function useIsWideDatePickerLayout() {
1004
+ return useMediaQuery(DATE_RANGE_WIDE_MQ, false);
1005
+ }
1006
+ function DateRangePicker({
1007
+ value,
1008
+ onChange,
1009
+ minDate,
1010
+ maxDate,
1011
+ placeholder,
1012
+ showPresets = true,
1013
+ presets: customPresets,
1014
+ translations,
1015
+ locale,
1016
+ onApply,
1017
+ isDateDisabled,
1018
+ className
1019
+ }) {
1020
+ const t = { ...DEFAULT_TRANSLATIONS, ...translations };
1021
+ const effectivePlaceholder = placeholder ?? t.placeholder;
1022
+ const presetList = React6.useMemo(() => {
1023
+ if (customPresets?.length) return customPresets;
1024
+ if (!showPresets) return [];
1025
+ return DEFAULT_PRESET_IDS.map(({ id }) => ({
1026
+ id,
1027
+ label: translations?.presetLabels?.[id] ?? DEFAULT_PRESET_LABELS[id],
1028
+ getRange: () => getPresetRange(id)
1029
+ }));
1030
+ }, [customPresets, showPresets, translations?.presetLabels]);
1031
+ const normalizedMin = normalizeDate(minDate);
1032
+ const normalizedMax = normalizeDate(maxDate);
1033
+ const isMobileLayout = useIsDatePickerMobileLayout();
1034
+ const isWideLayout = useIsWideDatePickerLayout();
1035
+ const calendarMonths = isMobileLayout ? 1 : isWideLayout ? 2 : 1;
1036
+ const [open, setOpen] = React6.useState(false);
1037
+ const [draft, setDraft] = React6.useState(value);
1038
+ const [displayedMonth, setDisplayedMonth] = React6.useState(() => value?.from ?? /* @__PURE__ */ new Date());
1039
+ const appliedRef = React6.useRef(value);
1040
+ const wasOpenRef = React6.useRef(false);
1041
+ const useApplyFlow = !!onApply;
1042
+ const idScope = React6.useId();
1043
+ const startInputId = `date-range-start-${idScope}`;
1044
+ const endInputId = `date-range-end-${idScope}`;
1045
+ React6.useEffect(() => {
1046
+ const wasOpen = wasOpenRef.current;
1047
+ wasOpenRef.current = open;
1048
+ if (open && !wasOpen) {
1049
+ appliedRef.current = value;
1050
+ setDraft(value);
1051
+ setDisplayedMonth(value?.from ?? /* @__PURE__ */ new Date());
1052
+ } else if (open && wasOpen) {
1053
+ setDraft(value);
1054
+ }
1055
+ }, [open, value]);
1056
+ const handleOpenChange = React6.useCallback(
1057
+ (next) => {
1058
+ if (!next && open && !useApplyFlow) {
1059
+ onChange(appliedRef.current);
1060
+ setDraft(appliedRef.current);
1061
+ }
1062
+ setOpen(next);
1063
+ },
1064
+ [open, useApplyFlow, onChange]
1065
+ );
1066
+ const formatOpts = React6.useMemo(() => locale ? { locale } : void 0, [locale]);
1067
+ const label = React6.useMemo(
1068
+ () => formatRangeLabel(value, effectivePlaceholder, formatOpts),
1069
+ [effectivePlaceholder, value, formatOpts]
1070
+ );
1071
+ const [inputText, setInputText] = React6.useState(label);
1072
+ const inputFocusedRef = React6.useRef(false);
1073
+ React6.useEffect(() => {
1074
+ if (!inputFocusedRef.current) setInputText(label);
1075
+ }, [label]);
1076
+ const handleInputBlur = () => {
1077
+ inputFocusedRef.current = false;
1078
+ const next = parseInputToRange(inputText);
1079
+ if (next) {
1080
+ const formatted = next.from && next.to ? `${format(next.from, DISPLAY_FORMAT, formatOpts)} \u2013 ${format(next.to, DISPLAY_FORMAT, formatOpts)}` : next.from ? format(next.from, DISPLAY_FORMAT, formatOpts) : effectivePlaceholder;
1081
+ if (useApplyFlow) {
1082
+ setDraft(next);
1083
+ setInputText(formatted);
1084
+ } else {
1085
+ onChange(next);
1086
+ setInputText(formatted);
1087
+ }
1088
+ } else {
1089
+ setInputText(label);
1090
+ }
1091
+ };
1092
+ const disabledMatchers = React6.useMemo(() => {
1093
+ const toStartOfDay = (d) => {
1094
+ const copy = new Date(d);
1095
+ copy.setHours(0, 0, 0, 0);
1096
+ return copy.getTime();
1097
+ };
1098
+ const matchers = [];
1099
+ if (normalizedMin) {
1100
+ matchers.push((date) => toStartOfDay(date) < toStartOfDay(normalizedMin));
1101
+ }
1102
+ if (normalizedMax) {
1103
+ matchers.push((date) => toStartOfDay(date) > toStartOfDay(normalizedMax));
1104
+ }
1105
+ if (isDateDisabled) matchers.push((date) => isDateDisabled(date));
1106
+ return matchers;
1107
+ }, [normalizedMin, normalizedMax, isDateDisabled]);
1108
+ const handlePreset = (getRange) => {
1109
+ const range = getRange();
1110
+ setDraft(range);
1111
+ if (!useApplyFlow) onChange(range);
1112
+ };
1113
+ const handleApply = () => {
1114
+ if (useApplyFlow) {
1115
+ onChange(draft);
1116
+ onApply?.(draft);
1117
+ }
1118
+ setOpen(false);
1119
+ };
1120
+ const handleCancel = () => {
1121
+ if (useApplyFlow) {
1122
+ setDraft(appliedRef.current);
1123
+ } else {
1124
+ onChange(appliedRef.current);
1125
+ setDraft(appliedRef.current);
1126
+ }
1127
+ setOpen(false);
1128
+ };
1129
+ const handleSelect = (_next, triggerDate) => {
1130
+ const day = normalizeDate(triggerDate);
1131
+ if (!day) return;
1132
+ setDraft((prev) => {
1133
+ if (!prev?.from || prev.from && prev.to) {
1134
+ const nextRange2 = { from: day, to: void 0 };
1135
+ if (!useApplyFlow) onChange(nextRange2);
1136
+ return nextRange2;
1137
+ }
1138
+ if (day < prev.from) {
1139
+ const nextRange2 = { from: day, to: void 0 };
1140
+ if (!useApplyFlow) onChange(nextRange2);
1141
+ return nextRange2;
1142
+ }
1143
+ const nextRange = { from: prev.from, to: day };
1144
+ if (!useApplyFlow) onChange(nextRange);
1145
+ return nextRange;
1146
+ });
1147
+ };
1148
+ const [startInputText, setStartInputText] = React6.useState("");
1149
+ const [endInputText, setEndInputText] = React6.useState("");
1150
+ React6.useEffect(() => {
1151
+ if (open) {
1152
+ setStartInputText(draft?.from ? format(draft.from, INPUT_FORMAT) : "");
1153
+ setEndInputText(draft?.to ? format(draft.to, INPUT_FORMAT) : "");
1154
+ }
1155
+ }, [open, draft?.from, draft?.to]);
1156
+ const commitStartInput = () => {
1157
+ const d = parseDate(startInputText);
1158
+ if (d) {
1159
+ setDraft((prev) => ({ from: d, to: prev?.to && prev.to >= d ? prev.to : void 0 }));
1160
+ } else {
1161
+ setStartInputText(draft?.from ? format(draft.from, INPUT_FORMAT) : "");
1162
+ }
1163
+ };
1164
+ const commitEndInput = () => {
1165
+ const d = parseDate(endInputText);
1166
+ if (d) {
1167
+ setDraft((prev) => ({ from: prev?.from && prev.from <= d ? prev.from : d, to: d }));
1168
+ } else {
1169
+ setEndInputText(draft?.to ? format(draft.to, INPUT_FORMAT) : "");
1170
+ }
1171
+ };
1172
+ const fieldsCalendar = /* @__PURE__ */ jsx(
1173
+ DateRangePickerFieldsCalendar,
1174
+ {
1175
+ calendarMonths,
1176
+ draft,
1177
+ displayedMonth,
1178
+ onMonthChange: setDisplayedMonth,
1179
+ onSelect: handleSelect,
1180
+ disabledMatchers,
1181
+ locale,
1182
+ startInputId,
1183
+ endInputId,
1184
+ startLabel: t.startLabel,
1185
+ endLabel: t.endLabel,
1186
+ startInputText,
1187
+ endInputText,
1188
+ effectivePlaceholder,
1189
+ onStartInputChange: setStartInputText,
1190
+ onEndInputChange: setEndInputText,
1191
+ onCommitStart: commitStartInput,
1192
+ onCommitEnd: commitEndInput
1193
+ }
1194
+ );
1195
+ const footer = /* @__PURE__ */ jsx(
1196
+ DateRangePickerActionFooter,
1197
+ {
1198
+ visible: useApplyFlow || isMobileLayout,
1199
+ isMobileLayout,
1200
+ cancelLabel: t.cancelButton,
1201
+ applyLabel: t.applyButton,
1202
+ onCancel: handleCancel,
1203
+ onApply: handleApply
1204
+ }
1205
+ );
1206
+ const trigger = /* @__PURE__ */ jsx(
1207
+ DateRangePickerTrigger,
1208
+ {
1209
+ className,
1210
+ inputText,
1211
+ effectivePlaceholder,
1212
+ isEmpty: !value?.from,
1213
+ ariaLabel: t.ariaLabel,
1214
+ onOpen: () => setOpen(true),
1215
+ onInputChange: setInputText,
1216
+ onInputFocus: () => {
1217
+ inputFocusedRef.current = true;
1218
+ },
1219
+ onInputBlur: handleInputBlur
1220
+ }
1221
+ );
1222
+ if (isMobileLayout) {
1223
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1224
+ trigger,
1225
+ /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(
1226
+ DialogContent,
1227
+ {
1228
+ showCloseButton: true,
1229
+ className: cn(
1230
+ "h-dvh max-h-dvh w-full max-w-full gap-0 rounded-none border-0 p-0 shadow-[var(--shadow-elevated)]",
1231
+ "top-0 left-0 flex translate-x-0 translate-y-0 flex-col"
1232
+ ),
1233
+ overlayClassName: "z-110",
1234
+ children: [
1235
+ /* @__PURE__ */ jsx(DialogHeader, { className: "shrink-0 items-start border-b border-border/50 px-4 py-4 text-left", children: /* @__PURE__ */ jsx(DialogTitle, { className: "pr-10 text-left text-base", children: t.ariaLabel }) }),
1236
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: [
1237
+ /* @__PURE__ */ jsx(
1238
+ DateRangePickerPresetList,
1239
+ {
1240
+ presets: presetList,
1241
+ draft,
1242
+ layout: "mobile-row",
1243
+ onPreset: handlePreset
1244
+ }
1245
+ ),
1246
+ /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto px-4 py-4", children: /* @__PURE__ */ jsx("div", { className: "mx-auto flex w-full max-w-md flex-col items-center", children: fieldsCalendar }) }),
1247
+ footer
1248
+ ] })
1249
+ ]
1250
+ }
1251
+ ) })
1252
+ ] });
1253
+ }
1254
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
1255
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: trigger }),
1256
+ /* @__PURE__ */ jsx(
1257
+ PopoverContent,
1258
+ {
1259
+ className: cn(
1260
+ surfaceOverlay,
1261
+ "w-auto max-w-[min(calc(100vw-1.5rem),52rem)] overflow-hidden p-0",
1262
+ calendarMonths === 2 && "min-w-[36rem]"
1263
+ ),
1264
+ align: "start",
1265
+ sideOffset: 8,
1266
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row", children: [
1267
+ /* @__PURE__ */ jsx(
1268
+ DateRangePickerPresetList,
1269
+ {
1270
+ presets: presetList,
1271
+ draft,
1272
+ layout: "sidebar",
1273
+ presetsHeading: t.presetsHeading,
1274
+ onPreset: handlePreset
1275
+ }
1276
+ ),
1277
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col bg-background", children: [
1278
+ /* @__PURE__ */ jsx("div", { className: "flex w-full flex-col items-stretch p-4", children: fieldsCalendar }),
1279
+ footer
1280
+ ] })
1281
+ ] })
1282
+ }
1283
+ )
1284
+ ] });
1285
+ }
1286
+ var dropdownMenuSelectOptionsMaxHeightClassName = "max-h-[min(var(--radix-dropdown-menu-content-available-height),13rem)]";
1287
+ function DropdownMenu({ ...props }) {
1288
+ return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1289
+ }
1290
+ function DropdownMenuTrigger({
1291
+ ...props
1292
+ }) {
1293
+ return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1294
+ }
1295
+ function DropdownMenuContent({
1296
+ className,
1297
+ sideOffset = 4,
1298
+ portalled = true,
1299
+ ...props
1300
+ }) {
1301
+ const content = /* @__PURE__ */ jsx(
1302
+ DropdownMenuPrimitive.Content,
1303
+ {
1304
+ "data-slot": "dropdown-menu-content",
1305
+ sideOffset,
1306
+ className: cn(
1307
+ surfaceOverlay,
1308
+ "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 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto p-1",
1309
+ className
1310
+ ),
1311
+ ...props
1312
+ }
1313
+ );
1314
+ if (!portalled) {
1315
+ return content;
1316
+ }
1317
+ return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: content });
1318
+ }
1319
+ function DropdownMenuItem({
1320
+ className,
1321
+ ...props
1322
+ }) {
1323
+ return /* @__PURE__ */ jsx(
1324
+ DropdownMenuPrimitive.Item,
1325
+ {
1326
+ "data-slot": "dropdown-menu-item",
1327
+ className: cn(
1328
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1329
+ className
1330
+ ),
1331
+ ...props
1332
+ }
1333
+ );
1334
+ }
1335
+ function DropdownScrollableList({
1336
+ children,
1337
+ scrollKey,
1338
+ className,
1339
+ scrollAreaClassName,
1340
+ grow = true
1341
+ }) {
1342
+ const scrollRef = React6.useRef(null);
1343
+ const [showTop, setShowTop] = React6.useState(false);
1344
+ const [showBottom, setShowBottom] = React6.useState(false);
1345
+ const update = React6.useCallback(() => {
1346
+ const el = scrollRef.current;
1347
+ if (!el) {
1348
+ setShowTop(false);
1349
+ setShowBottom(false);
1350
+ return;
1351
+ }
1352
+ const { scrollTop, scrollHeight, clientHeight } = el;
1353
+ const overflow = scrollHeight - clientHeight > 2;
1354
+ if (!overflow) {
1355
+ setShowTop(false);
1356
+ setShowBottom(false);
1357
+ return;
1358
+ }
1359
+ setShowTop(scrollTop > 2);
1360
+ setShowBottom(scrollTop + clientHeight < scrollHeight - 2);
1361
+ }, []);
1362
+ React6.useLayoutEffect(() => {
1363
+ update();
1364
+ const id = requestAnimationFrame(() => {
1365
+ requestAnimationFrame(update);
1366
+ });
1367
+ return () => cancelAnimationFrame(id);
1368
+ }, [update, scrollKey]);
1369
+ React6.useEffect(() => {
1370
+ const el = scrollRef.current;
1371
+ if (!el) return;
1372
+ if (typeof ResizeObserver === "undefined") {
1373
+ return;
1374
+ }
1375
+ const ro = new ResizeObserver(() => {
1376
+ window.requestAnimationFrame(update);
1377
+ });
1378
+ ro.observe(el);
1379
+ return () => ro.disconnect();
1380
+ }, [update]);
1381
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative flex min-h-0 flex-col", grow && "flex-1", className), children: [
1382
+ /* @__PURE__ */ jsx(
1383
+ "div",
1384
+ {
1385
+ ref: scrollRef,
1386
+ className: cn(
1387
+ grow ? cn("min-h-0 flex-1 overflow-y-auto overscroll-y-contain p-1", scrollAreaClassName) : scrollAreaClassName
1388
+ ),
1389
+ onScroll: update,
1390
+ children
1391
+ }
1392
+ ),
1393
+ showTop ? /* @__PURE__ */ jsxs(
1394
+ "div",
1395
+ {
1396
+ className: "pointer-events-none absolute inset-x-0 top-0 z-[1] flex h-6 flex-col items-center justify-start pt-px",
1397
+ "aria-hidden": true,
1398
+ children: [
1399
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-b from-popover via-popover/35 to-transparent backdrop-blur-[0.5px]" }),
1400
+ /* @__PURE__ */ jsx(
1401
+ ChevronUp,
1402
+ {
1403
+ className: "relative z-[2] h-3.5 w-3.5 shrink-0 text-muted-foreground opacity-90 drop-shadow-sm",
1404
+ strokeWidth: 2.5
1405
+ }
1406
+ )
1407
+ ]
1408
+ }
1409
+ ) : null,
1410
+ showBottom ? /* @__PURE__ */ jsxs(
1411
+ "div",
1412
+ {
1413
+ className: "pointer-events-none absolute inset-x-0 bottom-0 z-[1] flex h-6 flex-col items-center justify-end pb-px",
1414
+ "aria-hidden": true,
1415
+ children: [
1416
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-popover via-popover/35 to-transparent backdrop-blur-[0.5px]" }),
1417
+ /* @__PURE__ */ jsx(
1418
+ ChevronDown,
1419
+ {
1420
+ className: "relative z-[2] h-3.5 w-3.5 shrink-0 text-muted-foreground opacity-90 drop-shadow-sm",
1421
+ strokeWidth: 2.5
1422
+ }
1423
+ )
1424
+ ]
1425
+ }
1426
+ ) : null
1427
+ ] });
1428
+ }
1429
+ function DropdownSelectSearchInput({
1430
+ value,
1431
+ onChange,
1432
+ placeholder = "Search\u2026",
1433
+ className,
1434
+ autoFocus = false
1435
+ }) {
1436
+ return /* @__PURE__ */ jsx("div", { className: cn("shrink-0 px-1 pb-2 pt-1", className), children: /* @__PURE__ */ jsx(
1437
+ Input,
1438
+ {
1439
+ value,
1440
+ onChange: (event) => onChange(event.target.value),
1441
+ placeholder,
1442
+ "aria-label": placeholder,
1443
+ autoFocus,
1444
+ onKeyDown: (event) => event.stopPropagation()
1445
+ }
1446
+ ) });
1447
+ }
1448
+ var labelVariants = cva(
1449
+ "text-sm font-medium leading-none tracking-tight text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
1450
+ );
1451
+ function Label({
1452
+ className,
1453
+ ...props
1454
+ }) {
1455
+ return /* @__PURE__ */ jsx(LabelPrimitive.Root, { "data-slot": "label", className: cn(labelVariants(), className), ...props });
1456
+ }
1457
+ var Form = FormProvider;
1458
+ var FormFieldContext = React6.createContext(null);
1459
+ var FormField = ({
1460
+ ...props
1461
+ }) => {
1462
+ return /* @__PURE__ */ jsx(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsx(Controller, { ...props }) });
1463
+ };
1464
+ var useFormField = () => {
1465
+ const fieldContext = React6.useContext(FormFieldContext);
1466
+ const itemContext = React6.useContext(FormItemContext);
1467
+ if (fieldContext === null || fieldContext === void 0) {
1468
+ throw new Error("useFormField should be used within <FormField>");
1469
+ }
1470
+ const { getFieldState } = useFormContext();
1471
+ const formState = useFormState({ name: fieldContext.name });
1472
+ const fieldState = getFieldState(fieldContext.name, formState);
1473
+ const { id } = itemContext;
1474
+ return {
1475
+ id,
1476
+ name: fieldContext.name,
1477
+ formItemId: `${id}-form-item`,
1478
+ formDescriptionId: `${id}-form-item-description`,
1479
+ formMessageId: `${id}-form-item-message`,
1480
+ ...fieldState
1481
+ };
1482
+ };
1483
+ var FormItemContext = React6.createContext({});
1484
+ function FormItem({ className, ...props }) {
1485
+ const id = React6.useId();
1486
+ return /* @__PURE__ */ jsx(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ jsx("div", { "data-slot": "form-item", className: cn("grid gap-3", className), ...props }) });
1487
+ }
1488
+ function FormLabel({
1489
+ className,
1490
+ ...props
1491
+ }) {
1492
+ const { error, formItemId } = useFormField();
1493
+ return /* @__PURE__ */ jsx(
1494
+ Label,
1495
+ {
1496
+ "data-slot": "form-label",
1497
+ "data-error": !!error,
1498
+ className: cn("data-[error=true]:text-destructive", className),
1499
+ htmlFor: formItemId,
1500
+ ...props
1501
+ }
1502
+ );
1503
+ }
1504
+ function FormControl({ ...props }) {
1505
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
1506
+ return /* @__PURE__ */ jsx(
1507
+ Slot,
1508
+ {
1509
+ "data-slot": "form-control",
1510
+ id: formItemId,
1511
+ "aria-describedby": !error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`,
1512
+ "aria-invalid": !!error,
1513
+ ...props
1514
+ }
1515
+ );
1516
+ }
1517
+ function FormDescription({ className, ...props }) {
1518
+ const { formDescriptionId } = useFormField();
1519
+ return /* @__PURE__ */ jsx(
1520
+ "p",
1521
+ {
1522
+ "data-slot": "form-description",
1523
+ id: formDescriptionId,
1524
+ className: cn("text-muted-foreground text-sm", className),
1525
+ ...props
1526
+ }
1527
+ );
1528
+ }
1529
+ function FormMessage({ className, ...props }) {
1530
+ const { error, formMessageId } = useFormField();
1531
+ const body = error ? String(error?.message ?? "") : props.children;
1532
+ if (!body) {
1533
+ return null;
1534
+ }
1535
+ return /* @__PURE__ */ jsx(
1536
+ "p",
1537
+ {
1538
+ "data-slot": "form-message",
1539
+ id: formMessageId,
1540
+ className: cn("text-destructive text-sm", className),
1541
+ ...props,
1542
+ children: body
1543
+ }
1544
+ );
1545
+ }
1546
+ var InsideModalScrollLockContext = React6.createContext(false);
1547
+ function InsideModalScrollLockProvider({
1548
+ children,
1549
+ active = true
1550
+ }) {
1551
+ return /* @__PURE__ */ jsx(InsideModalScrollLockContext.Provider, { value: active, children });
1552
+ }
1553
+ function useInsideModalScrollLock() {
1554
+ return React6.useContext(InsideModalScrollLockContext);
1555
+ }
1556
+ function Sheet({ ...props }) {
1557
+ return /* @__PURE__ */ jsx(DialogPrimitive.Root, { ...props });
1558
+ }
1559
+ function SheetTrigger({ ...props }) {
1560
+ return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { ...props });
1561
+ }
1562
+ function SheetClose({ ...props }) {
1563
+ return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...props });
1564
+ }
1565
+ function SheetPortal({ ...props }) {
1566
+ return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { ...props });
1567
+ }
1568
+ function SheetOverlay({
1569
+ className,
1570
+ ...props
1571
+ }) {
1572
+ return /* @__PURE__ */ jsx(
1573
+ DialogPrimitive.Overlay,
1574
+ {
1575
+ className: cn(
1576
+ "fixed inset-0 z-[100] bg-foreground/20 backdrop-blur-[2px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1577
+ className
1578
+ ),
1579
+ ...props
1580
+ }
1581
+ );
1582
+ }
1583
+ function SheetContent({
1584
+ className,
1585
+ children,
1586
+ side = "right",
1587
+ onPointerDownOutside,
1588
+ onInteractOutside,
1589
+ onFocusOutside,
1590
+ ...props
1591
+ }) {
1592
+ return /* @__PURE__ */ jsxs(SheetPortal, { children: [
1593
+ /* @__PURE__ */ jsx(SheetOverlay, {}),
1594
+ /* @__PURE__ */ jsxs(
1595
+ DialogPrimitive.Content,
1596
+ {
1597
+ onPointerDownOutside: (event) => {
1598
+ preventDismissOnPortaledOverlay(event);
1599
+ if (!event.defaultPrevented) {
1600
+ onPointerDownOutside?.(event);
1601
+ }
1602
+ },
1603
+ onInteractOutside: (event) => {
1604
+ preventDismissOnPortaledOverlay(event);
1605
+ if (!event.defaultPrevented) {
1606
+ onInteractOutside?.(event);
1607
+ }
1608
+ },
1609
+ onFocusOutside: (event) => {
1610
+ preventDismissOnPortaledOverlay(event);
1611
+ if (!event.defaultPrevented) {
1612
+ onFocusOutside?.(event);
1613
+ }
1614
+ },
1615
+ className: cn(
1616
+ "bg-background border-border/50 data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-[100] flex flex-col gap-4 border p-6 shadow-[var(--shadow-elevated)] transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 overflow-y-auto overflow-x-hidden max-h-full",
1617
+ side === "right" && "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-11/12 border-l sm:max-w-sm",
1618
+ side === "left" && "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-11/12 border-r sm:max-w-sm",
1619
+ side === "top" && "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
1620
+ side === "bottom" && "data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
1621
+ className
1622
+ ),
1623
+ ...props,
1624
+ children: [
1625
+ children,
1626
+ /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-6 right-6 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none cursor-pointer", children: [
1627
+ /* @__PURE__ */ jsx(XIcon, { className: "h-4 w-4" }),
1628
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
1629
+ ] })
1630
+ ]
1631
+ }
1632
+ )
1633
+ ] });
1634
+ }
1635
+ var SheetHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-2 text-left pb-4", className), ...props });
1636
+ SheetHeader.displayName = "SheetHeader";
1637
+ var SheetFooter = ({ className, ...props }) => /* @__PURE__ */ jsx(
1638
+ "div",
1639
+ {
1640
+ className: cn(
1641
+ "flex flex-col-reverse gap-2 pt-4 border-t sm:flex-row sm:justify-end sm:space-x-2 sm:gap-0",
1642
+ className
1643
+ ),
1644
+ ...props
1645
+ }
1646
+ );
1647
+ SheetFooter.displayName = "SheetFooter";
1648
+ function SheetTitle({ className, ...props }) {
1649
+ return /* @__PURE__ */ jsx(
1650
+ DialogPrimitive.Title,
1651
+ {
1652
+ className: cn("text-lg font-semibold text-foreground", className),
1653
+ ...props
1654
+ }
1655
+ );
1656
+ }
1657
+ function SheetDescription({
1658
+ className,
1659
+ ...props
1660
+ }) {
1661
+ return /* @__PURE__ */ jsx(
1662
+ DialogPrimitive.Description,
1663
+ {
1664
+ className: cn("text-sm text-muted-foreground", className),
1665
+ ...props
1666
+ }
1667
+ );
1668
+ }
1669
+ function FormDrawer({
1670
+ open,
1671
+ onOpenChange,
1672
+ title,
1673
+ description,
1674
+ children,
1675
+ className,
1676
+ contentClassName
1677
+ }) {
1678
+ return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
1679
+ SheetContent,
1680
+ {
1681
+ "data-slot": "form-drawer-content",
1682
+ className: cn(
1683
+ "flex flex-col gap-4 w-[calc(100%-2rem)] max-w-[calc(100%-2rem)] sm:max-w-lg overflow-hidden",
1684
+ contentClassName
1685
+ ),
1686
+ children: [
1687
+ /* @__PURE__ */ jsxs(SheetHeader, { className: "flex-shrink-0 gap-2 pb-2", children: [
1688
+ /* @__PURE__ */ jsx(SheetTitle, { className: "text-base sm:text-lg", children: title }),
1689
+ description && /* @__PURE__ */ jsx(SheetDescription, { className: "text-sm", children: description })
1690
+ ] }),
1691
+ /* @__PURE__ */ jsx(InsideModalScrollLockProvider, { children: /* @__PURE__ */ jsx(
1692
+ "div",
1693
+ {
1694
+ className: cn(
1695
+ // Inset so focus rings / box-shadow on full-width inputs are not clipped by overflow-y-auto
1696
+ "flex flex-col flex-1 min-h-0 gap-4 overflow-y-auto px-2 py-1",
1697
+ className
1698
+ ),
1699
+ children
1700
+ }
1701
+ ) })
1702
+ ]
1703
+ }
1704
+ ) });
1705
+ }
1706
+ var linkStyles = "cursor-pointer font-medium text-blue-600 underline-offset-4 hover:text-blue-700 hover:underline dark:text-blue-400 dark:hover:text-blue-300";
1707
+ var ALLOWED_SCHEMES = ["http:", "https:", "mailto:", "tel:", ""];
1708
+ function sanitizeHref(to) {
1709
+ const trimmed = to.trim();
1710
+ if (!trimmed) return "#";
1711
+ const hasScheme = /^[a-z][a-z0-9+.-]*:/i.test(trimmed);
1712
+ if (hasScheme) {
1713
+ const scheme = trimmed.split(":")[0];
1714
+ if (scheme && !ALLOWED_SCHEMES.includes(`${scheme.toLowerCase()}:`)) {
1715
+ return "#";
1716
+ }
1717
+ }
1718
+ return trimmed;
1719
+ }
1720
+ function Link({ className, external, to, ...props }) {
1721
+ const href = sanitizeHref(to);
1722
+ if (external) {
1723
+ return /* @__PURE__ */ jsx(
1724
+ "a",
1725
+ {
1726
+ href,
1727
+ target: "_blank",
1728
+ rel: "noopener noreferrer",
1729
+ className: cn(linkStyles, className),
1730
+ ...props
1731
+ }
1732
+ );
1733
+ }
1734
+ return /* @__PURE__ */ jsx("a", { href, className: cn(linkStyles, className), ...props });
1735
+ }
1736
+ var DEFAULT_TRANSLATIONS2 = {
1737
+ triggerLabel: "Select options",
1738
+ searchPlaceholder: "Search...",
1739
+ noOptionsText: "No options",
1740
+ removeOptionAriaLabel: "Remove"
1741
+ };
1742
+ function MultiSelect({
1743
+ value,
1744
+ onValueChange,
1745
+ options,
1746
+ disabled = false,
1747
+ className,
1748
+ "aria-label": ariaLabel,
1749
+ showSelectedTags = false,
1750
+ translations
1751
+ }) {
1752
+ const t = { ...DEFAULT_TRANSLATIONS2, ...translations };
1753
+ const insideModalScrollLock = useInsideModalScrollLock();
1754
+ const [search, setSearch] = React6.useState("");
1755
+ const selectedSet = React6.useMemo(() => new Set(value), [value]);
1756
+ const labelByValue = React6.useMemo(() => {
1757
+ const map = /* @__PURE__ */ new Map();
1758
+ for (const opt of options) map.set(opt.value, opt.label);
1759
+ return map;
1760
+ }, [options]);
1761
+ const filteredOptions = React6.useMemo(() => {
1762
+ const q = search.trim().toLowerCase();
1763
+ if (!q) return options;
1764
+ return options.filter((opt) => opt.label.toLowerCase().includes(q));
1765
+ }, [options, search]);
1766
+ const toggle = (optionValue, checked) => {
1767
+ if (checked) {
1768
+ onValueChange([...value, optionValue]);
1769
+ return;
1770
+ }
1771
+ onValueChange(value.filter((item) => item !== optionValue));
1772
+ };
1773
+ return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", className), children: [
1774
+ showSelectedTags && value.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: value.map((optionValue) => {
1775
+ const label = labelByValue.get(optionValue) ?? optionValue;
1776
+ return /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "gap-1 pr-1 font-normal", children: [
1777
+ label,
1778
+ !disabled ? /* @__PURE__ */ jsx(
1779
+ "button",
1780
+ {
1781
+ type: "button",
1782
+ className: "rounded-full p-0.5 hover:bg-muted-foreground/20",
1783
+ "aria-label": `${t.removeOptionAriaLabel} ${label}`,
1784
+ onClick: () => toggle(optionValue, false),
1785
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
1786
+ }
1787
+ ) : null
1788
+ ] }, optionValue);
1789
+ }) }) : null,
1790
+ /* @__PURE__ */ jsxs(DropdownMenu, { modal: false, children: [
1791
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1792
+ Button,
1793
+ {
1794
+ type: "button",
1795
+ variant: "outline",
1796
+ className: "w-full justify-between",
1797
+ "aria-label": ariaLabel ?? t.triggerLabel,
1798
+ disabled,
1799
+ children: [
1800
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
1801
+ /* @__PURE__ */ jsx(CheckSquare, { className: "h-4 w-4" }),
1802
+ t.triggerLabel
1803
+ ] }),
1804
+ !showSelectedTags && value.length > 0 ? /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: value.length }) : null
1805
+ ]
1806
+ }
1807
+ ) }),
1808
+ /* @__PURE__ */ jsxs(
1809
+ DropdownMenuContent,
1810
+ {
1811
+ align: "start",
1812
+ portalled: !insideModalScrollLock,
1813
+ className: "z-120 flex w-(--radix-dropdown-menu-trigger-width) min-w-[16rem] flex-col overflow-hidden p-0",
1814
+ children: [
1815
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 px-1 pb-2 pt-1", children: /* @__PURE__ */ jsx(
1816
+ Input,
1817
+ {
1818
+ value: search,
1819
+ onChange: (event) => setSearch(event.target.value),
1820
+ placeholder: t.searchPlaceholder,
1821
+ "aria-label": t.searchPlaceholder
1822
+ }
1823
+ ) }),
1824
+ /* @__PURE__ */ jsx(
1825
+ DropdownScrollableList,
1826
+ {
1827
+ grow: false,
1828
+ scrollAreaClassName: "max-h-52 overflow-y-auto",
1829
+ scrollKey: `${filteredOptions.length}:${search}`,
1830
+ children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-1.5 text-sm text-muted-foreground", children: t.noOptionsText }) : filteredOptions.map((option) => {
1831
+ const checked = selectedSet.has(option.value);
1832
+ return /* @__PURE__ */ jsxs(
1833
+ DropdownMenuItem,
1834
+ {
1835
+ onSelect: (event) => {
1836
+ event.preventDefault();
1837
+ toggle(option.value, !checked);
1838
+ },
1839
+ children: [
1840
+ /* @__PURE__ */ jsx(Checkbox, { checked }),
1841
+ option.label
1842
+ ]
1843
+ },
1844
+ option.value
1845
+ );
1846
+ })
1847
+ }
1848
+ )
1849
+ ]
1850
+ }
1851
+ )
1852
+ ] })
1853
+ ] });
1854
+ }
1855
+ var ScrollArea = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1856
+ ScrollAreaPrimitive.Root,
1857
+ {
1858
+ ref,
1859
+ className: cn("relative overflow-hidden", className),
1860
+ ...props,
1861
+ children: [
1862
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
1863
+ /* @__PURE__ */ jsx(ScrollBar, {}),
1864
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
1865
+ ]
1866
+ }
1867
+ ));
1868
+ ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
1869
+ var ScrollBar = React6.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx(
1870
+ ScrollAreaPrimitive.ScrollAreaScrollbar,
1871
+ {
1872
+ ref,
1873
+ orientation,
1874
+ className: cn(
1875
+ "flex touch-none select-none transition-colors",
1876
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
1877
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
1878
+ className
1879
+ ),
1880
+ ...props,
1881
+ children: /* @__PURE__ */ jsx(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
1882
+ }
1883
+ ));
1884
+ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
1885
+
1886
+ // src/components/ui/select-search/index.ts
1887
+ var SEARCHABLE_SELECT_MIN_OPTIONS = 8;
1888
+ function filterSelectOptions(options, query) {
1889
+ const q = query.trim().toLowerCase();
1890
+ if (!q) return options;
1891
+ return options.filter((option) => option.label.toLowerCase().includes(q));
1892
+ }
1893
+ function isSelectSearchable(optionCount, searchable) {
1894
+ if (searchable === true) return true;
1895
+ if (searchable === false) return false;
1896
+ return optionCount >= SEARCHABLE_SELECT_MIN_OPTIONS;
1897
+ }
1898
+ var DEFAULT_TRANSLATIONS3 = {
1899
+ searchPlaceholder: "Search\u2026",
1900
+ noOptionsText: "No options"
1901
+ };
1902
+ function Select({
1903
+ value,
1904
+ onValueChange,
1905
+ options,
1906
+ placeholder = "",
1907
+ disabled = false,
1908
+ className,
1909
+ triggerClassName,
1910
+ searchable,
1911
+ translations,
1912
+ "aria-label": ariaLabel
1913
+ }) {
1914
+ const t = { ...DEFAULT_TRANSLATIONS3, ...translations };
1915
+ const insideModalScrollLock = useInsideModalScrollLock();
1916
+ const [open, setOpen] = React6.useState(false);
1917
+ const [search, setSearch] = React6.useState("");
1918
+ const showSearch = isSelectSearchable(options.length, searchable);
1919
+ const filteredOptions = React6.useMemo(
1920
+ () => showSearch ? filterSelectOptions(options, search) : options,
1921
+ [options, search, showSearch]
1922
+ );
1923
+ const selectedOption = options.find((opt) => opt.value === value);
1924
+ const displayValue = selectedOption?.label ?? placeholder;
1925
+ const handleOpenChange = (nextOpen) => {
1926
+ setOpen(nextOpen);
1927
+ if (!nextOpen) setSearch("");
1928
+ };
1929
+ return /* @__PURE__ */ jsxs(DropdownMenu, { modal: false, open, onOpenChange: handleOpenChange, children: [
1930
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1931
+ "button",
1932
+ {
1933
+ type: "button",
1934
+ role: "combobox",
1935
+ "aria-expanded": open,
1936
+ "aria-label": ariaLabel,
1937
+ "aria-haspopup": "listbox",
1938
+ disabled,
1939
+ className: cn(
1940
+ controlBase,
1941
+ controlFocus,
1942
+ "flex h-9 w-full cursor-pointer items-center justify-between px-3 py-2 text-sm",
1943
+ "hover:bg-accent/40 disabled:pointer-events-none disabled:opacity-50",
1944
+ !value && "text-muted-foreground",
1945
+ triggerClassName,
1946
+ className
1947
+ ),
1948
+ children: [
1949
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-left", children: displayValue }),
1950
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "ml-2 h-4 w-4 shrink-0 text-muted-foreground" })
1951
+ ]
1952
+ }
1953
+ ) }),
1954
+ /* @__PURE__ */ jsxs(
1955
+ DropdownMenuContent,
1956
+ {
1957
+ align: "start",
1958
+ sideOffset: 0,
1959
+ portalled: !insideModalScrollLock,
1960
+ className: "z-[120] flex min-w-(--radix-dropdown-menu-trigger-width) flex-col overflow-hidden p-0",
1961
+ onCloseAutoFocus: (e) => e.preventDefault(),
1962
+ children: [
1963
+ showSearch ? /* @__PURE__ */ jsx(
1964
+ DropdownSelectSearchInput,
1965
+ {
1966
+ value: search,
1967
+ onChange: setSearch,
1968
+ placeholder: t.searchPlaceholder,
1969
+ autoFocus: open
1970
+ }
1971
+ ) : null,
1972
+ /* @__PURE__ */ jsx(
1973
+ DropdownScrollableList,
1974
+ {
1975
+ grow: false,
1976
+ scrollAreaClassName: cn(
1977
+ "overflow-y-auto overscroll-y-contain p-1",
1978
+ dropdownMenuSelectOptionsMaxHeightClassName
1979
+ ),
1980
+ scrollKey: `${filteredOptions.length}-${open ? 1 : 0}-${search}`,
1981
+ children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-1.5 text-sm text-muted-foreground", children: t.noOptionsText }) : filteredOptions.map((opt) => /* @__PURE__ */ jsx(
1982
+ DropdownMenuItem,
1983
+ {
1984
+ onClick: () => {
1985
+ onValueChange(opt.value);
1986
+ setOpen(false);
1987
+ setSearch("");
1988
+ },
1989
+ children: opt.label
1990
+ },
1991
+ opt.value
1992
+ ))
1993
+ }
1994
+ )
1995
+ ]
1996
+ }
1997
+ )
1998
+ ] });
1999
+ }
2000
+ function ChevronDownIcon({ className, ...props }) {
2001
+ return /* @__PURE__ */ jsxs(
2002
+ "svg",
2003
+ {
2004
+ xmlns: "http://www.w3.org/2000/svg",
2005
+ width: "24",
2006
+ height: "24",
2007
+ viewBox: "0 0 24 24",
2008
+ fill: "none",
2009
+ stroke: "currentColor",
2010
+ strokeWidth: "2",
2011
+ strokeLinecap: "round",
2012
+ strokeLinejoin: "round",
2013
+ className,
2014
+ "aria-hidden": "true",
2015
+ ...props,
2016
+ children: [
2017
+ /* @__PURE__ */ jsx("title", { children: "Chevron down" }),
2018
+ /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" })
2019
+ ]
2020
+ }
2021
+ );
2022
+ }
2023
+ var Separator = React6.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx(
2024
+ SeparatorPrimitive.Root,
2025
+ {
2026
+ ref,
2027
+ decorative,
2028
+ orientation,
2029
+ className: cn(
2030
+ "shrink-0 bg-border",
2031
+ orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
2032
+ className
2033
+ ),
2034
+ ...props
2035
+ }
2036
+ ));
2037
+ Separator.displayName = SeparatorPrimitive.Root.displayName;
2038
+ var Switch = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2039
+ SwitchPrimitive.Root,
2040
+ {
2041
+ ref,
2042
+ "data-slot": "switch",
2043
+ className: cn(
2044
+ "peer inline-flex h-[22px] w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-[var(--shadow-surface)] transition-colors",
2045
+ controlFocus,
2046
+ "disabled:cursor-not-allowed disabled:opacity-50",
2047
+ "data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
2048
+ className
2049
+ ),
2050
+ ...props,
2051
+ children: /* @__PURE__ */ jsx(
2052
+ SwitchPrimitive.Thumb,
2053
+ {
2054
+ "data-slot": "switch-thumb",
2055
+ className: cn(
2056
+ "pointer-events-none block size-[18px] rounded-full bg-background shadow-sm ring-0 transition-transform",
2057
+ "data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-0.5"
2058
+ )
2059
+ }
2060
+ )
2061
+ }
2062
+ ));
2063
+ Switch.displayName = SwitchPrimitive.Root.displayName;
2064
+ var Table = React6.forwardRef(
2065
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx("table", { ref, className: cn("w-full caption-bottom text-sm", className), ...props }) })
2066
+ );
2067
+ Table.displayName = "Table";
2068
+ var TableHeader = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2069
+ "thead",
2070
+ {
2071
+ ref,
2072
+ className: cn("[&_tr]:border-border/40 [&_tr]:border-b", className),
2073
+ ...props
2074
+ }
2075
+ ));
2076
+ TableHeader.displayName = "TableHeader";
2077
+ var TableBody = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props }));
2078
+ TableBody.displayName = "TableBody";
2079
+ var TableFooter = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2080
+ "tfoot",
2081
+ {
2082
+ ref,
2083
+ className: cn(
2084
+ "border-border/40 border-t bg-muted/40 font-medium [&>tr]:last:border-b-0",
2085
+ className
2086
+ ),
2087
+ ...props
2088
+ }
2089
+ ));
2090
+ TableFooter.displayName = "TableFooter";
2091
+ var TableRow = React6.forwardRef(
2092
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2093
+ "tr",
2094
+ {
2095
+ ref,
2096
+ className: cn(
2097
+ "border-border/40 border-b transition-colors hover:bg-muted/40 data-[state=selected]:bg-muted/60",
2098
+ className
2099
+ ),
2100
+ ...props
2101
+ }
2102
+ )
2103
+ );
2104
+ TableRow.displayName = "TableRow";
2105
+ var TableHead = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2106
+ "th",
2107
+ {
2108
+ ref,
2109
+ className: cn(
2110
+ "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
2111
+ className
2112
+ ),
2113
+ ...props
2114
+ }
2115
+ ));
2116
+ TableHead.displayName = "TableHead";
2117
+ var TableCell = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2118
+ "td",
2119
+ {
2120
+ ref,
2121
+ className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className),
2122
+ ...props
2123
+ }
2124
+ ));
2125
+ TableCell.displayName = "TableCell";
2126
+ var TableCaption = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props }));
2127
+ TableCaption.displayName = "TableCaption";
2128
+ function Tabs({ className, ...props }) {
2129
+ return /* @__PURE__ */ jsx(
2130
+ TabsPrimitive.Root,
2131
+ {
2132
+ "data-slot": "tabs",
2133
+ className: cn("flex flex-col gap-2", className),
2134
+ ...props
2135
+ }
2136
+ );
2137
+ }
2138
+ function TabsList({ className, ...props }) {
2139
+ return /* @__PURE__ */ jsx(
2140
+ TabsPrimitive.List,
2141
+ {
2142
+ "data-slot": "tabs-list",
2143
+ className: cn(
2144
+ "inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
2145
+ className
2146
+ ),
2147
+ ...props
2148
+ }
2149
+ );
2150
+ }
2151
+ function TabsTrigger({
2152
+ className,
2153
+ ...props
2154
+ }) {
2155
+ return /* @__PURE__ */ jsx(
2156
+ TabsPrimitive.Trigger,
2157
+ {
2158
+ "data-slot": "tabs-trigger",
2159
+ className: cn(
2160
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all cursor-pointer",
2161
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2162
+ "disabled:pointer-events-none disabled:opacity-50",
2163
+ "data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
2164
+ className
2165
+ ),
2166
+ ...props
2167
+ }
2168
+ );
2169
+ }
2170
+ function TabsContent({
2171
+ className,
2172
+ ...props
2173
+ }) {
2174
+ return /* @__PURE__ */ jsx(
2175
+ TabsPrimitive.Content,
2176
+ {
2177
+ "data-slot": "tabs-content",
2178
+ className: cn(
2179
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2180
+ className
2181
+ ),
2182
+ ...props
2183
+ }
2184
+ );
2185
+ }
2186
+ var Textarea = React6.forwardRef(
2187
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2188
+ "textarea",
2189
+ {
2190
+ ref,
2191
+ "data-slot": "textarea",
2192
+ className: cn(
2193
+ controlBase,
2194
+ controlFocus,
2195
+ controlInvalid,
2196
+ "placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground",
2197
+ "flex min-h-[96px] w-full min-w-0 px-3 py-2 text-base md:text-sm",
2198
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
2199
+ className
2200
+ ),
2201
+ ...props
2202
+ }
2203
+ )
2204
+ );
2205
+ Textarea.displayName = "Textarea";
2206
+ var TooltipProvider = TooltipPrimitive.Provider;
2207
+ function Tooltip({
2208
+ content,
2209
+ children,
2210
+ side = "top",
2211
+ align = "center",
2212
+ delayDuration = 400,
2213
+ closeDelay = 100
2214
+ }) {
2215
+ const [open, setOpen] = React6.useState(false);
2216
+ const openTimeoutRef = React6.useRef(null);
2217
+ const closeTimeoutRef = React6.useRef(null);
2218
+ const clearOpenTimeout = React6.useCallback(() => {
2219
+ if (openTimeoutRef.current !== null) {
2220
+ window.clearTimeout(openTimeoutRef.current);
2221
+ openTimeoutRef.current = null;
2222
+ }
2223
+ }, []);
2224
+ const clearCloseTimeout = React6.useCallback(() => {
2225
+ if (closeTimeoutRef.current !== null) {
2226
+ window.clearTimeout(closeTimeoutRef.current);
2227
+ closeTimeoutRef.current = null;
2228
+ }
2229
+ }, []);
2230
+ const handleOpenChange = React6.useCallback(
2231
+ (next) => {
2232
+ if (!next) {
2233
+ clearOpenTimeout();
2234
+ clearCloseTimeout();
2235
+ setOpen(false);
2236
+ }
2237
+ },
2238
+ [clearCloseTimeout, clearOpenTimeout]
2239
+ );
2240
+ const handlePointerEnter = React6.useCallback(() => {
2241
+ clearCloseTimeout();
2242
+ clearOpenTimeout();
2243
+ openTimeoutRef.current = window.setTimeout(() => {
2244
+ setOpen(true);
2245
+ }, delayDuration);
2246
+ }, [clearCloseTimeout, clearOpenTimeout, delayDuration]);
2247
+ const handlePointerLeave = React6.useCallback(() => {
2248
+ clearOpenTimeout();
2249
+ clearCloseTimeout();
2250
+ if (closeDelay === 0) {
2251
+ setOpen(false);
2252
+ return;
2253
+ }
2254
+ closeTimeoutRef.current = window.setTimeout(() => {
2255
+ setOpen(false);
2256
+ }, closeDelay);
2257
+ }, [clearCloseTimeout, clearOpenTimeout, closeDelay]);
2258
+ React6.useEffect(
2259
+ () => () => {
2260
+ clearOpenTimeout();
2261
+ clearCloseTimeout();
2262
+ },
2263
+ [clearCloseTimeout, clearOpenTimeout]
2264
+ );
2265
+ return /* @__PURE__ */ jsxs(TooltipPrimitive.Root, { open, onOpenChange: handleOpenChange, children: [
2266
+ /* @__PURE__ */ jsx(
2267
+ TooltipPrimitive.Trigger,
2268
+ {
2269
+ asChild: true,
2270
+ onPointerEnter: handlePointerEnter,
2271
+ onPointerLeave: handlePointerLeave,
2272
+ children
2273
+ }
2274
+ ),
2275
+ /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
2276
+ TooltipPrimitive.Content,
2277
+ {
2278
+ side,
2279
+ align,
2280
+ sideOffset: 6,
2281
+ onPointerEnter: handlePointerEnter,
2282
+ onPointerLeave: handlePointerLeave,
2283
+ className: cn(
2284
+ surfaceOverlay,
2285
+ "z-110 max-w-xs px-3 py-2 text-sm outline-none",
2286
+ "animate-in fade-in-0 zoom-in-95",
2287
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
2288
+ ),
2289
+ children: content
2290
+ }
2291
+ ) })
2292
+ ] });
2293
+ }
2294
+ var headingVariants = cva("font-semibold tracking-tight text-foreground", {
2295
+ variants: {
2296
+ level: {
2297
+ h1: "text-3xl font-bold",
2298
+ h2: "text-2xl",
2299
+ h3: "text-xl",
2300
+ h4: "text-lg"
2301
+ }
2302
+ },
2303
+ defaultVariants: {
2304
+ level: "h1"
2305
+ }
2306
+ });
2307
+ var paragraphVariants = cva("text-muted-foreground leading-relaxed", {
2308
+ variants: {
2309
+ size: {
2310
+ default: "text-base",
2311
+ sm: "text-sm",
2312
+ lg: "text-lg"
2313
+ }
2314
+ },
2315
+ defaultVariants: {
2316
+ size: "default"
2317
+ }
2318
+ });
2319
+ var Heading = React6.forwardRef(
2320
+ ({ className, level, as, ...props }, ref) => {
2321
+ const Component = as || (level === "h1" ? "h1" : level === "h2" ? "h2" : level === "h3" ? "h3" : "h4");
2322
+ return /* @__PURE__ */ jsx(
2323
+ Component,
2324
+ {
2325
+ ref,
2326
+ className: cn(headingVariants({ level: level || as }), className),
2327
+ ...props
2328
+ }
2329
+ );
2330
+ }
2331
+ );
2332
+ Heading.displayName = "Heading";
2333
+ var Paragraph = React6.forwardRef(
2334
+ ({ className, size, ...props }, ref) => {
2335
+ return /* @__PURE__ */ jsx("p", { ref, className: cn(paragraphVariants({ size }), className), ...props });
2336
+ }
2337
+ );
2338
+ Paragraph.displayName = "Paragraph";
2339
+ var H3 = React6.forwardRef(
2340
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(Heading, { ref, level: "h3", as: "h3", className, ...props })
2341
+ );
2342
+ H3.displayName = "H3";
2343
+ var DEFAULT_TRANSLATIONS4 = {
2344
+ imageAlt: "Image",
2345
+ dropHintText: "Drag and drop an image here, or click to choose a file.",
2346
+ chooseImageText: "Choose image",
2347
+ chooseFileText: "Choose file",
2348
+ removeText: "Remove",
2349
+ removeExistingImageText: "Remove existing image"
2350
+ };
2351
+ function UploadDropzone(props) {
2352
+ const isFile = props.variant === "file";
2353
+ const inputId = useId();
2354
+ const removeExistingLabelId = useId();
2355
+ const pickerDisabled = isFile && props.disabled;
2356
+ const t = { ...DEFAULT_TRANSLATIONS4, ...props.translations };
2357
+ const inputRef = useRef(null);
2358
+ const [isDragging, setIsDragging] = useState(false);
2359
+ const [previewUrl, setPreviewUrl] = useState(null);
2360
+ useEffect(() => {
2361
+ if (isFile) {
2362
+ if (!props.value || !props.value.type.startsWith("video/")) {
2363
+ setPreviewUrl(null);
2364
+ return;
2365
+ }
2366
+ const nextUrl2 = URL.createObjectURL(props.value);
2367
+ setPreviewUrl(nextUrl2);
2368
+ return () => URL.revokeObjectURL(nextUrl2);
2369
+ }
2370
+ if (!props.value) {
2371
+ setPreviewUrl(null);
2372
+ return;
2373
+ }
2374
+ const nextUrl = URL.createObjectURL(props.value);
2375
+ setPreviewUrl(nextUrl);
2376
+ return () => URL.revokeObjectURL(nextUrl);
2377
+ }, [isFile, props.value]);
2378
+ const handleFile = (file) => {
2379
+ if (!file) return;
2380
+ if (props.maxSizeBytes != null && file.size > props.maxSizeBytes) {
2381
+ props.onFileTooLarge?.();
2382
+ return;
2383
+ }
2384
+ if (isFile) {
2385
+ if (props.disabled) return;
2386
+ props.onChange(file);
2387
+ return;
2388
+ }
2389
+ if (!file.type.startsWith("image/")) return;
2390
+ props.onChange(file);
2391
+ props.onRemoveExistingImageChange?.(false);
2392
+ };
2393
+ const displayedImage = !isFile && (previewUrl ?? (!props.removeExistingImage ? props.existingImageUrl : void 0));
2394
+ const dashedClasses = cn(
2395
+ "block rounded-xl border-2 border-dashed border-border/55 p-4 transition-colors",
2396
+ pickerDisabled && "pointer-events-none opacity-50",
2397
+ !pickerDisabled && "cursor-pointer hover:border-primary/50 hover:bg-muted/15",
2398
+ isDragging ? "border-primary/70 bg-primary/5" : void 0
2399
+ );
2400
+ const chooseLabel = isFile ? t.chooseFileText : t.chooseImageText;
2401
+ return /* @__PURE__ */ jsxs("div", { className: cn("space-y-3", isFile ? props.className : void 0), children: [
2402
+ /* @__PURE__ */ jsxs(
2403
+ "label",
2404
+ {
2405
+ htmlFor: pickerDisabled ? void 0 : inputId,
2406
+ className: dashedClasses,
2407
+ onDragOver: (event) => {
2408
+ event.preventDefault();
2409
+ if (pickerDisabled) return;
2410
+ setIsDragging(true);
2411
+ },
2412
+ onDragLeave: () => setIsDragging(false),
2413
+ onDrop: (event) => {
2414
+ event.preventDefault();
2415
+ setIsDragging(false);
2416
+ if (pickerDisabled) return;
2417
+ const file = event.dataTransfer.files?.[0] ?? null;
2418
+ handleFile(file);
2419
+ },
2420
+ children: [
2421
+ /* @__PURE__ */ jsx(
2422
+ "input",
2423
+ {
2424
+ id: inputId,
2425
+ ref: inputRef,
2426
+ type: "file",
2427
+ accept: isFile ? props.accept : "image/*",
2428
+ disabled: pickerDisabled || void 0,
2429
+ className: "sr-only",
2430
+ onChange: (event) => handleFile(event.target.files?.[0] ?? null)
2431
+ }
2432
+ ),
2433
+ isFile ? /* @__PURE__ */ jsxs("div", { className: "mb-3 flex min-h-28 flex-col items-center justify-center gap-2 rounded-lg border border-border/45 bg-muted/20 px-3 py-4 text-center", children: [
2434
+ previewUrl ? /* @__PURE__ */ jsx(
2435
+ "video",
2436
+ {
2437
+ src: previewUrl,
2438
+ controls: true,
2439
+ className: "max-h-44 w-full rounded-lg border border-border/45 bg-foreground"
2440
+ }
2441
+ ) : /* @__PURE__ */ jsx(FileText, { className: "h-8 w-8 shrink-0 text-muted-foreground", "aria-hidden": true }),
2442
+ props.value ? /* @__PURE__ */ jsx("p", { className: "line-clamp-2 w-full break-all text-sm font-medium", children: props.value.name }) : null
2443
+ ] }) : displayedImage ? /* @__PURE__ */ jsx(
2444
+ "img",
2445
+ {
2446
+ src: displayedImage,
2447
+ alt: t.imageAlt,
2448
+ className: "mb-3 h-44 w-full rounded-lg border border-border/45 object-cover"
2449
+ }
2450
+ ) : /* @__PURE__ */ jsx("div", { className: "mb-3 flex h-32 items-center justify-center rounded-lg border border-border/45 bg-muted/20", children: /* @__PURE__ */ jsx(ImagePlus, { className: "h-8 w-8 text-muted-foreground", "aria-hidden": true }) }),
2451
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [
2452
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t.dropHintText }),
2453
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
2454
+ /* @__PURE__ */ jsxs(
2455
+ Button,
2456
+ {
2457
+ type: "button",
2458
+ size: "sm",
2459
+ variant: "outline",
2460
+ disabled: pickerDisabled || void 0,
2461
+ onClick: (event) => {
2462
+ event.preventDefault();
2463
+ inputRef.current?.click();
2464
+ },
2465
+ children: [
2466
+ /* @__PURE__ */ jsx(UploadCloud, { className: "mr-2 h-4 w-4", "aria-hidden": true }),
2467
+ chooseLabel
2468
+ ]
2469
+ }
2470
+ ),
2471
+ props.value ? /* @__PURE__ */ jsx(
2472
+ Button,
2473
+ {
2474
+ type: "button",
2475
+ size: "sm",
2476
+ variant: "outline",
2477
+ disabled: pickerDisabled || void 0,
2478
+ onClick: (event) => {
2479
+ event.preventDefault();
2480
+ event.stopPropagation();
2481
+ props.onChange(null);
2482
+ },
2483
+ children: t.removeText
2484
+ }
2485
+ ) : null
2486
+ ] })
2487
+ ] })
2488
+ ]
2489
+ }
2490
+ ),
2491
+ !isFile && props.existingImageUrl && props.onRemoveExistingImageChange && t.removeExistingImageText ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between rounded-lg border border-border/45 bg-muted/15 px-3 py-2", children: [
2492
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", id: removeExistingLabelId, children: t.removeExistingImageText }),
2493
+ /* @__PURE__ */ jsx(
2494
+ Checkbox,
2495
+ {
2496
+ "aria-labelledby": removeExistingLabelId,
2497
+ checked: props.removeExistingImage,
2498
+ onCheckedChange: (checked) => props.onRemoveExistingImageChange?.(checked === true)
2499
+ }
2500
+ )
2501
+ ] }) : null
2502
+ ] });
2503
+ }
2504
+
2505
+ export { Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, AvatarFallback, AvatarImage, Badge, Calendar, Checkbox, ConfirmDialog, DatePicker, DateRangePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownScrollableList, DropdownSelectSearchInput, Form, FormControl, FormDescription, FormDrawer, FormField, FormItem, FormLabel, FormMessage, H3, Heading, Label, Link, MultiSelect, Paragraph, Popover, PopoverContent, PopoverTrigger, SEARCHABLE_SELECT_MIN_OPTIONS, ScrollArea, ScrollBar, Select, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Tooltip, TooltipProvider, UploadDropzone, badgeVariants, dropdownMenuSelectOptionsMaxHeightClassName, filterSelectOptions, headingVariants, isSelectSearchable, linkStyles, paragraphVariants, useFormField };
2506
+ //# sourceMappingURL=chunk-PLSNCPEC.js.map
2507
+ //# sourceMappingURL=chunk-PLSNCPEC.js.map