@kjaniec-dev/ui 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  var clsx = require('clsx');
4
4
  var tailwindMerge = require('tailwind-merge');
5
- var React18 = require('react');
5
+ var React52 = require('react');
6
6
  var classVarianceAuthority = require('class-variance-authority');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
 
@@ -24,7 +24,7 @@ function _interopNamespace(e) {
24
24
  return Object.freeze(n);
25
25
  }
26
26
 
27
- var React18__namespace = /*#__PURE__*/_interopNamespace(React18);
27
+ var React52__namespace = /*#__PURE__*/_interopNamespace(React52);
28
28
 
29
29
  // src/lib/cn.ts
30
30
  function cn(...inputs) {
@@ -60,7 +60,7 @@ var buttonVariants = classVarianceAuthority.cva(
60
60
  defaultVariants: { variant: "primary", size: "md" }
61
61
  }
62
62
  );
63
- var Button = React18__namespace.forwardRef(
63
+ var Button = React52__namespace.forwardRef(
64
64
  ({ className, variant, size, loading, leadingIcon, trailingIcon, children, disabled, ...props }, ref) => {
65
65
  return /* @__PURE__ */ jsxRuntime.jsxs(
66
66
  "button",
@@ -107,7 +107,7 @@ var badgeVariants = classVarianceAuthority.cva(
107
107
  defaultVariants: { variant: "neutral" }
108
108
  }
109
109
  );
110
- var Badge = React18__namespace.forwardRef(
110
+ var Badge = React52__namespace.forwardRef(
111
111
  ({ className, variant, dot, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("span", { ref, className: cn(badgeVariants({ variant }), className), ...props, children: [
112
112
  dot && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-current", "aria-hidden": true }),
113
113
  children
@@ -134,7 +134,7 @@ var iconColor = {
134
134
  warning: "text-warning",
135
135
  danger: "text-danger"
136
136
  };
137
- var Alert = React18__namespace.forwardRef(
137
+ var Alert = React52__namespace.forwardRef(
138
138
  ({ className, variant = "info", icon, title, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, role: "alert", className: cn(alertVariants({ variant }), className), ...props, children: [
139
139
  icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("shrink-0 mt-0.5 [&_svg]:h-[1.15rem] [&_svg]:w-[1.15rem]", iconColor[variant ?? "info"]), children: icon }),
140
140
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-foreground", children: [
@@ -144,7 +144,7 @@ var Alert = React18__namespace.forwardRef(
144
144
  ] })
145
145
  );
146
146
  Alert.displayName = "Alert";
147
- var Spinner = React18__namespace.forwardRef(
147
+ var Spinner = React52__namespace.forwardRef(
148
148
  ({ className, size = 24, style, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
149
149
  "span",
150
150
  {
@@ -161,7 +161,7 @@ var Spinner = React18__namespace.forwardRef(
161
161
  )
162
162
  );
163
163
  Spinner.displayName = "Spinner";
164
- var Progress = React18__namespace.forwardRef(
164
+ var Progress = React52__namespace.forwardRef(
165
165
  ({ className, value = 0, tone = "primary", barClassName, ...props }, ref) => {
166
166
  const pct = Math.max(0, Math.min(100, value));
167
167
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -191,14 +191,14 @@ var Progress = React18__namespace.forwardRef(
191
191
  }
192
192
  );
193
193
  Progress.displayName = "Progress";
194
- var Label = React18__namespace.forwardRef(
194
+ var Label = React52__namespace.forwardRef(
195
195
  ({ className, required, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("label", { ref, className: cn("text-[0.8rem] font-semibold text-foreground", className), ...props, children: [
196
196
  children,
197
197
  required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-danger", children: " *" })
198
198
  ] })
199
199
  );
200
200
  Label.displayName = "Label";
201
- var Hint = React18__namespace.forwardRef(
201
+ var Hint = React52__namespace.forwardRef(
202
202
  ({ className, error, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
203
203
  "span",
204
204
  {
@@ -209,17 +209,17 @@ var Hint = React18__namespace.forwardRef(
209
209
  )
210
210
  );
211
211
  Hint.displayName = "Hint";
212
- var Field = React18__namespace.forwardRef(
212
+ var Field = React52__namespace.forwardRef(
213
213
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col gap-1.5", className), ...props })
214
214
  );
215
215
  Field.displayName = "Field";
216
- var FormField = React18__namespace.forwardRef(
216
+ var FormField = React52__namespace.forwardRef(
217
217
  ({ className, label, hint, error, required, children, ...props }, ref) => {
218
- const id = React18__namespace.useId();
218
+ const id = React52__namespace.useId();
219
219
  const hintId = `${id}-hint`;
220
220
  const errorId = `${id}-error`;
221
- const child = React18__namespace.Children.only(children);
222
- const clonedChild = React18__namespace.cloneElement(child, {
221
+ const child = React52__namespace.Children.only(children);
222
+ const clonedChild = React52__namespace.cloneElement(child, {
223
223
  id: child.props.id ?? id,
224
224
  "aria-describedby": cn(
225
225
  hint && hintId,
@@ -238,9 +238,136 @@ var FormField = React18__namespace.forwardRef(
238
238
  }
239
239
  );
240
240
  FormField.displayName = "FormField";
241
+ var sizeDimensions = {
242
+ sm: 36,
243
+ md: 64,
244
+ lg: 96,
245
+ xl: 128
246
+ };
247
+ var defaultStrokeWidths = {
248
+ sm: 3.5,
249
+ md: 6,
250
+ lg: 8,
251
+ xl: 10
252
+ };
253
+ var textSizeClasses = {
254
+ sm: "text-[0.65rem] font-semibold leading-none",
255
+ md: "text-xs font-semibold leading-none",
256
+ lg: "text-base font-bold leading-none",
257
+ xl: "text-xl font-bold leading-none"
258
+ };
259
+ var toneClasses = {
260
+ primary: "text-primary stroke-current",
261
+ secondary: "text-secondary stroke-current",
262
+ success: "text-success stroke-current",
263
+ warning: "text-warning stroke-current",
264
+ danger: "text-danger stroke-current",
265
+ info: "text-info stroke-current"
266
+ };
267
+ var ProgressRing = React52__namespace.forwardRef(
268
+ ({
269
+ className,
270
+ style,
271
+ value = 0,
272
+ min = 0,
273
+ max = 100,
274
+ size = "md",
275
+ strokeWidth,
276
+ tone = "primary",
277
+ showValue = false,
278
+ formatValue,
279
+ trackClassName,
280
+ indicatorClassName,
281
+ children,
282
+ "aria-label": ariaLabel,
283
+ ...props
284
+ }, ref) => {
285
+ const range2 = max > min ? max - min : 100;
286
+ const clampedValue = Math.max(min, Math.min(max, value));
287
+ const percentage = Math.max(0, Math.min(100, (clampedValue - min) / range2 * 100));
288
+ const dimension = sizeDimensions[size];
289
+ const strokeWidthVal = strokeWidth ?? defaultStrokeWidths[size];
290
+ const radius = Math.max(0, (dimension - strokeWidthVal) / 2);
291
+ const circumference = 2 * Math.PI * radius;
292
+ const strokeDashoffset = circumference - percentage / 100 * circumference;
293
+ const computedAriaLabel = ariaLabel ?? (props["aria-labelledby"] ? void 0 : "Progress");
294
+ return /* @__PURE__ */ jsxRuntime.jsxs(
295
+ "div",
296
+ {
297
+ ref,
298
+ role: "progressbar",
299
+ "aria-label": computedAriaLabel,
300
+ "aria-valuenow": clampedValue,
301
+ "aria-valuemin": min,
302
+ "aria-valuemax": max,
303
+ className: cn("relative inline-flex items-center justify-center shrink-0", className),
304
+ style: { width: dimension, height: dimension, ...style },
305
+ ...props,
306
+ children: [
307
+ /* @__PURE__ */ jsxRuntime.jsxs(
308
+ "svg",
309
+ {
310
+ width: dimension,
311
+ height: dimension,
312
+ viewBox: `0 0 ${dimension} ${dimension}`,
313
+ className: "-rotate-90 transform",
314
+ children: [
315
+ /* @__PURE__ */ jsxRuntime.jsx(
316
+ "circle",
317
+ {
318
+ cx: dimension / 2,
319
+ cy: dimension / 2,
320
+ r: radius,
321
+ strokeWidth: strokeWidthVal,
322
+ className: cn("stroke-muted/30 fill-none", trackClassName)
323
+ }
324
+ ),
325
+ /* @__PURE__ */ jsxRuntime.jsx(
326
+ "circle",
327
+ {
328
+ cx: dimension / 2,
329
+ cy: dimension / 2,
330
+ r: radius,
331
+ strokeWidth: strokeWidthVal,
332
+ strokeDasharray: circumference,
333
+ strokeDashoffset,
334
+ strokeLinecap: percentage === 0 ? "butt" : "round",
335
+ className: cn(
336
+ "fill-none transition-[stroke-dashoffset,opacity] duration-500 ease-in-out",
337
+ percentage === 0 && "opacity-0",
338
+ toneClasses[tone],
339
+ indicatorClassName
340
+ )
341
+ }
342
+ )
343
+ ]
344
+ }
345
+ ),
346
+ (children || showValue) && /* @__PURE__ */ jsxRuntime.jsx(
347
+ "div",
348
+ {
349
+ className: cn(
350
+ "absolute inset-0 flex flex-col items-center justify-center text-center text-foreground p-1",
351
+ textSizeClasses[size]
352
+ ),
353
+ children: children ?? (formatValue ? formatValue(clampedValue, Math.round(percentage)) : `${Math.round(percentage)}%`)
354
+ }
355
+ )
356
+ ]
357
+ }
358
+ );
359
+ }
360
+ );
361
+ ProgressRing.displayName = "ProgressRing";
362
+ var ProgressRingField = React52__namespace.forwardRef(
363
+ ({ label, hint, error, required, fieldClassName, ...ringProps }, ref) => {
364
+ return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className: fieldClassName, children: /* @__PURE__ */ jsxRuntime.jsx(ProgressRing, { ref, "aria-label": ringProps["aria-label"] ?? label, ...ringProps }) });
365
+ }
366
+ );
367
+ ProgressRingField.displayName = "ProgressRingField";
241
368
  var baseField = "w-full font-sans text-sm text-foreground bg-surface border rounded-kj-md px-[0.85rem] transition-[border-color,box-shadow] duration-150 placeholder:text-muted-foreground focus:outline-none focus:border-ring focus:ring-[3px] focus:ring-ring/30 disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed";
242
- var Input = React18__namespace.forwardRef(
243
- ({ className, error, leadingIcon, style, ...props }, ref) => {
369
+ var Input = React52__namespace.forwardRef(
370
+ ({ className, error, leadingIcon, ...props }, ref) => {
244
371
  const field = /* @__PURE__ */ jsxRuntime.jsx(
245
372
  "input",
246
373
  {
@@ -264,7 +391,7 @@ var Input = React18__namespace.forwardRef(
264
391
  }
265
392
  );
266
393
  Input.displayName = "Input";
267
- var Textarea = React18__namespace.forwardRef(
394
+ var Textarea = React52__namespace.forwardRef(
268
395
  ({ className, error, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
269
396
  "textarea",
270
397
  {
@@ -281,14 +408,14 @@ var Textarea = React18__namespace.forwardRef(
281
408
  )
282
409
  );
283
410
  Textarea.displayName = "Textarea";
284
- var TextField = React18__namespace.forwardRef(
411
+ var TextField = React52__namespace.forwardRef(
285
412
  ({ label, hint, error, required, className, ...props }, ref) => {
286
413
  return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(Input, { ref, error: !!error, ...props }) });
287
414
  }
288
415
  );
289
416
  TextField.displayName = "TextField";
290
417
  var chevron = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E";
291
- var Select = React18__namespace.forwardRef(
418
+ var Select = React52__namespace.forwardRef(
292
419
  ({ className, error, style, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
293
420
  "select",
294
421
  {
@@ -316,15 +443,15 @@ var Select = React18__namespace.forwardRef(
316
443
  )
317
444
  );
318
445
  Select.displayName = "Select";
319
- var SelectField = React18__namespace.forwardRef(
446
+ var SelectField = React52__namespace.forwardRef(
320
447
  ({ label, hint, error, required, className, children, ...props }, ref) => {
321
448
  return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(Select, { ref, error: !!error, ...props, children }) });
322
449
  }
323
450
  );
324
451
  SelectField.displayName = "SelectField";
325
- var Checkbox = React18__namespace.forwardRef(
452
+ var Checkbox = React52__namespace.forwardRef(
326
453
  ({ className, label, id, ...props }, ref) => {
327
- const autoId = React18__namespace.useId();
454
+ const autoId = React52__namespace.useId();
328
455
  const inputId = id ?? autoId;
329
456
  return /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: cn("inline-flex items-center gap-2.5 cursor-pointer text-sm select-none", className), children: [
330
457
  /* @__PURE__ */ jsxRuntime.jsx("input", { ref, id: inputId, type: "checkbox", className: "peer sr-only", ...props }),
@@ -334,9 +461,9 @@ var Checkbox = React18__namespace.forwardRef(
334
461
  }
335
462
  );
336
463
  Checkbox.displayName = "Checkbox";
337
- var Radio = React18__namespace.forwardRef(
464
+ var Radio = React52__namespace.forwardRef(
338
465
  ({ className, label, id, ...props }, ref) => {
339
- const autoId = React18__namespace.useId();
466
+ const autoId = React52__namespace.useId();
340
467
  const inputId = id ?? autoId;
341
468
  return /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: cn("inline-flex items-center gap-2.5 cursor-pointer text-sm select-none", className), children: [
342
469
  /* @__PURE__ */ jsxRuntime.jsx("input", { ref, id: inputId, type: "radio", className: "peer sr-only", ...props }),
@@ -346,9 +473,9 @@ var Radio = React18__namespace.forwardRef(
346
473
  }
347
474
  );
348
475
  Radio.displayName = "Radio";
349
- var CheckboxField = React18__namespace.forwardRef(
476
+ var CheckboxField = React52__namespace.forwardRef(
350
477
  ({ label, hint, error, className, ...props }, ref) => {
351
- const id = React18__namespace.useId();
478
+ const id = React52__namespace.useId();
352
479
  const hintId = `${id}-hint`;
353
480
  const errorId = `${id}-error`;
354
481
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1 w-full", className), children: [
@@ -369,9 +496,9 @@ var CheckboxField = React18__namespace.forwardRef(
369
496
  }
370
497
  );
371
498
  CheckboxField.displayName = "CheckboxField";
372
- var Switch = React18__namespace.forwardRef(
499
+ var Switch = React52__namespace.forwardRef(
373
500
  ({ className, label, id, ...props }, ref) => {
374
- const autoId = React18__namespace.useId();
501
+ const autoId = React52__namespace.useId();
375
502
  const inputId = id ?? autoId;
376
503
  return /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: cn("inline-flex items-center gap-2.5 cursor-pointer text-sm select-none", className), children: [
377
504
  /* @__PURE__ */ jsxRuntime.jsx("input", { ref, id: inputId, type: "checkbox", role: "switch", className: "peer sr-only", ...props }),
@@ -381,19 +508,47 @@ var Switch = React18__namespace.forwardRef(
381
508
  }
382
509
  );
383
510
  Switch.displayName = "Switch";
384
- var Slider = React18__namespace.forwardRef(
385
- ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
386
- "input",
387
- {
388
- ref,
389
- type: "range",
390
- className: cn(
391
- "kj-slider w-full h-1.5 rounded-full bg-input appearance-none cursor-pointer",
392
- className
393
- ),
394
- ...props
395
- }
396
- )
511
+ var Slider = React52__namespace.forwardRef(
512
+ ({ className, style, value, defaultValue, min = 0, max = 100, onChange, ...props }, ref) => {
513
+ const [localValue, setLocalValue] = React52__namespace.useState(
514
+ Number(defaultValue ?? value ?? 50)
515
+ );
516
+ const isControlled = value !== void 0;
517
+ const currentVal = isControlled ? Number(value) : localValue;
518
+ const numMin = Number(min);
519
+ const numMax = Number(max);
520
+ const percentage = Math.min(
521
+ 100,
522
+ Math.max(0, (currentVal - numMin) / (numMax - numMin) * 100)
523
+ );
524
+ const handleChange = (e) => {
525
+ if (!isControlled) {
526
+ setLocalValue(Number(e.target.value));
527
+ }
528
+ onChange?.(e);
529
+ };
530
+ return /* @__PURE__ */ jsxRuntime.jsx(
531
+ "input",
532
+ {
533
+ ref,
534
+ type: "range",
535
+ value,
536
+ defaultValue,
537
+ min,
538
+ max,
539
+ onChange: handleChange,
540
+ style: {
541
+ background: `linear-gradient(to right, var(--kj-primary) ${percentage}%, var(--kj-border, rgba(120, 120, 128, 0.2)) ${percentage}%)`,
542
+ ...style
543
+ },
544
+ className: cn(
545
+ "kj-slider w-full h-1.5 rounded-full appearance-none cursor-pointer accent-primary",
546
+ className
547
+ ),
548
+ ...props
549
+ }
550
+ );
551
+ }
397
552
  );
398
553
  Slider.displayName = "Slider";
399
554
  var sliderThumbCSS = `
@@ -434,7 +589,47 @@ function Segmented({
434
589
  }
435
590
  );
436
591
  }
437
- var Card = React18__namespace.forwardRef(
592
+ function ToggleGroup({
593
+ options,
594
+ value,
595
+ onChange,
596
+ disabled,
597
+ className,
598
+ ...props
599
+ }) {
600
+ const toggle = (optionValue) => {
601
+ if (disabled) return;
602
+ const next = value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue];
603
+ onChange(next);
604
+ };
605
+ return /* @__PURE__ */ jsxRuntime.jsx(
606
+ "div",
607
+ {
608
+ role: "group",
609
+ className: cn("inline-flex gap-0.5 p-[3px] rounded-kj-md bg-muted", className),
610
+ ...props,
611
+ children: options.map((opt) => {
612
+ const active = value.includes(opt.value);
613
+ return /* @__PURE__ */ jsxRuntime.jsx(
614
+ "button",
615
+ {
616
+ type: "button",
617
+ "aria-pressed": active,
618
+ disabled,
619
+ onClick: () => toggle(opt.value),
620
+ className: cn(
621
+ "px-3.5 py-1.5 text-[0.82rem] font-semibold rounded-[calc(var(--kj-radius-md)-3px)] cursor-pointer transition-all duration-150 disabled:cursor-not-allowed disabled:opacity-50",
622
+ active ? "bg-surface text-foreground shadow-kj-xs" : "bg-transparent text-muted-foreground hover:text-foreground"
623
+ ),
624
+ children: opt.label
625
+ },
626
+ opt.value
627
+ );
628
+ })
629
+ }
630
+ );
631
+ }
632
+ var Card = React52__namespace.forwardRef(
438
633
  ({ as: Tag = "div", className, elevated, interactive, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
439
634
  Tag,
440
635
  {
@@ -450,23 +645,23 @@ var Card = React18__namespace.forwardRef(
450
645
  )
451
646
  );
452
647
  Card.displayName = "Card";
453
- var CardHeader = React18__namespace.forwardRef(
648
+ var CardHeader = React52__namespace.forwardRef(
454
649
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-[1.35rem] flex flex-col gap-1", className), ...props })
455
650
  );
456
651
  CardHeader.displayName = "CardHeader";
457
- var CardTitle = React18__namespace.forwardRef(
458
- ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("m-0 text-base font-bold tracking-[-0.01em]", className), ...props })
652
+ var CardTitle = React52__namespace.forwardRef(
653
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("m-0 text-base font-bold tracking-[-0.01em]", className), ...props, children })
459
654
  );
460
655
  CardTitle.displayName = "CardTitle";
461
- var CardDescription = React18__namespace.forwardRef(
656
+ var CardDescription = React52__namespace.forwardRef(
462
657
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("m-0 text-[0.85rem] text-muted-foreground", className), ...props })
463
658
  );
464
659
  CardDescription.displayName = "CardDescription";
465
- var CardContent = React18__namespace.forwardRef(
660
+ var CardContent = React52__namespace.forwardRef(
466
661
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("px-[1.35rem] pb-[1.35rem]", className), ...props })
467
662
  );
468
663
  CardContent.displayName = "CardContent";
469
- var CardFooter = React18__namespace.forwardRef(
664
+ var CardFooter = React52__namespace.forwardRef(
470
665
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
471
666
  "div",
472
667
  {
@@ -477,7 +672,7 @@ var CardFooter = React18__namespace.forwardRef(
477
672
  )
478
673
  );
479
674
  CardFooter.displayName = "CardFooter";
480
- var Stat = React18__namespace.forwardRef(
675
+ var Stat = React52__namespace.forwardRef(
481
676
  ({ className, label, value, delta, trend, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(Card, { ref, className: cn("p-[1.35rem] flex flex-col gap-2", className), ...props, children: [
482
677
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.78rem] font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: label }),
483
678
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[2rem] font-bold tracking-[-0.03em] tabular-nums leading-none", children: value }),
@@ -517,7 +712,7 @@ var avatarVariants = classVarianceAuthority.cva(
517
712
  defaultVariants: { size: "md", tone: "secondary" }
518
713
  }
519
714
  );
520
- var Avatar = React18__namespace.forwardRef(
715
+ var Avatar = React52__namespace.forwardRef(
521
716
  ({ className, size, tone, src, alt, status, children, ...props }, ref) => {
522
717
  const node = /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: cn(avatarVariants({ size, tone }), "overflow-hidden", className), ...props, children: src ? /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt, className: "h-full w-full object-cover" }) : children });
523
718
  if (!status) return node;
@@ -528,21 +723,21 @@ var Avatar = React18__namespace.forwardRef(
528
723
  }
529
724
  );
530
725
  Avatar.displayName = "Avatar";
531
- var AvatarGroup = React18__namespace.forwardRef(
726
+ var AvatarGroup = React52__namespace.forwardRef(
532
727
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex [&>*:not(:first-child)]:-ml-2.5", className), ...props })
533
728
  );
534
729
  AvatarGroup.displayName = "AvatarGroup";
535
- var TabsContext = React18__namespace.createContext(null);
730
+ var TabsContext = React52__namespace.createContext(null);
536
731
  function useTabs() {
537
- const ctx = React18__namespace.useContext(TabsContext);
732
+ const ctx = React52__namespace.useContext(TabsContext);
538
733
  if (!ctx) throw new Error("Tabs.* must be used within <Tabs>");
539
734
  return ctx;
540
735
  }
541
736
  function Tabs({ value, defaultValue, onValueChange, className, children, ...props }) {
542
- const [internal, setInternal] = React18__namespace.useState(defaultValue ?? "");
543
- const uid = React18__namespace.useId();
737
+ const [internal, setInternal] = React52__namespace.useState(defaultValue ?? "");
738
+ const uid = React52__namespace.useId();
544
739
  const current = value ?? internal;
545
- const setValue = React18__namespace.useCallback(
740
+ const setValue = React52__namespace.useCallback(
546
741
  (v) => {
547
742
  if (value === void 0) setInternal(v);
548
743
  onValueChange?.(v);
@@ -551,7 +746,7 @@ function Tabs({ value, defaultValue, onValueChange, className, children, ...prop
551
746
  );
552
747
  return /* @__PURE__ */ jsxRuntime.jsx(TabsContext.Provider, { value: { value: current, setValue, uid }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, ...props, children }) });
553
748
  }
554
- var TabsList = React18__namespace.forwardRef(
749
+ var TabsList = React52__namespace.forwardRef(
555
750
  ({ className, onKeyDown, ...props }, ref) => {
556
751
  const handleKeyDown = (e) => {
557
752
  const container = e.currentTarget;
@@ -598,7 +793,7 @@ var TabsList = React18__namespace.forwardRef(
598
793
  }
599
794
  );
600
795
  TabsList.displayName = "TabsList";
601
- var TabsTrigger = React18__namespace.forwardRef(
796
+ var TabsTrigger = React52__namespace.forwardRef(
602
797
  ({ className, value, children, ...props }, ref) => {
603
798
  const { value: current, setValue, uid } = useTabs();
604
799
  const active = current === value;
@@ -627,7 +822,7 @@ var TabsTrigger = React18__namespace.forwardRef(
627
822
  }
628
823
  );
629
824
  TabsTrigger.displayName = "TabsTrigger";
630
- var TabsContent = React18__namespace.forwardRef(
825
+ var TabsContent = React52__namespace.forwardRef(
631
826
  ({ className, value, ...props }, ref) => {
632
827
  const { value: current, uid } = useTabs();
633
828
  const active = current === value;
@@ -647,10 +842,10 @@ var TabsContent = React18__namespace.forwardRef(
647
842
  }
648
843
  );
649
844
  TabsContent.displayName = "TabsContent";
650
- var AccordionContext = React18__namespace.createContext(null);
845
+ var AccordionContext = React52__namespace.createContext(null);
651
846
  function Accordion({ type = "single", defaultValue = [], className, children, ...props }) {
652
- const [open, setOpen] = React18__namespace.useState(defaultValue);
653
- const toggle = React18__namespace.useCallback(
847
+ const [open, setOpen] = React52__namespace.useState(defaultValue);
848
+ const toggle = React52__namespace.useCallback(
654
849
  (v) => {
655
850
  setOpen((prev) => {
656
851
  const isOpen = prev.includes(v);
@@ -662,15 +857,15 @@ function Accordion({ type = "single", defaultValue = [], className, children, ..
662
857
  );
663
858
  return /* @__PURE__ */ jsxRuntime.jsx(AccordionContext.Provider, { value: { open, toggle }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("border border-border rounded-kj-lg overflow-hidden", className), ...props, children }) });
664
859
  }
665
- var ItemContext = React18__namespace.createContext("");
666
- var AccordionItem = React18__namespace.forwardRef(
860
+ var ItemContext = React52__namespace.createContext("");
861
+ var AccordionItem = React52__namespace.forwardRef(
667
862
  ({ className, value, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(ItemContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("border-t border-border first:border-t-0", className), ...props }) })
668
863
  );
669
864
  AccordionItem.displayName = "AccordionItem";
670
- var AccordionTrigger = React18__namespace.forwardRef(
865
+ var AccordionTrigger = React52__namespace.forwardRef(
671
866
  ({ className, children, ...props }, ref) => {
672
- const ctx = React18__namespace.useContext(AccordionContext);
673
- const value = React18__namespace.useContext(ItemContext);
867
+ const ctx = React52__namespace.useContext(AccordionContext);
868
+ const value = React52__namespace.useContext(ItemContext);
674
869
  const isOpen = ctx.open.includes(value);
675
870
  return /* @__PURE__ */ jsxRuntime.jsxs(
676
871
  "button",
@@ -707,10 +902,10 @@ var AccordionTrigger = React18__namespace.forwardRef(
707
902
  }
708
903
  );
709
904
  AccordionTrigger.displayName = "AccordionTrigger";
710
- var AccordionContent = React18__namespace.forwardRef(
905
+ var AccordionContent = React52__namespace.forwardRef(
711
906
  ({ className, children, ...props }, ref) => {
712
- const ctx = React18__namespace.useContext(AccordionContext);
713
- const value = React18__namespace.useContext(ItemContext);
907
+ const ctx = React52__namespace.useContext(AccordionContext);
908
+ const value = React52__namespace.useContext(ItemContext);
714
909
  const isOpen = ctx.open.includes(value);
715
910
  return /* @__PURE__ */ jsxRuntime.jsx(
716
911
  "div",
@@ -724,11 +919,11 @@ var AccordionContent = React18__namespace.forwardRef(
724
919
  }
725
920
  );
726
921
  AccordionContent.displayName = "AccordionContent";
727
- var MenuContext = React18__namespace.createContext(null);
922
+ var MenuContext = React52__namespace.createContext(null);
728
923
  function DropdownMenu({ children, className }) {
729
- const [open, setOpen] = React18__namespace.useState(false);
730
- const ref = React18__namespace.useRef(null);
731
- React18__namespace.useEffect(() => {
924
+ const [open, setOpen] = React52__namespace.useState(false);
925
+ const ref = React52__namespace.useRef(null);
926
+ React52__namespace.useEffect(() => {
732
927
  if (!open) return;
733
928
  const onDoc = (e) => {
734
929
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -743,11 +938,11 @@ function DropdownMenu({ children, className }) {
743
938
  }, [open]);
744
939
  return /* @__PURE__ */ jsxRuntime.jsx(MenuContext.Provider, { value: { open, setOpen }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("relative inline-block", className), children }) });
745
940
  }
746
- var DropdownMenuTrigger = React18__namespace.forwardRef(({ onClick, asChild, ...props }, ref) => {
747
- const ctx = React18__namespace.useContext(MenuContext);
941
+ var DropdownMenuTrigger = React52__namespace.forwardRef(({ onClick, asChild, ...props }, ref) => {
942
+ const ctx = React52__namespace.useContext(MenuContext);
748
943
  if (asChild) {
749
- const child = React18__namespace.Children.only(props.children);
750
- return React18__namespace.cloneElement(child, {
944
+ const child = React52__namespace.Children.only(props.children);
945
+ return React52__namespace.cloneElement(child, {
751
946
  ref,
752
947
  ...props,
753
948
  ...child.props,
@@ -777,9 +972,9 @@ var DropdownMenuTrigger = React18__namespace.forwardRef(({ onClick, asChild, ...
777
972
  });
778
973
  DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
779
974
  function DropdownMenuContent({ className, align = "start", children, ...props }) {
780
- const ctx = React18__namespace.useContext(MenuContext);
781
- const ref = React18__namespace.useRef(null);
782
- React18__namespace.useEffect(() => {
975
+ const ctx = React52__namespace.useContext(MenuContext);
976
+ const ref = React52__namespace.useRef(null);
977
+ React52__namespace.useEffect(() => {
783
978
  if (!ctx.open) return;
784
979
  const container = ref.current;
785
980
  if (container) {
@@ -826,9 +1021,9 @@ function DropdownMenuContent({ className, align = "start", children, ...props })
826
1021
  }
827
1022
  );
828
1023
  }
829
- var DropdownMenuItem = React18__namespace.forwardRef(
1024
+ var DropdownMenuItem = React52__namespace.forwardRef(
830
1025
  ({ className, danger, icon, children, onClick, ...props }, ref) => {
831
- const ctx = React18__namespace.useContext(MenuContext);
1026
+ const ctx = React52__namespace.useContext(MenuContext);
832
1027
  return /* @__PURE__ */ jsxRuntime.jsxs(
833
1028
  "button",
834
1029
  {
@@ -858,11 +1053,11 @@ DropdownMenuItem.displayName = "DropdownMenuItem";
858
1053
  function DropdownMenuSeparator({ className }) {
859
1054
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("h-px bg-border my-1.5", className), role: "separator" });
860
1055
  }
861
- var Breadcrumb = React18__namespace.forwardRef(
1056
+ var Breadcrumb = React52__namespace.forwardRef(
862
1057
  ({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("nav", { ref, "aria-label": "Breadcrumb", className: cn("flex items-center gap-1.5 text-[0.85rem] text-muted-foreground", className), ...props, children })
863
1058
  );
864
1059
  Breadcrumb.displayName = "Breadcrumb";
865
- var BreadcrumbItem = React18__namespace.forwardRef(
1060
+ var BreadcrumbItem = React52__namespace.forwardRef(
866
1061
  ({ className, current, children, ...props }, ref) => {
867
1062
  if (current) {
868
1063
  return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-current": "page", className: cn("text-foreground font-semibold", className), children });
@@ -909,7 +1104,7 @@ function Pagination({ page, pageCount, onPageChange, className }) {
909
1104
  /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Next", disabled: page >= pageCount, onClick: () => onPageChange(page + 1), children: /* @__PURE__ */ jsxRuntime.jsx(Chevron, { dir: "right" }) })
910
1105
  ] });
911
1106
  }
912
- var BottomNavigation = React18__namespace.forwardRef(
1107
+ var BottomNavigation = React52__namespace.forwardRef(
913
1108
  ({ className, items, showLabels = "always", fixed = true, ...props }, ref) => {
914
1109
  return /* @__PURE__ */ jsxRuntime.jsx(
915
1110
  "nav",
@@ -981,27 +1176,27 @@ var BottomNavigation = React18__namespace.forwardRef(
981
1176
  }
982
1177
  );
983
1178
  BottomNavigation.displayName = "BottomNavigation";
984
- var TableWrap = React18__namespace.forwardRef(
1179
+ var TableWrap = React52__namespace.forwardRef(
985
1180
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("border border-border rounded-kj-lg overflow-x-auto w-full", className), ...props })
986
1181
  );
987
1182
  TableWrap.displayName = "TableWrap";
988
- var Table = React18__namespace.forwardRef(
1183
+ var Table = React52__namespace.forwardRef(
989
1184
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("table", { ref, className: cn("w-full border-collapse text-[0.85rem]", className), ...props })
990
1185
  );
991
1186
  Table.displayName = "Table";
992
- var TableHeader = React18__namespace.forwardRef(
1187
+ var TableHeader = React52__namespace.forwardRef(
993
1188
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className, ...props })
994
1189
  );
995
1190
  TableHeader.displayName = "TableHeader";
996
- var TableBody = React18__namespace.forwardRef(
1191
+ var TableBody = React52__namespace.forwardRef(
997
1192
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className, ...props })
998
1193
  );
999
1194
  TableBody.displayName = "TableBody";
1000
- var TableRow = React18__namespace.forwardRef(
1195
+ var TableRow = React52__namespace.forwardRef(
1001
1196
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tr", { ref, className: cn("transition-colors hover:bg-muted/50", className), ...props })
1002
1197
  );
1003
1198
  TableRow.displayName = "TableRow";
1004
- var TableHead = React18__namespace.forwardRef(
1199
+ var TableHead = React52__namespace.forwardRef(
1005
1200
  ({ className, numeric, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1006
1201
  "th",
1007
1202
  {
@@ -1016,7 +1211,7 @@ var TableHead = React18__namespace.forwardRef(
1016
1211
  )
1017
1212
  );
1018
1213
  TableHead.displayName = "TableHead";
1019
- var TableCell = React18__namespace.forwardRef(
1214
+ var TableCell = React52__namespace.forwardRef(
1020
1215
  ({ className, numeric, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1021
1216
  "td",
1022
1217
  {
@@ -1032,30 +1227,33 @@ var TableCell = React18__namespace.forwardRef(
1032
1227
  );
1033
1228
  TableCell.displayName = "TableCell";
1034
1229
  function Tooltip({ content, children, className }) {
1035
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("relative inline-flex group", className), tabIndex: 0, children: [
1036
- children,
1037
- /* @__PURE__ */ jsxRuntime.jsx(
1038
- "span",
1039
- {
1040
- role: "tooltip",
1041
- className: cn(
1042
- "pointer-events-none absolute bottom-[calc(100%+8px)] left-1/2 -translate-x-1/2 translate-y-1 whitespace-nowrap",
1043
- "rounded-kj-sm bg-foreground text-background text-xs font-medium px-2.5 py-1.5 shadow-kj-md",
1044
- "opacity-0 transition-all duration-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0",
1045
- "after:content-[''] after:absolute after:top-full after:left-1/2 after:-translate-x-1/2 after:border-[5px] after:border-transparent after:border-t-foreground"
1046
- ),
1047
- children: content
1048
- }
1049
- )
1050
- ] });
1230
+ return (
1231
+ /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
1232
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("relative inline-flex group", className), tabIndex: 0, children: [
1233
+ children,
1234
+ /* @__PURE__ */ jsxRuntime.jsx(
1235
+ "span",
1236
+ {
1237
+ role: "tooltip",
1238
+ className: cn(
1239
+ "pointer-events-none absolute bottom-[calc(100%+8px)] left-1/2 -translate-x-1/2 translate-y-1 whitespace-nowrap",
1240
+ "rounded-kj-sm bg-foreground text-background text-xs font-medium px-2.5 py-1.5 shadow-kj-md",
1241
+ "opacity-0 transition-all duration-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0",
1242
+ "after:content-[''] after:absolute after:top-full after:left-1/2 after:-translate-x-1/2 after:border-[5px] after:border-transparent after:border-t-foreground"
1243
+ ),
1244
+ children: content
1245
+ }
1246
+ )
1247
+ ] })
1248
+ );
1051
1249
  }
1052
- var ModalContext = React18__namespace.createContext(null);
1250
+ var ModalContext = React52__namespace.createContext(null);
1053
1251
  function Modal({ open, onClose, children, width = 440, className, showClose = true }) {
1054
- const titleId = React18__namespace.useId();
1055
- const descId = React18__namespace.useId();
1056
- const containerRef = React18__namespace.useRef(null);
1057
- const lastActiveElement = React18__namespace.useRef(null);
1058
- React18__namespace.useEffect(() => {
1252
+ const titleId = React52__namespace.useId();
1253
+ const descId = React52__namespace.useId();
1254
+ const containerRef = React52__namespace.useRef(null);
1255
+ const lastActiveElement = React52__namespace.useRef(null);
1256
+ React52__namespace.useEffect(() => {
1059
1257
  if (!open) {
1060
1258
  if (lastActiveElement.current) {
1061
1259
  lastActiveElement.current.focus();
@@ -1156,20 +1354,20 @@ function Modal({ open, onClose, children, width = 440, className, showClose = tr
1156
1354
  }
1157
1355
  );
1158
1356
  }
1159
- function ModalTitle({ className, id, ...props }) {
1160
- const ctx = React18__namespace.useContext(ModalContext);
1161
- return /* @__PURE__ */ jsxRuntime.jsx("h3", { id: id ?? ctx?.titleId, className: cn("m-0 mb-2 text-[1.15rem] font-bold tracking-[-0.01em]", className), ...props });
1357
+ function ModalTitle({ className, id, children, ...props }) {
1358
+ const ctx = React52__namespace.useContext(ModalContext);
1359
+ return /* @__PURE__ */ jsxRuntime.jsx("h3", { id: id ?? ctx?.titleId, className: cn("m-0 mb-2 text-[1.15rem] font-bold tracking-[-0.01em]", className), ...props, children });
1162
1360
  }
1163
1361
  function ModalDescription({ className, id, ...props }) {
1164
- const ctx = React18__namespace.useContext(ModalContext);
1362
+ const ctx = React52__namespace.useContext(ModalContext);
1165
1363
  return /* @__PURE__ */ jsxRuntime.jsx("p", { id: id ?? ctx?.descId, className: cn("m-0 text-[0.9rem] text-muted-foreground", className), ...props });
1166
1364
  }
1167
1365
  function ModalActions({ className, ...props }) {
1168
1366
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex gap-2.5 justify-end mt-6", className), ...props });
1169
1367
  }
1170
- var ToastContext = React18__namespace.createContext(null);
1368
+ var ToastContext = React52__namespace.createContext(null);
1171
1369
  function useToast() {
1172
- const ctx = React18__namespace.useContext(ToastContext);
1370
+ const ctx = React52__namespace.useContext(ToastContext);
1173
1371
  if (!ctx) throw new Error("useToast must be used within <ToastProvider>");
1174
1372
  return ctx;
1175
1373
  }
@@ -1190,13 +1388,13 @@ var toneBorder = {
1190
1388
  danger: "border-l-danger"
1191
1389
  };
1192
1390
  function ToastProvider({ children }) {
1193
- const [items, setItems] = React18__namespace.useState([]);
1194
- const idRef = React18__namespace.useRef(0);
1195
- const remove = React18__namespace.useCallback((id) => {
1391
+ const [items, setItems] = React52__namespace.useState([]);
1392
+ const idRef = React52__namespace.useRef(0);
1393
+ const remove = React52__namespace.useCallback((id) => {
1196
1394
  setItems((prev) => prev.map((t) => t.id === id ? { ...t, leaving: true } : t));
1197
1395
  setTimeout(() => setItems((prev) => prev.filter((t) => t.id !== id)), 250);
1198
1396
  }, []);
1199
- const toast = React18__namespace.useCallback(
1397
+ const toast = React52__namespace.useCallback(
1200
1398
  ({ message, tone = "default", duration = 3200 }) => {
1201
1399
  const id = ++idRef.current;
1202
1400
  setItems((prev) => [...prev, { id, message, tone, duration }]);
@@ -1226,7 +1424,7 @@ function ToastProvider({ children }) {
1226
1424
  )) })
1227
1425
  ] });
1228
1426
  }
1229
- var PageHeader = React18__namespace.forwardRef(
1427
+ var PageHeader = React52__namespace.forwardRef(
1230
1428
  ({ eyebrow, title, description, actions }, ref) => /* @__PURE__ */ jsxRuntime.jsx("header", { ref, className: "py-12 md:py-16", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6 md:flex-row md:items-end md:justify-between", children: [
1231
1429
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 max-w-2xl", children: [
1232
1430
  eyebrow && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-xs font-bold uppercase tracking-[0.2em] text-primary", children: eyebrow }),
@@ -1237,7 +1435,111 @@ var PageHeader = React18__namespace.forwardRef(
1237
1435
  ] }) })
1238
1436
  );
1239
1437
  PageHeader.displayName = "PageHeader";
1240
- var EmptyState = React18__namespace.forwardRef(
1438
+ var SectionHeaderKicker = React52__namespace.forwardRef(
1439
+ ({ className, children, ...props }, ref) => {
1440
+ if (!children) return null;
1441
+ return /* @__PURE__ */ jsxRuntime.jsx(
1442
+ "p",
1443
+ {
1444
+ ref,
1445
+ className: cn(
1446
+ "font-mono text-xs font-bold uppercase tracking-[0.2em] text-primary",
1447
+ className
1448
+ ),
1449
+ ...props,
1450
+ children
1451
+ }
1452
+ );
1453
+ }
1454
+ );
1455
+ SectionHeaderKicker.displayName = "SectionHeaderKicker";
1456
+ var SectionHeaderTitle = React52__namespace.forwardRef(
1457
+ ({ className, as: Component = "h2", children, ...props }, ref) => {
1458
+ if (!children) return null;
1459
+ return /* @__PURE__ */ jsxRuntime.jsx(
1460
+ Component,
1461
+ {
1462
+ ref,
1463
+ className: cn("text-2xl font-bold tracking-tight text-foreground sm:text-3xl", className),
1464
+ ...props,
1465
+ children
1466
+ }
1467
+ );
1468
+ }
1469
+ );
1470
+ SectionHeaderTitle.displayName = "SectionHeaderTitle";
1471
+ var SectionHeaderDescription = React52__namespace.forwardRef(({ className, children, ...props }, ref) => {
1472
+ if (!children) return null;
1473
+ return /* @__PURE__ */ jsxRuntime.jsx(
1474
+ "p",
1475
+ {
1476
+ ref,
1477
+ className: cn("text-base leading-relaxed text-muted-foreground max-w-2xl", className),
1478
+ ...props,
1479
+ children
1480
+ }
1481
+ );
1482
+ });
1483
+ SectionHeaderDescription.displayName = "SectionHeaderDescription";
1484
+ var SectionHeaderActions = React52__namespace.forwardRef(
1485
+ ({ className, children, ...props }, ref) => {
1486
+ if (!children) return null;
1487
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-wrap items-center gap-3", className), ...props, children });
1488
+ }
1489
+ );
1490
+ SectionHeaderActions.displayName = "SectionHeaderActions";
1491
+ var SectionHeader = React52__namespace.forwardRef(
1492
+ ({
1493
+ kicker,
1494
+ title,
1495
+ description,
1496
+ actions,
1497
+ align = "left",
1498
+ headingLevel = "h2",
1499
+ divider = false,
1500
+ className,
1501
+ children,
1502
+ ...props
1503
+ }, ref) => {
1504
+ const isCentered = align === "center";
1505
+ return /* @__PURE__ */ jsxRuntime.jsx(
1506
+ "div",
1507
+ {
1508
+ ref,
1509
+ className: cn(
1510
+ "space-y-4",
1511
+ isCentered ? "text-center items-center mx-auto max-w-3xl" : "md:flex md:items-end md:justify-between md:space-y-0",
1512
+ divider && "border-b border-border pb-6",
1513
+ className
1514
+ ),
1515
+ ...props,
1516
+ children: children ? children : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1517
+ /* @__PURE__ */ jsxRuntime.jsxs(
1518
+ "div",
1519
+ {
1520
+ className: cn(
1521
+ "space-y-2",
1522
+ isCentered && "flex flex-col items-center"
1523
+ ),
1524
+ children: [
1525
+ kicker && /* @__PURE__ */ jsxRuntime.jsx(SectionHeaderKicker, { children: kicker }),
1526
+ title && /* @__PURE__ */ jsxRuntime.jsx(SectionHeaderTitle, { as: headingLevel, children: title }),
1527
+ description && /* @__PURE__ */ jsxRuntime.jsx(SectionHeaderDescription, { children: description })
1528
+ ]
1529
+ }
1530
+ ),
1531
+ actions && /* @__PURE__ */ jsxRuntime.jsx(SectionHeaderActions, { className: cn(isCentered && "justify-center mt-4"), children: actions })
1532
+ ] })
1533
+ }
1534
+ );
1535
+ }
1536
+ );
1537
+ SectionHeader.displayName = "SectionHeader";
1538
+ SectionHeader.Kicker = SectionHeaderKicker;
1539
+ SectionHeader.Title = SectionHeaderTitle;
1540
+ SectionHeader.Description = SectionHeaderDescription;
1541
+ SectionHeader.Actions = SectionHeaderActions;
1542
+ var EmptyState = React52__namespace.forwardRef(
1241
1543
  ({ className, icon, title, description, action, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
1242
1544
  "div",
1243
1545
  {
@@ -1257,7 +1559,7 @@ var EmptyState = React18__namespace.forwardRef(
1257
1559
  )
1258
1560
  );
1259
1561
  EmptyState.displayName = "EmptyState";
1260
- var MetricCard = React18__namespace.forwardRef(
1562
+ var MetricCard = React52__namespace.forwardRef(
1261
1563
  ({ className, title, value, trend, trendDirection = "neutral", description, icon, ...props }, ref) => {
1262
1564
  const trendColor = {
1263
1565
  up: "text-success bg-success-surface border-success/20",
@@ -1298,22 +1600,22 @@ function DataTable({
1298
1600
  onSort,
1299
1601
  ...props
1300
1602
  }) {
1301
- const getRowId = React18__namespace.useCallback(
1603
+ const getRowId = React52__namespace.useCallback(
1302
1604
  (row, index) => getRowKey ? getRowKey(row, index) : index,
1303
1605
  [getRowKey]
1304
1606
  );
1305
1607
  const isSelectionActive = selectedRows !== void 0 && onSelectionChange !== void 0;
1306
- const allSelected = React18__namespace.useMemo(() => {
1608
+ const allSelected = React52__namespace.useMemo(() => {
1307
1609
  if (!isSelectionActive || data.length === 0) return false;
1308
1610
  return data.every((row, idx) => selectedRows.has(getRowId(row, idx)));
1309
1611
  }, [isSelectionActive, data, selectedRows, getRowId]);
1310
- const someSelected = React18__namespace.useMemo(() => {
1612
+ const someSelected = React52__namespace.useMemo(() => {
1311
1613
  if (!isSelectionActive || data.length === 0) return false;
1312
1614
  const selectedCount = data.filter((row, idx) => selectedRows.has(getRowId(row, idx))).length;
1313
1615
  return selectedCount > 0 && selectedCount < data.length;
1314
1616
  }, [isSelectionActive, data, selectedRows, getRowId]);
1315
- const headerCheckboxRef = React18__namespace.useRef(null);
1316
- React18__namespace.useEffect(() => {
1617
+ const headerCheckboxRef = React52__namespace.useRef(null);
1618
+ React52__namespace.useEffect(() => {
1317
1619
  if (headerCheckboxRef.current) {
1318
1620
  headerCheckboxRef.current.indeterminate = someSelected;
1319
1621
  }
@@ -1467,7 +1769,7 @@ function DataTable({
1467
1769
  ] });
1468
1770
  }
1469
1771
  DataTable.displayName = "DataTable";
1470
- var ErrorState = React18__namespace.forwardRef(
1772
+ var ErrorState = React52__namespace.forwardRef(
1471
1773
  ({ className, title = "Wyst\u0105pi\u0142 b\u0142\u0105d", message, onRetry, retryLabel = "Spr\xF3buj ponownie", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
1472
1774
  "div",
1473
1775
  {
@@ -1487,7 +1789,7 @@ var ErrorState = React18__namespace.forwardRef(
1487
1789
  )
1488
1790
  );
1489
1791
  ErrorState.displayName = "ErrorState";
1490
- var Skeleton = React18__namespace.forwardRef(
1792
+ var Skeleton = React52__namespace.forwardRef(
1491
1793
  ({ className, variant = "rectangular", width, height, style, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1492
1794
  "div",
1493
1795
  {
@@ -1509,7 +1811,7 @@ var Skeleton = React18__namespace.forwardRef(
1509
1811
  )
1510
1812
  );
1511
1813
  Skeleton.displayName = "Skeleton";
1512
- var DashboardShell = React18__namespace.forwardRef(
1814
+ var DashboardShell = React52__namespace.forwardRef(
1513
1815
  ({
1514
1816
  className,
1515
1817
  sidebar,
@@ -1521,7 +1823,7 @@ var DashboardShell = React18__namespace.forwardRef(
1521
1823
  mobileSidebar,
1522
1824
  ...props
1523
1825
  }, ref) => {
1524
- const [mobileOpen, setMobileOpen] = React18__namespace.useState(false);
1826
+ const [mobileOpen, setMobileOpen] = React52__namespace.useState(false);
1525
1827
  const contentWidthClass = {
1526
1828
  default: "max-w-7xl w-full mx-auto",
1527
1829
  wide: "max-w-screen-2xl w-full mx-auto",
@@ -1612,7 +1914,7 @@ var DashboardShell = React18__namespace.forwardRef(
1612
1914
  }
1613
1915
  );
1614
1916
  DashboardShell.displayName = "DashboardShell";
1615
- var SettingsLayout = React18__namespace.forwardRef(
1917
+ var SettingsLayout = React52__namespace.forwardRef(
1616
1918
  ({ className, sidebar, children, title, description, ...props }, ref) => {
1617
1919
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("space-y-6 w-full", className), ...props, children: [
1618
1920
  (title || description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border pb-4", children: [
@@ -1627,7 +1929,7 @@ var SettingsLayout = React18__namespace.forwardRef(
1627
1929
  }
1628
1930
  );
1629
1931
  SettingsLayout.displayName = "SettingsLayout";
1630
- var DetailPageLayout = React18__namespace.forwardRef(
1932
+ var DetailPageLayout = React52__namespace.forwardRef(
1631
1933
  ({ className, title, description, backHref, backLabel = "Back", onBackClick, actions, aside, children, ...props }, ref) => {
1632
1934
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("space-y-6 w-full", className), ...props, children: [
1633
1935
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
@@ -1673,7 +1975,7 @@ var DetailPageLayout = React18__namespace.forwardRef(
1673
1975
  }
1674
1976
  );
1675
1977
  DetailPageLayout.displayName = "DetailPageLayout";
1676
- var TableToolbar = React18__namespace.forwardRef(
1978
+ var TableToolbar = React52__namespace.forwardRef(
1677
1979
  ({ className, searchQuery, onSearchChange, searchPlaceholder = "Search...", actions, filters, ...props }, ref) => {
1678
1980
  return /* @__PURE__ */ jsxRuntime.jsxs(
1679
1981
  "div",
@@ -1742,9 +2044,9 @@ function Drawer({
1742
2044
  width = "max-w-md",
1743
2045
  side = "right"
1744
2046
  }) {
1745
- const containerRef = React18__namespace.useRef(null);
1746
- const lastActiveElement = React18__namespace.useRef(null);
1747
- React18__namespace.useEffect(() => {
2047
+ const containerRef = React52__namespace.useRef(null);
2048
+ const lastActiveElement = React52__namespace.useRef(null);
2049
+ React52__namespace.useEffect(() => {
1748
2050
  if (!open) {
1749
2051
  if (lastActiveElement.current) {
1750
2052
  lastActiveElement.current.focus();
@@ -1863,11 +2165,11 @@ function Drawer({
1863
2165
  }
1864
2166
  Drawer.displayName = "Drawer";
1865
2167
  function CommandPalette({ open, onClose, items, placeholder = "Type a command or search..." }) {
1866
- const [search, setSearch] = React18__namespace.useState("");
1867
- const [activeIndex, setActiveIndex] = React18__namespace.useState(0);
1868
- const containerRef = React18__namespace.useRef(null);
1869
- const listRef = React18__namespace.useRef(null);
1870
- React18__namespace.useEffect(() => {
2168
+ const [search, setSearch] = React52__namespace.useState("");
2169
+ const [activeIndex, setActiveIndex] = React52__namespace.useState(0);
2170
+ const containerRef = React52__namespace.useRef(null);
2171
+ const listRef = React52__namespace.useRef(null);
2172
+ React52__namespace.useEffect(() => {
1871
2173
  if (open) {
1872
2174
  setSearch("");
1873
2175
  setActiveIndex(0);
@@ -1876,17 +2178,17 @@ function CommandPalette({ open, onClose, items, placeholder = "Type a command or
1876
2178
  document.body.style.overflow = "";
1877
2179
  }
1878
2180
  }, [open]);
1879
- const filteredItems = React18__namespace.useMemo(() => {
2181
+ const filteredItems = React52__namespace.useMemo(() => {
1880
2182
  if (!search) return items;
1881
2183
  const cleanSearch = search.toLowerCase();
1882
2184
  return items.filter(
1883
2185
  (item) => item.title.toLowerCase().includes(cleanSearch) || item.subtitle?.toLowerCase().includes(cleanSearch) || item.category?.toLowerCase().includes(cleanSearch)
1884
2186
  );
1885
2187
  }, [search, items]);
1886
- React18__namespace.useEffect(() => {
2188
+ React52__namespace.useEffect(() => {
1887
2189
  setActiveIndex(0);
1888
2190
  }, [filteredItems]);
1889
- React18__namespace.useEffect(() => {
2191
+ React52__namespace.useEffect(() => {
1890
2192
  if (!open) return;
1891
2193
  const handleKeyDown = (e) => {
1892
2194
  if (e.key === "Escape") {
@@ -1910,7 +2212,7 @@ function CommandPalette({ open, onClose, items, placeholder = "Type a command or
1910
2212
  document.addEventListener("keydown", handleKeyDown);
1911
2213
  return () => document.removeEventListener("keydown", handleKeyDown);
1912
2214
  }, [open, filteredItems, activeIndex, onClose]);
1913
- React18__namespace.useEffect(() => {
2215
+ React52__namespace.useEffect(() => {
1914
2216
  if (listRef.current) {
1915
2217
  const activeEl = listRef.current.querySelector('[aria-selected="true"]');
1916
2218
  if (activeEl) {
@@ -2113,7 +2415,7 @@ var fabVariants = classVarianceAuthority.cva(
2113
2415
  defaultVariants: { variant: "primary", size: "md", position: "bottom-right" }
2114
2416
  }
2115
2417
  );
2116
- var Fab = React18__namespace.forwardRef(
2418
+ var Fab = React52__namespace.forwardRef(
2117
2419
  ({ className, variant, size, position, mobileOnly, icon, label, loading, disabled, ...props }, ref) => {
2118
2420
  return /* @__PURE__ */ jsxRuntime.jsx(
2119
2421
  "button",
@@ -2140,7 +2442,7 @@ var Fab = React18__namespace.forwardRef(
2140
2442
  }
2141
2443
  );
2142
2444
  Fab.displayName = "Fab";
2143
- var BottomSheetContext = React18__namespace.createContext(null);
2445
+ var BottomSheetContext = React52__namespace.createContext(null);
2144
2446
  function BottomSheet({
2145
2447
  open,
2146
2448
  onClose,
@@ -2149,12 +2451,12 @@ function BottomSheet({
2149
2451
  className,
2150
2452
  showClose = true
2151
2453
  }) {
2152
- const titleId = React18__namespace.useId();
2153
- const descId = React18__namespace.useId();
2154
- const containerRef = React18__namespace.useRef(null);
2155
- const lastActiveElement = React18__namespace.useRef(null);
2156
- const [mounted, setMounted] = React18__namespace.useState(open);
2157
- React18__namespace.useEffect(() => {
2454
+ const titleId = React52__namespace.useId();
2455
+ const descId = React52__namespace.useId();
2456
+ const containerRef = React52__namespace.useRef(null);
2457
+ const lastActiveElement = React52__namespace.useRef(null);
2458
+ const [mounted, setMounted] = React52__namespace.useState(open);
2459
+ React52__namespace.useEffect(() => {
2158
2460
  if (open) {
2159
2461
  setMounted(true);
2160
2462
  } else {
@@ -2162,7 +2464,7 @@ function BottomSheet({
2162
2464
  return () => clearTimeout(timer);
2163
2465
  }
2164
2466
  }, [open]);
2165
- React18__namespace.useEffect(() => {
2467
+ React52__namespace.useEffect(() => {
2166
2468
  if (!open) return;
2167
2469
  lastActiveElement.current = document.activeElement;
2168
2470
  const container = containerRef.current;
@@ -2284,12 +2586,12 @@ function BottomSheet({
2284
2586
  function BottomSheetHeader({ className, ...props }) {
2285
2587
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("p-6 flex flex-col gap-1.5 border-b border-border", className), ...props });
2286
2588
  }
2287
- function BottomSheetTitle({ className, id, ...props }) {
2288
- const ctx = React18__namespace.useContext(BottomSheetContext);
2289
- return /* @__PURE__ */ jsxRuntime.jsx("h2", { id: id ?? ctx?.titleId, className: cn("m-0 text-[1.15rem] font-bold tracking-[-0.01em]", className), ...props });
2589
+ function BottomSheetTitle({ className, id, children, ...props }) {
2590
+ const ctx = React52__namespace.useContext(BottomSheetContext);
2591
+ return /* @__PURE__ */ jsxRuntime.jsx("h2", { id: id ?? ctx?.titleId, className: cn("m-0 text-[1.15rem] font-bold tracking-[-0.01em]", className), ...props, children });
2290
2592
  }
2291
2593
  function BottomSheetDescription({ className, id, ...props }) {
2292
- const ctx = React18__namespace.useContext(BottomSheetContext);
2594
+ const ctx = React52__namespace.useContext(BottomSheetContext);
2293
2595
  return /* @__PURE__ */ jsxRuntime.jsx("p", { id: id ?? ctx?.descId, className: cn("m-0 text-[0.9rem] text-muted-foreground", className), ...props });
2294
2596
  }
2295
2597
  function BottomSheetContent({ className, ...props }) {
@@ -2310,7 +2612,7 @@ var kbdVariants = classVarianceAuthority.cva(
2310
2612
  defaultVariants: { size: "sm" }
2311
2613
  }
2312
2614
  );
2313
- var Kbd = React18__namespace.forwardRef(
2615
+ var Kbd = React52__namespace.forwardRef(
2314
2616
  ({ className, size, keys, children, ...props }, ref) => {
2315
2617
  if (keys && keys.length > 0) {
2316
2618
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2327,9 +2629,9 @@ var Kbd = React18__namespace.forwardRef(
2327
2629
  }
2328
2630
  );
2329
2631
  Kbd.displayName = "Kbd";
2330
- var CodeBlock = React18__namespace.forwardRef(
2632
+ var CodeBlock = React52__namespace.forwardRef(
2331
2633
  ({ className, code, language, filename, copyable = true, maxHeight, ...props }, ref) => {
2332
- const [copied, setCopied] = React18__namespace.useState(false);
2634
+ const [copied, setCopied] = React52__namespace.useState(false);
2333
2635
  const canCopy = copyable && typeof navigator !== "undefined" && !!navigator.clipboard;
2334
2636
  const onCopy = () => {
2335
2637
  navigator.clipboard.writeText(code).then(
@@ -2375,26 +2677,40 @@ var CodeBlock = React18__namespace.forwardRef(
2375
2677
  }
2376
2678
  );
2377
2679
  CodeBlock.displayName = "CodeBlock";
2378
- var PopoverContext = React18__namespace.createContext(null);
2680
+ function Separator({ orientation = "horizontal", decorative = true, className }) {
2681
+ const semanticProps = decorative ? { role: "none", "aria-hidden": true } : { role: "separator", "aria-orientation": orientation };
2682
+ return /* @__PURE__ */ jsxRuntime.jsx(
2683
+ "div",
2684
+ {
2685
+ className: cn(
2686
+ "shrink-0 bg-border",
2687
+ orientation === "horizontal" ? "h-px w-full" : "w-px h-full",
2688
+ className
2689
+ ),
2690
+ ...semanticProps
2691
+ }
2692
+ );
2693
+ }
2694
+ var PopoverContext = React52__namespace.createContext(null);
2379
2695
  function usePopoverContext(part) {
2380
- const ctx = React18__namespace.useContext(PopoverContext);
2696
+ const ctx = React52__namespace.useContext(PopoverContext);
2381
2697
  if (!ctx) throw new Error(`${part} must be used inside <Popover>`);
2382
2698
  return ctx;
2383
2699
  }
2384
2700
  function Popover({ children, className, open: openProp, onOpenChange }) {
2385
- const [openState, setOpenState] = React18__namespace.useState(false);
2701
+ const [openState, setOpenState] = React52__namespace.useState(false);
2386
2702
  const controlled = openProp !== void 0;
2387
2703
  const open = controlled ? openProp : openState;
2388
- const triggerRef = React18__namespace.useRef(null);
2389
- const ref = React18__namespace.useRef(null);
2390
- const setOpen = React18__namespace.useCallback(
2704
+ const triggerRef = React52__namespace.useRef(null);
2705
+ const ref = React52__namespace.useRef(null);
2706
+ const setOpen = React52__namespace.useCallback(
2391
2707
  (v) => {
2392
2708
  if (!controlled) setOpenState(v);
2393
2709
  onOpenChange?.(v);
2394
2710
  },
2395
2711
  [controlled, onOpenChange]
2396
2712
  );
2397
- React18__namespace.useEffect(() => {
2713
+ React52__namespace.useEffect(() => {
2398
2714
  if (!open) return;
2399
2715
  const onDoc = (e) => {
2400
2716
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -2414,7 +2730,7 @@ function Popover({ children, className, open: openProp, onOpenChange }) {
2414
2730
  }, [open, setOpen]);
2415
2731
  return /* @__PURE__ */ jsxRuntime.jsx(PopoverContext.Provider, { value: { open, setOpen, triggerRef }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("relative inline-block", className), children }) });
2416
2732
  }
2417
- var PopoverTrigger = React18__namespace.forwardRef(({ onClick, asChild, ...props }, ref) => {
2733
+ var PopoverTrigger = React52__namespace.forwardRef(({ onClick, asChild, ...props }, ref) => {
2418
2734
  const ctx = usePopoverContext("PopoverTrigger");
2419
2735
  const setRefs = (node) => {
2420
2736
  ctx.triggerRef.current = node;
@@ -2422,8 +2738,8 @@ var PopoverTrigger = React18__namespace.forwardRef(({ onClick, asChild, ...props
2422
2738
  else if (ref) ref.current = node;
2423
2739
  };
2424
2740
  if (asChild) {
2425
- const child = React18__namespace.Children.only(props.children);
2426
- return React18__namespace.cloneElement(child, {
2741
+ const child = React52__namespace.Children.only(props.children);
2742
+ return React52__namespace.cloneElement(child, {
2427
2743
  ref: setRefs,
2428
2744
  ...props,
2429
2745
  ...child.props,
@@ -2474,8 +2790,8 @@ function PopoverContent({
2474
2790
  ...props
2475
2791
  }) {
2476
2792
  const ctx = usePopoverContext("PopoverContent");
2477
- const ref = React18__namespace.useRef(null);
2478
- React18__namespace.useEffect(() => {
2793
+ const ref = React52__namespace.useRef(null);
2794
+ React52__namespace.useEffect(() => {
2479
2795
  if (ctx.open) ref.current?.focus();
2480
2796
  }, [ctx.open]);
2481
2797
  if (!ctx.open) return null;
@@ -2496,15 +2812,3289 @@ function PopoverContent({
2496
2812
  }
2497
2813
  );
2498
2814
  }
2815
+ function toArray(v) {
2816
+ if (v == null) return [];
2817
+ return Array.isArray(v) ? v : [v];
2818
+ }
2819
+ var Combobox = React52__namespace.forwardRef(
2820
+ function Combobox2(props, ref) {
2821
+ const {
2822
+ options,
2823
+ placeholder = "Select\u2026",
2824
+ searchPlaceholder = "Search\u2026",
2825
+ emptyMessage = "No results",
2826
+ disabled = false,
2827
+ error = false,
2828
+ required = false,
2829
+ className,
2830
+ id,
2831
+ name,
2832
+ "aria-describedby": describedBy
2833
+ } = props;
2834
+ const multiple = props.multiple ?? false;
2835
+ const reactId = React52__namespace.useId();
2836
+ const baseId = id ?? reactId;
2837
+ const listId = `${baseId}-listbox`;
2838
+ const optionId = (i) => `${baseId}-opt-${i}`;
2839
+ const controlled = props.value !== void 0;
2840
+ const [internal, setInternal] = React52__namespace.useState(() => toArray(props.defaultValue));
2841
+ const selected = controlled ? toArray(props.value) : internal;
2842
+ const [open, setOpen] = React52__namespace.useState(false);
2843
+ const [search, setSearch] = React52__namespace.useState("");
2844
+ const [activeIndex, setActiveIndex] = React52__namespace.useState(0);
2845
+ const containerRef = React52__namespace.useRef(null);
2846
+ const triggerRef = React52__namespace.useRef(null);
2847
+ const inputRef = React52__namespace.useRef(null);
2848
+ const listRef = React52__namespace.useRef(null);
2849
+ const setTriggerRef = (node) => {
2850
+ triggerRef.current = node;
2851
+ if (typeof ref === "function") ref(node);
2852
+ else if (ref) ref.current = node;
2853
+ };
2854
+ const filtered = React52__namespace.useMemo(() => {
2855
+ const q = search.trim().toLowerCase();
2856
+ return q ? options.filter((o) => o.label.toLowerCase().includes(q)) : options;
2857
+ }, [search, options]);
2858
+ const firstEnabled = React52__namespace.useCallback(() => {
2859
+ const i = filtered.findIndex((o) => !o.disabled);
2860
+ return i === -1 ? 0 : i;
2861
+ }, [filtered]);
2862
+ const labelFor = (v) => options.find((o) => o.value === v)?.label ?? v;
2863
+ const emit = (next) => {
2864
+ if (!controlled) setInternal(next);
2865
+ if (props.multiple) {
2866
+ props.onChange?.(next);
2867
+ } else {
2868
+ props.onChange?.(next[0] ?? "");
2869
+ }
2870
+ };
2871
+ const closePopup = React52__namespace.useCallback(() => {
2872
+ setOpen(false);
2873
+ setSearch("");
2874
+ }, []);
2875
+ const openPopup = () => {
2876
+ if (!disabled) setOpen(true);
2877
+ };
2878
+ const handleSelect = (opt) => {
2879
+ if (opt.disabled) return;
2880
+ if (multiple) {
2881
+ const next = selected.includes(opt.value) ? selected.filter((v) => v !== opt.value) : [...selected, opt.value];
2882
+ emit(next);
2883
+ inputRef.current?.focus();
2884
+ } else {
2885
+ emit([opt.value]);
2886
+ closePopup();
2887
+ triggerRef.current?.focus();
2888
+ }
2889
+ };
2890
+ const removeValue = (value) => {
2891
+ emit(selected.filter((v) => v !== value));
2892
+ };
2893
+ React52__namespace.useEffect(() => {
2894
+ if (open) setActiveIndex(firstEnabled());
2895
+ }, [open, firstEnabled]);
2896
+ React52__namespace.useEffect(() => {
2897
+ if (open) inputRef.current?.focus();
2898
+ }, [open]);
2899
+ React52__namespace.useEffect(() => {
2900
+ if (!open) return;
2901
+ const onDown = (e) => {
2902
+ if (containerRef.current && !containerRef.current.contains(e.target)) closePopup();
2903
+ };
2904
+ document.addEventListener("mousedown", onDown);
2905
+ return () => document.removeEventListener("mousedown", onDown);
2906
+ }, [open, closePopup]);
2907
+ React52__namespace.useEffect(() => {
2908
+ const el = listRef.current?.querySelector('[data-active="true"]');
2909
+ el?.scrollIntoView({ block: "nearest" });
2910
+ }, [activeIndex]);
2911
+ const moveActive = (dir) => {
2912
+ if (filtered.length === 0) return;
2913
+ setActiveIndex((prev) => {
2914
+ let i = prev;
2915
+ for (let step = 0; step < filtered.length; step++) {
2916
+ i = (i + dir + filtered.length) % filtered.length;
2917
+ if (!filtered[i]?.disabled) return i;
2918
+ }
2919
+ return prev;
2920
+ });
2921
+ };
2922
+ const onInputKeyDown = (e) => {
2923
+ switch (e.key) {
2924
+ case "ArrowDown":
2925
+ e.preventDefault();
2926
+ moveActive(1);
2927
+ break;
2928
+ case "ArrowUp":
2929
+ e.preventDefault();
2930
+ moveActive(-1);
2931
+ break;
2932
+ case "Home":
2933
+ e.preventDefault();
2934
+ setActiveIndex(firstEnabled());
2935
+ break;
2936
+ case "End":
2937
+ e.preventDefault();
2938
+ for (let i = filtered.length - 1; i >= 0; i--) {
2939
+ if (!filtered[i].disabled) {
2940
+ setActiveIndex(i);
2941
+ break;
2942
+ }
2943
+ }
2944
+ break;
2945
+ case "Enter":
2946
+ e.preventDefault();
2947
+ if (filtered[activeIndex]) handleSelect(filtered[activeIndex]);
2948
+ break;
2949
+ case "Escape":
2950
+ e.preventDefault();
2951
+ closePopup();
2952
+ triggerRef.current?.focus();
2953
+ break;
2954
+ case "Backspace":
2955
+ if (multiple && search === "" && selected.length > 0) {
2956
+ removeValue(selected[selected.length - 1]);
2957
+ }
2958
+ break;
2959
+ }
2960
+ };
2961
+ const onTriggerKeyDown = (e) => {
2962
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
2963
+ e.preventDefault();
2964
+ openPopup();
2965
+ }
2966
+ };
2967
+ const showPlaceholder = multiple ? selected.length === 0 : !selected[0];
2968
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: cn("relative w-full", className), children: [
2969
+ /* @__PURE__ */ jsxRuntime.jsxs(
2970
+ "div",
2971
+ {
2972
+ className: cn(
2973
+ "relative flex w-full items-center gap-1.5 flex-wrap border rounded-kj-md bg-surface",
2974
+ "pl-[0.85rem] pr-9 py-[calc(0.45rem*var(--kj-density,1))] min-h-[calc(2.5rem*var(--kj-density,1))]",
2975
+ "transition-[border-color,box-shadow] duration-150",
2976
+ "focus-within:outline-none focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/30",
2977
+ disabled && "bg-muted cursor-not-allowed",
2978
+ error ? "border-danger" : "border-input"
2979
+ ),
2980
+ children: [
2981
+ multiple && selected.map((value) => /* @__PURE__ */ jsxRuntime.jsxs(
2982
+ "span",
2983
+ {
2984
+ className: "inline-flex items-center gap-1 rounded-kj-sm bg-primary/10 text-primary text-xs font-medium pl-2 pr-1 py-0.5",
2985
+ children: [
2986
+ labelFor(value),
2987
+ /* @__PURE__ */ jsxRuntime.jsx(
2988
+ "button",
2989
+ {
2990
+ type: "button",
2991
+ "aria-label": `Remove ${labelFor(value)}`,
2992
+ disabled,
2993
+ onClick: (e) => {
2994
+ e.stopPropagation();
2995
+ removeValue(value);
2996
+ },
2997
+ className: "rounded-full p-0.5 leading-none hover:bg-primary/20",
2998
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-3 w-3", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 6l12 12M18 6L6 18" }) })
2999
+ }
3000
+ )
3001
+ ]
3002
+ },
3003
+ value
3004
+ )),
3005
+ /* @__PURE__ */ jsxRuntime.jsx(
3006
+ "button",
3007
+ {
3008
+ ref: setTriggerRef,
3009
+ type: "button",
3010
+ id,
3011
+ disabled,
3012
+ "aria-haspopup": "listbox",
3013
+ "aria-expanded": open,
3014
+ "aria-controls": open && filtered.length > 0 ? listId : void 0,
3015
+ "aria-invalid": error || void 0,
3016
+ "aria-required": required || void 0,
3017
+ "aria-describedby": describedBy,
3018
+ onClick: () => open ? closePopup() : openPopup(),
3019
+ onKeyDown: onTriggerKeyDown,
3020
+ className: cn(
3021
+ "flex-1 min-w-[60px] text-left bg-transparent border-none outline-none cursor-pointer text-sm disabled:cursor-not-allowed",
3022
+ showPlaceholder && "text-muted-foreground"
3023
+ ),
3024
+ children: multiple ? selected.length === 0 ? placeholder : "" : (selected[0] ? labelFor(selected[0]) : "") || placeholder
3025
+ }
3026
+ ),
3027
+ name && multiple && selected.map((v) => /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: v }, v)),
3028
+ name && !multiple && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: selected[0] ?? "" }),
3029
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) }) })
3030
+ ]
3031
+ }
3032
+ ),
3033
+ open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute z-40 top-[calc(100%+6px)] left-0 w-full min-w-[12rem] bg-surface border border-border rounded-kj-md shadow-kj-lg overflow-hidden animate-[kjpop_.12s_ease]", children: [
3034
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
3035
+ "input",
3036
+ {
3037
+ ref: inputRef,
3038
+ type: "text",
3039
+ role: "combobox",
3040
+ "aria-autocomplete": "list",
3041
+ "aria-expanded": open,
3042
+ "aria-controls": filtered.length > 0 ? listId : void 0,
3043
+ "aria-activedescendant": filtered[activeIndex] ? optionId(activeIndex) : void 0,
3044
+ "aria-label": searchPlaceholder,
3045
+ placeholder: searchPlaceholder,
3046
+ value: search,
3047
+ onChange: (e) => setSearch(e.target.value),
3048
+ onKeyDown: onInputKeyDown,
3049
+ className: "w-full bg-transparent text-sm text-foreground placeholder:text-muted-foreground outline-none px-2 py-1"
3050
+ }
3051
+ ) }),
3052
+ filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ jsxRuntime.jsx(
3053
+ "div",
3054
+ {
3055
+ ref: listRef,
3056
+ id: listId,
3057
+ role: "listbox",
3058
+ "aria-multiselectable": multiple || void 0,
3059
+ "aria-label": placeholder,
3060
+ className: "max-h-60 overflow-y-auto p-1",
3061
+ children: filtered.map((opt, i) => {
3062
+ const isSelected = selected.includes(opt.value);
3063
+ const isActive = i === activeIndex;
3064
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3065
+ "div",
3066
+ {
3067
+ id: optionId(i),
3068
+ role: "option",
3069
+ "aria-selected": isSelected,
3070
+ "aria-disabled": opt.disabled || void 0,
3071
+ "data-active": isActive || void 0,
3072
+ onMouseEnter: () => !opt.disabled && setActiveIndex(i),
3073
+ onClick: () => handleSelect(opt),
3074
+ className: cn(
3075
+ "flex items-center justify-between gap-2 px-3 py-2 rounded-kj-sm text-sm cursor-pointer select-none",
3076
+ opt.disabled && "text-muted-foreground opacity-50 cursor-not-allowed",
3077
+ !opt.disabled && isActive && "bg-primary/10 text-primary",
3078
+ !opt.disabled && !isActive && "text-foreground hover:bg-muted"
3079
+ ),
3080
+ children: [
3081
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: opt.label }),
3082
+ isSelected && /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4 text-primary shrink-0", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m5 12 5 5L20 7" }) })
3083
+ ]
3084
+ },
3085
+ opt.value
3086
+ );
3087
+ })
3088
+ }
3089
+ )
3090
+ ] })
3091
+ ] });
3092
+ }
3093
+ );
3094
+ Combobox.displayName = "Combobox";
3095
+ var ComboboxField = React52__namespace.forwardRef(
3096
+ function ComboboxField2({ label, hint, error, required, className, ...props }, ref) {
3097
+ return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(Combobox, { ref, error: !!error, ...props }) });
3098
+ }
3099
+ );
3100
+ ComboboxField.displayName = "ComboboxField";
3101
+
3102
+ // src/components/calendar-internals.ts
3103
+ function startOfDay(d) {
3104
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate());
3105
+ }
3106
+ function isSameDay(a, b) {
3107
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
3108
+ }
3109
+ function addDays(d, n) {
3110
+ const r = new Date(d);
3111
+ r.setDate(r.getDate() + n);
3112
+ return r;
3113
+ }
3114
+ function addMonths(d, n) {
3115
+ const r = new Date(d);
3116
+ r.setMonth(r.getMonth() + n);
3117
+ return r;
3118
+ }
3119
+ function clampToMonth(year, month, day) {
3120
+ const daysInTarget = new Date(year, month + 1, 0).getDate();
3121
+ return new Date(year, month, Math.min(day, daysInTarget));
3122
+ }
3123
+ function addMonthsClamped(d, n) {
3124
+ return clampToMonth(d.getFullYear(), d.getMonth() + n, d.getDate());
3125
+ }
3126
+ function addYearsClamped(d, n) {
3127
+ return clampToMonth(d.getFullYear() + n, d.getMonth(), d.getDate());
3128
+ }
3129
+ function startOfMonth(d) {
3130
+ return new Date(d.getFullYear(), d.getMonth(), 1);
3131
+ }
3132
+ function startOfWeek(d) {
3133
+ const r = startOfDay(d);
3134
+ r.setDate(r.getDate() - r.getDay());
3135
+ return r;
3136
+ }
3137
+ function buildGridDays(viewMonth) {
3138
+ const gridStart = startOfWeek(startOfMonth(viewMonth));
3139
+ return Array.from({ length: 42 }, (_, i) => addDays(gridStart, i));
3140
+ }
3141
+ function dateKey(d) {
3142
+ return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
3143
+ }
3144
+ function toISODateString(d) {
3145
+ const y = d.getFullYear();
3146
+ const m = String(d.getMonth() + 1).padStart(2, "0");
3147
+ const day = String(d.getDate()).padStart(2, "0");
3148
+ return `${y}-${m}-${day}`;
3149
+ }
3150
+ var monthLabelFormat = new Intl.DateTimeFormat(void 0, { month: "long", year: "numeric" });
3151
+ var fullDateFormat = new Intl.DateTimeFormat(void 0, { dateStyle: "full" });
3152
+ var weekdayShortFormat = new Intl.DateTimeFormat(void 0, { weekday: "short" });
3153
+ var weekdayLongFormat = new Intl.DateTimeFormat(void 0, { weekday: "long" });
3154
+ var weekdayLabels = Array.from({ length: 7 }, (_, i) => {
3155
+ const d = addDays(startOfWeek(/* @__PURE__ */ new Date()), i);
3156
+ return { key: i, short: weekdayShortFormat.format(d), long: weekdayLongFormat.format(d) };
3157
+ });
3158
+ var CalendarGrid = React52__namespace.forwardRef(function CalendarGrid2({ viewMonth, isDayDisabled, cellState, onSelectDay, onFocusDay, initialFocusDate, className }, ref) {
3159
+ const gridDays = React52__namespace.useMemo(() => buildGridDays(viewMonth), [viewMonth]);
3160
+ const inViewMonth = (d) => d.getMonth() === viewMonth.getMonth() && d.getFullYear() === viewMonth.getFullYear();
3161
+ const [focusedDate, setFocusedDate] = React52__namespace.useState(() => startOfDay(initialFocusDate));
3162
+ const pendingFocusRef = React52__namespace.useRef(false);
3163
+ const gridRef = React52__namespace.useRef(null);
3164
+ const rovingTarget = inViewMonth(focusedDate) && !isDayDisabled(focusedDate) ? focusedDate : gridDays.find((d) => inViewMonth(d) && !isDayDisabled(d)) ?? gridDays.find((d) => inViewMonth(d)) ?? gridDays[0];
3165
+ const moveFocusTo = (next, viaKeyboard) => {
3166
+ pendingFocusRef.current = viaKeyboard;
3167
+ setFocusedDate(next);
3168
+ onFocusDay?.(next);
3169
+ };
3170
+ React52__namespace.useEffect(() => {
3171
+ if (!pendingFocusRef.current) return;
3172
+ pendingFocusRef.current = false;
3173
+ const el = gridRef.current?.querySelector(`[data-date="${dateKey(rovingTarget)}"]`);
3174
+ el?.focus();
3175
+ }, [rovingTarget]);
3176
+ const step = (from, delta) => {
3177
+ let next = addDays(from, delta);
3178
+ let guard = 0;
3179
+ while (isDayDisabled(next) && guard < 1e3) {
3180
+ next = addDays(next, delta);
3181
+ guard++;
3182
+ }
3183
+ return isDayDisabled(next) ? from : next;
3184
+ };
3185
+ const selectDay = (d) => {
3186
+ if (isDayDisabled(d)) return;
3187
+ moveFocusTo(d, false);
3188
+ onSelectDay(d);
3189
+ };
3190
+ const onGridKeyDown = (e) => {
3191
+ switch (e.key) {
3192
+ case "ArrowRight":
3193
+ e.preventDefault();
3194
+ moveFocusTo(step(rovingTarget, 1), true);
3195
+ break;
3196
+ case "ArrowLeft":
3197
+ e.preventDefault();
3198
+ moveFocusTo(step(rovingTarget, -1), true);
3199
+ break;
3200
+ case "ArrowDown":
3201
+ e.preventDefault();
3202
+ moveFocusTo(step(rovingTarget, 7), true);
3203
+ break;
3204
+ case "ArrowUp":
3205
+ e.preventDefault();
3206
+ moveFocusTo(step(rovingTarget, -7), true);
3207
+ break;
3208
+ case "Home": {
3209
+ e.preventDefault();
3210
+ const target = startOfWeek(rovingTarget);
3211
+ moveFocusTo(isDayDisabled(target) ? step(target, 1) : target, true);
3212
+ break;
3213
+ }
3214
+ case "End": {
3215
+ e.preventDefault();
3216
+ const target = addDays(startOfWeek(rovingTarget), 6);
3217
+ moveFocusTo(isDayDisabled(target) ? step(target, -1) : target, true);
3218
+ break;
3219
+ }
3220
+ case "PageUp": {
3221
+ e.preventDefault();
3222
+ const target = e.shiftKey ? addYearsClamped(rovingTarget, -1) : addMonthsClamped(rovingTarget, -1);
3223
+ moveFocusTo(isDayDisabled(target) ? step(target, -1) : target, true);
3224
+ break;
3225
+ }
3226
+ case "PageDown": {
3227
+ e.preventDefault();
3228
+ const target = e.shiftKey ? addYearsClamped(rovingTarget, 1) : addMonthsClamped(rovingTarget, 1);
3229
+ moveFocusTo(isDayDisabled(target) ? step(target, 1) : target, true);
3230
+ break;
3231
+ }
3232
+ case "Enter":
3233
+ case " ":
3234
+ e.preventDefault();
3235
+ selectDay(rovingTarget);
3236
+ break;
3237
+ }
3238
+ };
3239
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: gridRef, role: "grid", "aria-label": monthLabelFormat.format(viewMonth), onKeyDown: onGridKeyDown, children: [
3240
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "row", className: "grid grid-cols-7", children: weekdayLabels.map((w) => /* @__PURE__ */ jsxRuntime.jsx(
3241
+ "div",
3242
+ {
3243
+ role: "columnheader",
3244
+ "aria-label": w.long,
3245
+ className: "h-8 flex items-center justify-center text-xs font-medium text-muted-foreground",
3246
+ children: w.short
3247
+ },
3248
+ w.key
3249
+ )) }),
3250
+ Array.from({ length: 6 }, (_, week) => /* @__PURE__ */ jsxRuntime.jsx("div", { role: "row", className: "grid grid-cols-7", children: gridDays.slice(week * 7, week * 7 + 7).map((day) => {
3251
+ if (!inViewMonth(day)) {
3252
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "gridcell", "aria-hidden": "true", className: "h-9" }, dateKey(day));
3253
+ }
3254
+ const disabled = isDayDisabled(day);
3255
+ const state = cellState(day);
3256
+ const isRoving = isSameDay(day, rovingTarget);
3257
+ const isEndpoint = !!(state.selected || state.rangeStart || state.rangeEnd);
3258
+ return /* @__PURE__ */ jsxRuntime.jsx(
3259
+ "button",
3260
+ {
3261
+ type: "button",
3262
+ role: "gridcell",
3263
+ "data-date": dateKey(day),
3264
+ tabIndex: isRoving ? 0 : -1,
3265
+ "aria-selected": isEndpoint,
3266
+ "aria-disabled": disabled || void 0,
3267
+ "aria-label": fullDateFormat.format(day),
3268
+ onMouseEnter: () => onFocusDay?.(day),
3269
+ onClick: () => selectDay(day),
3270
+ className: cn(
3271
+ "h-9 w-9 mx-auto flex items-center justify-center text-sm",
3272
+ state.inRange && !isEndpoint ? "rounded-none" : "rounded-full",
3273
+ "focus:outline-none focus:ring-[3px] focus:ring-ring/30",
3274
+ disabled && "text-muted-foreground opacity-40 cursor-not-allowed",
3275
+ !disabled && isEndpoint && "bg-primary text-primary-foreground",
3276
+ !disabled && state.inRange && !isEndpoint && "bg-primary/15 text-foreground",
3277
+ !disabled && !isEndpoint && !state.inRange && state.today && "ring-1 ring-primary text-primary font-medium",
3278
+ !disabled && !isEndpoint && !state.inRange && !state.today && "text-foreground hover:bg-muted"
3279
+ ),
3280
+ children: day.getDate()
3281
+ },
3282
+ dateKey(day)
3283
+ );
3284
+ }) }, week))
3285
+ ] }) });
3286
+ });
3287
+ CalendarGrid.displayName = "CalendarGrid";
3288
+ var Calendar = React52__namespace.forwardRef(
3289
+ function Calendar2({ value, defaultValue, onChange, month, defaultMonth, onMonthChange, min, max, disabledDates, className }, ref) {
3290
+ const controlled = value !== void 0;
3291
+ const [internalValue, setInternalValue] = React52__namespace.useState(defaultValue);
3292
+ const selected = controlled ? value : internalValue;
3293
+ const monthControlled = month !== void 0;
3294
+ const [internalMonth, setInternalMonth] = React52__namespace.useState(
3295
+ () => startOfMonth(month ?? defaultMonth ?? selected ?? /* @__PURE__ */ new Date())
3296
+ );
3297
+ const viewMonth = monthControlled ? startOfMonth(month) : internalMonth;
3298
+ const setViewMonth = (next) => {
3299
+ const normalized = startOfMonth(next);
3300
+ if (!monthControlled) setInternalMonth(normalized);
3301
+ onMonthChange?.(normalized);
3302
+ };
3303
+ const isDayDisabled = React52__namespace.useCallback(
3304
+ (d) => {
3305
+ if (min && d < startOfDay(min)) return true;
3306
+ if (max && d > startOfDay(max)) return true;
3307
+ return disabledDates?.(d) ?? false;
3308
+ },
3309
+ [min, max, disabledDates]
3310
+ );
3311
+ const commitValue = (d) => {
3312
+ if (!controlled) setInternalValue(d);
3313
+ onChange?.(d);
3314
+ };
3315
+ const today = /* @__PURE__ */ new Date();
3316
+ const cellState = (d) => ({
3317
+ selected: selected ? isSameDay(d, selected) : false,
3318
+ today: isSameDay(d, today)
3319
+ });
3320
+ const inViewMonth = (d) => d.getMonth() === viewMonth.getMonth() && d.getFullYear() === viewMonth.getFullYear();
3321
+ const handleFocusDay = (d) => {
3322
+ if (!inViewMonth(d)) setViewMonth(d);
3323
+ };
3324
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("w-[280px] select-none", className), children: [
3325
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
3326
+ /* @__PURE__ */ jsxRuntime.jsx(
3327
+ "button",
3328
+ {
3329
+ type: "button",
3330
+ "aria-label": "Previous month",
3331
+ onClick: () => setViewMonth(addMonths(viewMonth, -1)),
3332
+ className: "p-1.5 rounded-kj-sm text-muted-foreground hover:bg-muted hover:text-foreground",
3333
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) })
3334
+ }
3335
+ ),
3336
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: monthLabelFormat.format(viewMonth) }),
3337
+ /* @__PURE__ */ jsxRuntime.jsx(
3338
+ "button",
3339
+ {
3340
+ type: "button",
3341
+ "aria-label": "Next month",
3342
+ onClick: () => setViewMonth(addMonths(viewMonth, 1)),
3343
+ className: "p-1.5 rounded-kj-sm text-muted-foreground hover:bg-muted hover:text-foreground",
3344
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) })
3345
+ }
3346
+ )
3347
+ ] }),
3348
+ /* @__PURE__ */ jsxRuntime.jsx(
3349
+ CalendarGrid,
3350
+ {
3351
+ viewMonth,
3352
+ isDayDisabled,
3353
+ cellState,
3354
+ onSelectDay: commitValue,
3355
+ onFocusDay: handleFocusDay,
3356
+ initialFocusDate: selected ?? /* @__PURE__ */ new Date()
3357
+ }
3358
+ )
3359
+ ] });
3360
+ }
3361
+ );
3362
+ Calendar.displayName = "Calendar";
3363
+ var displayFormat = new Intl.DateTimeFormat(void 0, { dateStyle: "medium" });
3364
+ var DatePicker = React52__namespace.forwardRef(
3365
+ function DatePicker2({
3366
+ value,
3367
+ defaultValue,
3368
+ onChange,
3369
+ min,
3370
+ max,
3371
+ disabledDates,
3372
+ placeholder = "Pick a date\u2026",
3373
+ disabled = false,
3374
+ error = false,
3375
+ required = false,
3376
+ className,
3377
+ id,
3378
+ name,
3379
+ "aria-describedby": describedBy
3380
+ }, ref) {
3381
+ const controlled = value !== void 0;
3382
+ const [internalValue, setInternalValue] = React52__namespace.useState(defaultValue);
3383
+ const selected = controlled ? value : internalValue;
3384
+ const [open, setOpen] = React52__namespace.useState(false);
3385
+ const containerRef = React52__namespace.useRef(null);
3386
+ const triggerRef = React52__namespace.useRef(null);
3387
+ const setTriggerRef = (node) => {
3388
+ triggerRef.current = node;
3389
+ if (typeof ref === "function") ref(node);
3390
+ else if (ref) ref.current = node;
3391
+ };
3392
+ const commitValue = (d) => {
3393
+ if (!controlled) setInternalValue(d);
3394
+ onChange?.(d);
3395
+ };
3396
+ const closePopup = React52__namespace.useCallback(() => setOpen(false), []);
3397
+ const openPopup = () => {
3398
+ if (!disabled) setOpen(true);
3399
+ };
3400
+ const handleCalendarChange = (d) => {
3401
+ commitValue(d);
3402
+ closePopup();
3403
+ triggerRef.current?.focus();
3404
+ };
3405
+ React52__namespace.useEffect(() => {
3406
+ if (!open) return;
3407
+ const onDown = (e) => {
3408
+ if (containerRef.current && !containerRef.current.contains(e.target)) closePopup();
3409
+ };
3410
+ document.addEventListener("mousedown", onDown);
3411
+ return () => document.removeEventListener("mousedown", onDown);
3412
+ }, [open, closePopup]);
3413
+ const onTriggerKeyDown = (e) => {
3414
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
3415
+ e.preventDefault();
3416
+ openPopup();
3417
+ } else if (e.key === "Escape" && open) {
3418
+ e.preventDefault();
3419
+ closePopup();
3420
+ }
3421
+ };
3422
+ const onPanelKeyDown = (e) => {
3423
+ if (e.key === "Escape") {
3424
+ e.preventDefault();
3425
+ closePopup();
3426
+ triggerRef.current?.focus();
3427
+ }
3428
+ };
3429
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: cn("relative inline-block w-full", className), children: [
3430
+ /* @__PURE__ */ jsxRuntime.jsxs(
3431
+ "button",
3432
+ {
3433
+ ref: setTriggerRef,
3434
+ type: "button",
3435
+ id,
3436
+ disabled,
3437
+ "aria-haspopup": "grid",
3438
+ "aria-expanded": open,
3439
+ "aria-invalid": error || void 0,
3440
+ "aria-required": required || void 0,
3441
+ "aria-describedby": describedBy,
3442
+ onClick: () => open ? closePopup() : openPopup(),
3443
+ onKeyDown: onTriggerKeyDown,
3444
+ className: cn(
3445
+ "w-full flex items-center justify-between gap-2 border rounded-kj-md bg-surface text-left text-sm",
3446
+ "pl-[0.85rem] pr-3 py-[calc(0.6rem*var(--kj-density,1))]",
3447
+ "transition-[border-color,box-shadow] duration-150",
3448
+ "focus:outline-none focus:border-ring focus:ring-[3px] focus:ring-ring/30",
3449
+ disabled && "bg-muted text-muted-foreground cursor-not-allowed",
3450
+ error ? "border-danger" : "border-input",
3451
+ !selected && "text-muted-foreground"
3452
+ ),
3453
+ children: [
3454
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: selected ? displayFormat.format(selected) : placeholder }),
3455
+ /* @__PURE__ */ jsxRuntime.jsxs(
3456
+ "svg",
3457
+ {
3458
+ viewBox: "0 0 24 24",
3459
+ className: "h-4 w-4 text-muted-foreground shrink-0",
3460
+ fill: "none",
3461
+ stroke: "currentColor",
3462
+ strokeWidth: "2",
3463
+ strokeLinecap: "round",
3464
+ strokeLinejoin: "round",
3465
+ children: [
3466
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
3467
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 10h18M8 2v4M16 2v4" })
3468
+ ]
3469
+ }
3470
+ )
3471
+ ]
3472
+ }
3473
+ ),
3474
+ name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: selected ? toISODateString(selected) : "" }),
3475
+ open && /* @__PURE__ */ jsxRuntime.jsx(
3476
+ "div",
3477
+ {
3478
+ onKeyDown: onPanelKeyDown,
3479
+ className: "absolute z-40 top-[calc(100%+6px)] left-0 bg-surface border border-border rounded-kj-md shadow-kj-lg p-3 animate-[kjpop_.12s_ease]",
3480
+ children: /* @__PURE__ */ jsxRuntime.jsx(Calendar, { value: selected, onChange: handleCalendarChange, min, max, disabledDates })
3481
+ }
3482
+ )
3483
+ ] });
3484
+ }
3485
+ );
3486
+ DatePicker.displayName = "DatePicker";
3487
+ var DatePickerField = React52__namespace.forwardRef(
3488
+ function DatePickerField2({ label, hint, error, required, className, ...props }, ref) {
3489
+ return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(DatePicker, { ref, error: !!error, ...props }) });
3490
+ }
3491
+ );
3492
+ DatePickerField.displayName = "DatePickerField";
3493
+ function isBetweenExclusive(d, lo, hi) {
3494
+ const t = startOfDay(d).getTime();
3495
+ return t > startOfDay(lo).getTime() && t < startOfDay(hi).getTime();
3496
+ }
3497
+ var RangeCalendar = React52__namespace.forwardRef(
3498
+ function RangeCalendar2({ value, defaultValue, onChange, month, defaultMonth, onMonthChange, min, max, disabledDates, className }, ref) {
3499
+ const controlled = value !== void 0;
3500
+ const [internalValue, setInternalValue] = React52__namespace.useState(defaultValue ?? {});
3501
+ const range2 = controlled ? value : internalValue;
3502
+ const monthControlled = month !== void 0;
3503
+ const [internalMonth, setInternalMonth] = React52__namespace.useState(
3504
+ () => startOfMonth(month ?? defaultMonth ?? range2.start ?? /* @__PURE__ */ new Date())
3505
+ );
3506
+ const leftMonth = monthControlled ? startOfMonth(month) : internalMonth;
3507
+ const rightMonth = addMonths(leftMonth, 1);
3508
+ const setViewMonth = (next) => {
3509
+ const normalized = startOfMonth(next);
3510
+ if (!monthControlled) setInternalMonth(normalized);
3511
+ onMonthChange?.(normalized);
3512
+ };
3513
+ const isDayDisabled = React52__namespace.useCallback(
3514
+ (d) => {
3515
+ if (min && d < startOfDay(min)) return true;
3516
+ if (max && d > startOfDay(max)) return true;
3517
+ return disabledDates?.(d) ?? false;
3518
+ },
3519
+ [min, max, disabledDates]
3520
+ );
3521
+ const [pendingStart, setPendingStart] = React52__namespace.useState(void 0);
3522
+ const [hoverDate, setHoverDate] = React52__namespace.useState(void 0);
3523
+ const commitRange = (next) => {
3524
+ if (!controlled) setInternalValue(next);
3525
+ onChange?.(next);
3526
+ };
3527
+ const handleSelectDay = (d) => {
3528
+ const day = startOfDay(d);
3529
+ if (pendingStart === void 0) {
3530
+ setPendingStart(day);
3531
+ setHoverDate(void 0);
3532
+ return;
3533
+ }
3534
+ if (day < startOfDay(pendingStart)) {
3535
+ setPendingStart(day);
3536
+ setHoverDate(void 0);
3537
+ return;
3538
+ }
3539
+ commitRange({ start: pendingStart, end: day });
3540
+ setPendingStart(void 0);
3541
+ setHoverDate(void 0);
3542
+ };
3543
+ const today = /* @__PURE__ */ new Date();
3544
+ const previewEnd = pendingStart !== void 0 ? hoverDate : void 0;
3545
+ const cellState = (d) => {
3546
+ const isToday = isSameDay(d, today);
3547
+ if (pendingStart !== void 0) {
3548
+ if (previewEnd === void 0) {
3549
+ return { rangeStart: isSameDay(d, pendingStart), today: isToday };
3550
+ }
3551
+ if (startOfDay(previewEnd) < startOfDay(pendingStart)) {
3552
+ return { rangeStart: isSameDay(d, previewEnd), today: isToday };
3553
+ }
3554
+ return {
3555
+ rangeStart: isSameDay(d, pendingStart),
3556
+ rangeEnd: isSameDay(d, previewEnd),
3557
+ inRange: isBetweenExclusive(d, pendingStart, previewEnd),
3558
+ today: isToday
3559
+ };
3560
+ }
3561
+ if (range2.start && range2.end) {
3562
+ return {
3563
+ rangeStart: isSameDay(d, range2.start),
3564
+ rangeEnd: isSameDay(d, range2.end),
3565
+ inRange: isBetweenExclusive(d, range2.start, range2.end),
3566
+ today: isToday
3567
+ };
3568
+ }
3569
+ return { rangeStart: range2.start ? isSameDay(d, range2.start) : false, today: isToday };
3570
+ };
3571
+ const inLockedRange = (d) => d.getMonth() === leftMonth.getMonth() && d.getFullYear() === leftMonth.getFullYear() || d.getMonth() === rightMonth.getMonth() && d.getFullYear() === rightMonth.getFullYear();
3572
+ const handleFocusDay = (d) => {
3573
+ if (pendingStart !== void 0) setHoverDate(d);
3574
+ if (!inLockedRange(d)) setViewMonth(d);
3575
+ };
3576
+ const navButton = (direction) => /* @__PURE__ */ jsxRuntime.jsx(
3577
+ "button",
3578
+ {
3579
+ type: "button",
3580
+ "aria-label": direction === "prev" ? "Previous month" : "Next month",
3581
+ onClick: () => setViewMonth(addMonths(leftMonth, direction === "prev" ? -1 : 1)),
3582
+ className: "p-1.5 rounded-kj-sm text-muted-foreground hover:bg-muted hover:text-foreground",
3583
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: direction === "prev" ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) : /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) })
3584
+ }
3585
+ );
3586
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("flex gap-6 select-none", className), children: [
3587
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-[280px]", children: [
3588
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
3589
+ navButton("prev"),
3590
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: monthLabelFormat.format(leftMonth) }),
3591
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-[26px]", "aria-hidden": "true" })
3592
+ ] }),
3593
+ /* @__PURE__ */ jsxRuntime.jsx(
3594
+ CalendarGrid,
3595
+ {
3596
+ viewMonth: leftMonth,
3597
+ isDayDisabled,
3598
+ cellState,
3599
+ onSelectDay: handleSelectDay,
3600
+ onFocusDay: handleFocusDay,
3601
+ initialFocusDate: pendingStart ?? range2.start ?? /* @__PURE__ */ new Date()
3602
+ }
3603
+ )
3604
+ ] }),
3605
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-[280px]", children: [
3606
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
3607
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-[26px]", "aria-hidden": "true" }),
3608
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: monthLabelFormat.format(rightMonth) }),
3609
+ navButton("next")
3610
+ ] }),
3611
+ /* @__PURE__ */ jsxRuntime.jsx(
3612
+ CalendarGrid,
3613
+ {
3614
+ viewMonth: rightMonth,
3615
+ isDayDisabled,
3616
+ cellState,
3617
+ onSelectDay: handleSelectDay,
3618
+ onFocusDay: handleFocusDay,
3619
+ initialFocusDate: pendingStart ?? range2.start ?? /* @__PURE__ */ new Date()
3620
+ }
3621
+ )
3622
+ ] })
3623
+ ] });
3624
+ }
3625
+ );
3626
+ RangeCalendar.displayName = "RangeCalendar";
3627
+ var displayFormat2 = new Intl.DateTimeFormat(void 0, { dateStyle: "medium" });
3628
+ function formatRangeLabel(range2) {
3629
+ if (!range2.start || !range2.end) return void 0;
3630
+ return `${displayFormat2.format(range2.start)} \u2013 ${displayFormat2.format(range2.end)}`;
3631
+ }
3632
+ var DateRangePicker = React52__namespace.forwardRef(
3633
+ function DateRangePicker2({
3634
+ value,
3635
+ defaultValue,
3636
+ onChange,
3637
+ min,
3638
+ max,
3639
+ disabledDates,
3640
+ placeholder = "Pick a date range\u2026",
3641
+ disabled = false,
3642
+ error = false,
3643
+ required = false,
3644
+ className,
3645
+ id,
3646
+ name,
3647
+ "aria-describedby": describedBy
3648
+ }, ref) {
3649
+ const controlled = value !== void 0;
3650
+ const [internalValue, setInternalValue] = React52__namespace.useState(defaultValue ?? {});
3651
+ const selected = controlled ? value : internalValue;
3652
+ const [open, setOpen] = React52__namespace.useState(false);
3653
+ const containerRef = React52__namespace.useRef(null);
3654
+ const triggerRef = React52__namespace.useRef(null);
3655
+ const setTriggerRef = (node) => {
3656
+ triggerRef.current = node;
3657
+ if (typeof ref === "function") ref(node);
3658
+ else if (ref) ref.current = node;
3659
+ };
3660
+ const commitValue = (r) => {
3661
+ if (!controlled) setInternalValue(r);
3662
+ onChange?.(r);
3663
+ };
3664
+ const closePopup = React52__namespace.useCallback(() => setOpen(false), []);
3665
+ const openPopup = () => {
3666
+ if (!disabled) setOpen(true);
3667
+ };
3668
+ const handleRangeChange = (r) => {
3669
+ commitValue(r);
3670
+ closePopup();
3671
+ triggerRef.current?.focus();
3672
+ };
3673
+ React52__namespace.useEffect(() => {
3674
+ if (!open) return;
3675
+ const onDown = (e) => {
3676
+ if (containerRef.current && !containerRef.current.contains(e.target)) closePopup();
3677
+ };
3678
+ document.addEventListener("mousedown", onDown);
3679
+ return () => document.removeEventListener("mousedown", onDown);
3680
+ }, [open, closePopup]);
3681
+ const onTriggerKeyDown = (e) => {
3682
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
3683
+ e.preventDefault();
3684
+ openPopup();
3685
+ } else if (e.key === "Escape" && open) {
3686
+ e.preventDefault();
3687
+ closePopup();
3688
+ triggerRef.current?.focus();
3689
+ }
3690
+ };
3691
+ const onPanelKeyDown = (e) => {
3692
+ if (e.key === "Escape") {
3693
+ e.preventDefault();
3694
+ closePopup();
3695
+ triggerRef.current?.focus();
3696
+ }
3697
+ };
3698
+ const label = formatRangeLabel(selected);
3699
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: cn("relative inline-block w-full", className), children: [
3700
+ /* @__PURE__ */ jsxRuntime.jsxs(
3701
+ "button",
3702
+ {
3703
+ ref: setTriggerRef,
3704
+ type: "button",
3705
+ id,
3706
+ disabled,
3707
+ "aria-haspopup": "dialog",
3708
+ "aria-expanded": open,
3709
+ "aria-invalid": error || void 0,
3710
+ "aria-required": required || void 0,
3711
+ "aria-describedby": describedBy,
3712
+ onClick: () => open ? closePopup() : openPopup(),
3713
+ onKeyDown: onTriggerKeyDown,
3714
+ className: cn(
3715
+ "w-full flex items-center justify-between gap-2 border rounded-kj-md bg-surface text-left text-sm",
3716
+ "pl-[0.85rem] pr-3 py-[calc(0.6rem*var(--kj-density,1))]",
3717
+ "transition-[border-color,box-shadow] duration-150",
3718
+ "focus:outline-none focus:border-ring focus:ring-[3px] focus:ring-ring/30",
3719
+ disabled && "bg-muted text-muted-foreground cursor-not-allowed",
3720
+ error ? "border-danger" : "border-input",
3721
+ !label && "text-muted-foreground"
3722
+ ),
3723
+ children: [
3724
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label ?? placeholder }),
3725
+ /* @__PURE__ */ jsxRuntime.jsxs(
3726
+ "svg",
3727
+ {
3728
+ viewBox: "0 0 24 24",
3729
+ className: "h-4 w-4 text-muted-foreground shrink-0",
3730
+ fill: "none",
3731
+ stroke: "currentColor",
3732
+ strokeWidth: "2",
3733
+ strokeLinecap: "round",
3734
+ strokeLinejoin: "round",
3735
+ children: [
3736
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
3737
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 10h18M8 2v4M16 2v4" })
3738
+ ]
3739
+ }
3740
+ )
3741
+ ]
3742
+ }
3743
+ ),
3744
+ name && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3745
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name: `${name}Start`, value: selected.start ? toISODateString(selected.start) : "" }),
3746
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name: `${name}End`, value: selected.end ? toISODateString(selected.end) : "" })
3747
+ ] }),
3748
+ open && /* @__PURE__ */ jsxRuntime.jsx(
3749
+ "div",
3750
+ {
3751
+ onKeyDown: onPanelKeyDown,
3752
+ className: "absolute z-40 top-[calc(100%+6px)] left-0 bg-surface border border-border rounded-kj-md shadow-kj-lg p-3 animate-[kjpop_.12s_ease]",
3753
+ children: /* @__PURE__ */ jsxRuntime.jsx(RangeCalendar, { value: selected, onChange: handleRangeChange, min, max, disabledDates })
3754
+ }
3755
+ )
3756
+ ] });
3757
+ }
3758
+ );
3759
+ DateRangePicker.displayName = "DateRangePicker";
3760
+ var DateRangePickerField = React52__namespace.forwardRef(
3761
+ function DateRangePickerField2({ label, hint, error, required, className, ...props }, ref) {
3762
+ return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(DateRangePicker, { ref, error: !!error, ...props }) });
3763
+ }
3764
+ );
3765
+ DateRangePickerField.displayName = "DateRangePickerField";
3766
+ var Dropzone = React52__namespace.forwardRef(
3767
+ function Dropzone2({
3768
+ onFiles,
3769
+ accept,
3770
+ multiple = true,
3771
+ disabled = false,
3772
+ className,
3773
+ children,
3774
+ id,
3775
+ "aria-describedby": describedBy,
3776
+ "aria-invalid": ariaInvalid,
3777
+ "aria-required": ariaRequired
3778
+ }, ref) {
3779
+ const inputRef = React52__namespace.useRef(null);
3780
+ const [dragActive, setDragActive] = React52__namespace.useState(false);
3781
+ const dragCounter = React52__namespace.useRef(0);
3782
+ const invalid = ariaInvalid === true || ariaInvalid === "true";
3783
+ const openPicker = () => {
3784
+ if (!disabled) inputRef.current?.click();
3785
+ };
3786
+ const handleInputChange = (e) => {
3787
+ const files = e.target.files ? Array.from(e.target.files) : [];
3788
+ if (files.length > 0) onFiles(files);
3789
+ e.target.value = "";
3790
+ };
3791
+ const handleDragEnter = (e) => {
3792
+ e.preventDefault();
3793
+ if (disabled) return;
3794
+ dragCounter.current += 1;
3795
+ setDragActive(true);
3796
+ };
3797
+ const handleDragOver = (e) => {
3798
+ e.preventDefault();
3799
+ };
3800
+ const handleDragLeave = (e) => {
3801
+ e.preventDefault();
3802
+ if (disabled) return;
3803
+ dragCounter.current -= 1;
3804
+ if (dragCounter.current <= 0) {
3805
+ dragCounter.current = 0;
3806
+ setDragActive(false);
3807
+ }
3808
+ };
3809
+ const handleDrop = (e) => {
3810
+ e.preventDefault();
3811
+ dragCounter.current = 0;
3812
+ setDragActive(false);
3813
+ if (disabled) return;
3814
+ const files = e.dataTransfer?.files ? Array.from(e.dataTransfer.files) : [];
3815
+ if (files.length > 0) onFiles(files);
3816
+ };
3817
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full", className), children: [
3818
+ /* @__PURE__ */ jsxRuntime.jsx(
3819
+ "button",
3820
+ {
3821
+ ref,
3822
+ type: "button",
3823
+ id,
3824
+ disabled,
3825
+ "aria-describedby": describedBy,
3826
+ "aria-invalid": ariaInvalid,
3827
+ "aria-required": ariaRequired,
3828
+ "data-drag-active": dragActive || void 0,
3829
+ onClick: openPicker,
3830
+ onDragEnter: handleDragEnter,
3831
+ onDragOver: handleDragOver,
3832
+ onDragLeave: handleDragLeave,
3833
+ onDrop: handleDrop,
3834
+ className: cn(
3835
+ "w-full flex flex-col items-center justify-center gap-2 rounded-kj-md border-2 border-dashed px-6 py-8 text-center text-sm transition-colors",
3836
+ "focus:outline-none focus:ring-[3px] focus:ring-ring/30",
3837
+ disabled ? "border-input bg-muted text-muted-foreground cursor-not-allowed" : dragActive ? "border-primary bg-primary/5 text-foreground cursor-pointer" : invalid ? "border-danger bg-surface text-muted-foreground hover:text-foreground cursor-pointer" : "border-input bg-surface text-muted-foreground hover:border-primary hover:text-foreground cursor-pointer"
3838
+ ),
3839
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3840
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", className: "h-7 w-7", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
3841
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 16V4M7 9l5-5 5 5" }),
3842
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 16v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3" })
3843
+ ] }),
3844
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3845
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: "Drag and drop files here" }),
3846
+ ", or click to browse"
3847
+ ] })
3848
+ ] })
3849
+ }
3850
+ ),
3851
+ /* @__PURE__ */ jsxRuntime.jsx(
3852
+ "input",
3853
+ {
3854
+ ref: inputRef,
3855
+ type: "file",
3856
+ accept,
3857
+ multiple,
3858
+ disabled,
3859
+ onChange: handleInputChange,
3860
+ className: "sr-only",
3861
+ tabIndex: -1,
3862
+ "aria-hidden": "true"
3863
+ }
3864
+ )
3865
+ ] });
3866
+ }
3867
+ );
3868
+ Dropzone.displayName = "Dropzone";
3869
+
3870
+ // src/components/file-upload-internals.ts
3871
+ var KB = 1024;
3872
+ function formatBytes(bytes) {
3873
+ if (bytes < KB) return `${bytes} B`;
3874
+ const units = ["KB", "MB", "GB", "TB"];
3875
+ let value = bytes / KB;
3876
+ let unitIndex = 0;
3877
+ while (value >= KB && unitIndex < units.length - 1) {
3878
+ value /= KB;
3879
+ unitIndex++;
3880
+ }
3881
+ return `${value.toFixed(1)} ${units[unitIndex]}`;
3882
+ }
3883
+ function matchesAccept(file, accept) {
3884
+ if (!accept || accept.trim() === "") return true;
3885
+ const tokens = accept.split(",").map((t) => t.trim()).filter(Boolean);
3886
+ if (tokens.length === 0) return true;
3887
+ const fileType = file.type.toLowerCase();
3888
+ const fileName = file.name.toLowerCase();
3889
+ return tokens.some((token) => {
3890
+ const t = token.toLowerCase();
3891
+ if (t.startsWith(".")) return fileName.endsWith(t);
3892
+ if (t.endsWith("/*")) return fileType.startsWith(t.slice(0, -1));
3893
+ return fileType === t;
3894
+ });
3895
+ }
3896
+ var idCounter = 0;
3897
+ function generateId() {
3898
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
3899
+ return crypto.randomUUID();
3900
+ }
3901
+ idCounter += 1;
3902
+ return `file-${Date.now().toString(36)}-${idCounter}-${Math.random().toString(36).slice(2, 8)}`;
3903
+ }
3904
+ function validateFiles(files, { accept, maxSize, maxFiles, existingCount = 0, multiple = true }) {
3905
+ const accepted = [];
3906
+ const rejected = [];
3907
+ const effectiveExisting = multiple ? existingCount : 0;
3908
+ for (const file of files) {
3909
+ if (!matchesAccept(file, accept)) {
3910
+ rejected.push({ file, reason: "type" });
3911
+ continue;
3912
+ }
3913
+ if (maxSize != null && file.size > maxSize) {
3914
+ rejected.push({ file, reason: "size" });
3915
+ continue;
3916
+ }
3917
+ if (!multiple) {
3918
+ if (accepted.length === 0) accepted.push(file);
3919
+ else rejected.push({ file, reason: "count" });
3920
+ continue;
3921
+ }
3922
+ const capacity = maxFiles != null ? maxFiles - effectiveExisting - accepted.length : Infinity;
3923
+ if (capacity <= 0) {
3924
+ rejected.push({ file, reason: "count" });
3925
+ continue;
3926
+ }
3927
+ accepted.push(file);
3928
+ }
3929
+ return { accepted, rejected };
3930
+ }
3931
+ function FileIcon({ className }) {
3932
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", className, fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
3933
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
3934
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2v6h6" })
3935
+ ] });
3936
+ }
3937
+ var FileUpload = React52__namespace.forwardRef(
3938
+ function FileUpload2({
3939
+ value,
3940
+ defaultValue,
3941
+ onChange,
3942
+ onReject,
3943
+ accept,
3944
+ maxSize,
3945
+ maxFiles,
3946
+ multiple = true,
3947
+ disabled = false,
3948
+ error = false,
3949
+ required = false,
3950
+ className,
3951
+ id,
3952
+ "aria-describedby": describedBy
3953
+ }, ref) {
3954
+ const controlled = value !== void 0;
3955
+ const [internalItems, setInternalItems] = React52__namespace.useState(defaultValue ?? []);
3956
+ const items = controlled ? value : internalItems;
3957
+ const commit = (next) => {
3958
+ if (!controlled) setInternalItems(next);
3959
+ onChange?.(next);
3960
+ };
3961
+ const handleFiles = (files) => {
3962
+ const { accepted, rejected } = validateFiles(files, {
3963
+ accept,
3964
+ maxSize,
3965
+ maxFiles,
3966
+ existingCount: items.length,
3967
+ multiple
3968
+ });
3969
+ if (rejected.length > 0) onReject?.(rejected);
3970
+ if (accepted.length === 0) return;
3971
+ const newItems = accepted.map((file) => ({
3972
+ id: generateId(),
3973
+ file,
3974
+ status: "pending"
3975
+ }));
3976
+ commit(multiple ? [...items, ...newItems] : newItems.slice(0, 1));
3977
+ };
3978
+ const removeItem = (itemId) => {
3979
+ commit(items.filter((it) => it.id !== itemId));
3980
+ };
3981
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full flex flex-col gap-3", className), children: [
3982
+ /* @__PURE__ */ jsxRuntime.jsx(
3983
+ Dropzone,
3984
+ {
3985
+ ref,
3986
+ onFiles: handleFiles,
3987
+ accept,
3988
+ multiple,
3989
+ disabled,
3990
+ id,
3991
+ "aria-describedby": describedBy,
3992
+ "aria-invalid": error || void 0,
3993
+ "aria-required": required || void 0
3994
+ }
3995
+ ),
3996
+ items.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-2", children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
3997
+ "li",
3998
+ {
3999
+ className: "flex items-center gap-3 rounded-kj-md border border-border bg-surface px-3 py-2",
4000
+ children: [
4001
+ /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { className: "h-5 w-5 shrink-0 text-muted-foreground" }),
4002
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
4003
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
4004
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm text-foreground", children: item.file.name }),
4005
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatBytes(item.file.size) })
4006
+ ] }),
4007
+ item.status === "uploading" && item.progress != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 flex items-center gap-2", children: [
4008
+ /* @__PURE__ */ jsxRuntime.jsx(Progress, { value: item.progress, className: "h-1.5" }),
4009
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
4010
+ Math.round(item.progress),
4011
+ "%"
4012
+ ] })
4013
+ ] }),
4014
+ item.status === "success" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 block text-xs text-success", children: "Uploaded" }),
4015
+ item.status === "error" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 block text-xs text-danger", children: item.error ?? "Upload failed" })
4016
+ ] }),
4017
+ !disabled && /* @__PURE__ */ jsxRuntime.jsx(
4018
+ "button",
4019
+ {
4020
+ type: "button",
4021
+ "aria-label": `Remove ${item.file.name}`,
4022
+ onClick: () => removeItem(item.id),
4023
+ className: "shrink-0 rounded-kj-sm p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
4024
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
4025
+ }
4026
+ )
4027
+ ]
4028
+ },
4029
+ item.id
4030
+ )) })
4031
+ ] });
4032
+ }
4033
+ );
4034
+ FileUpload.displayName = "FileUpload";
4035
+ var FileUploadField = React52__namespace.forwardRef(
4036
+ function FileUploadField2({ label, hint, error, required, className, ...props }, ref) {
4037
+ return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(FileUpload, { ref, error: !!error, ...props }) });
4038
+ }
4039
+ );
4040
+ FileUploadField.displayName = "FileUploadField";
4041
+ var TimelineContext = React52__namespace.createContext(null);
4042
+ var TimelineItemContext = React52__namespace.createContext(null);
4043
+ var Timeline = React52__namespace.forwardRef(
4044
+ ({ align = "left", className, children, ...props }, ref) => {
4045
+ const validChildren = React52__namespace.Children.toArray(children).filter(React52__namespace.isValidElement);
4046
+ const count = validChildren.length;
4047
+ const childrenWithIndex = validChildren.map((child, index) => {
4048
+ return React52__namespace.cloneElement(child, {
4049
+ index
4050
+ });
4051
+ });
4052
+ return /* @__PURE__ */ jsxRuntime.jsx(TimelineContext.Provider, { value: { align, count }, children: /* @__PURE__ */ jsxRuntime.jsx(
4053
+ "div",
4054
+ {
4055
+ ref,
4056
+ role: "list",
4057
+ className: cn("flex flex-col gap-6 w-full", className),
4058
+ ...props,
4059
+ children: childrenWithIndex
4060
+ }
4061
+ ) });
4062
+ }
4063
+ );
4064
+ Timeline.displayName = "Timeline";
4065
+ var TimelineItem = React52__namespace.forwardRef(
4066
+ ({ className, index = 0, children, ...props }, ref) => {
4067
+ const ctx = React52__namespace.useContext(TimelineContext);
4068
+ if (!ctx) throw new Error("TimelineItem must be used within a Timeline");
4069
+ const { align, count } = ctx;
4070
+ const isEven = index % 2 === 0;
4071
+ const isLast = index === count - 1;
4072
+ const gridClass = cn(
4073
+ "grid w-full gap-4 items-start group/timeline-item",
4074
+ align === "left" && "grid-cols-[auto_1fr]",
4075
+ align === "right" && "grid-cols-[1fr_auto] text-right",
4076
+ align === "alternate" && "md:grid-cols-[1fr_auto_1fr] grid-cols-[auto_1fr]"
4077
+ );
4078
+ return /* @__PURE__ */ jsxRuntime.jsx(TimelineItemContext.Provider, { value: { isEven, align, isLast }, children: /* @__PURE__ */ jsxRuntime.jsx(
4079
+ "div",
4080
+ {
4081
+ ref,
4082
+ role: "listitem",
4083
+ className: cn(gridClass, className),
4084
+ ...props,
4085
+ children
4086
+ }
4087
+ ) });
4088
+ }
4089
+ );
4090
+ TimelineItem.displayName = "TimelineItem";
4091
+ var TimelineSeparator = React52__namespace.forwardRef(
4092
+ ({ className, align: propAlign, ...props }, ref) => {
4093
+ const ctx = React52__namespace.useContext(TimelineItemContext);
4094
+ const align = propAlign ?? ctx?.align ?? "left";
4095
+ const separatorClass = cn(
4096
+ "flex flex-col items-center justify-self-center h-full min-h-[40px]",
4097
+ align === "alternate" && "md:col-start-2 col-start-1",
4098
+ align === "left" && "col-start-1",
4099
+ align === "right" && "col-start-2",
4100
+ className
4101
+ );
4102
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: separatorClass, ...props });
4103
+ }
4104
+ );
4105
+ TimelineSeparator.displayName = "TimelineSeparator";
4106
+ var TimelineConnector = React52__namespace.forwardRef(
4107
+ ({ className, dashed, ...props }, ref) => {
4108
+ const ctx = React52__namespace.useContext(TimelineItemContext);
4109
+ const isLast = ctx?.isLast ?? false;
4110
+ const connectorClass = cn(
4111
+ "grow",
4112
+ isLast && "hidden",
4113
+ dashed ? "w-0 border-l border-dashed border-border" : "w-0.5 bg-border",
4114
+ className
4115
+ );
4116
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: connectorClass, ...props });
4117
+ }
4118
+ );
4119
+ TimelineConnector.displayName = "TimelineConnector";
4120
+ var TimelineDot = React52__namespace.forwardRef(
4121
+ ({ className, variant = "default", size = "md", ...props }, ref) => {
4122
+ const sizeClasses2 = {
4123
+ sm: "w-2.5 h-2.5 rounded-full my-1.5",
4124
+ md: "w-4 h-4 rounded-full my-1 border-2 bg-background border-border",
4125
+ lg: "w-8 h-8 rounded-full border flex items-center justify-center bg-background text-[0.8rem]"
4126
+ };
4127
+ const variantClasses = {
4128
+ default: "border-border text-muted-foreground",
4129
+ primary: "border-primary bg-primary/5 text-primary",
4130
+ secondary: "border-secondary bg-secondary/5 text-secondary",
4131
+ success: "border-success bg-success-surface text-success",
4132
+ warning: "border-warning bg-warning-surface text-warning",
4133
+ danger: "border-danger bg-danger-surface text-danger"
4134
+ };
4135
+ return /* @__PURE__ */ jsxRuntime.jsx(
4136
+ "div",
4137
+ {
4138
+ ref,
4139
+ className: cn(
4140
+ "shrink-0 select-none",
4141
+ sizeClasses2[size],
4142
+ variantClasses[variant],
4143
+ className
4144
+ ),
4145
+ ...props
4146
+ }
4147
+ );
4148
+ }
4149
+ );
4150
+ TimelineDot.displayName = "TimelineDot";
4151
+ var TimelineContent = React52__namespace.forwardRef(
4152
+ ({ className, isEven: propIsEven, align: propAlign, ...props }, ref) => {
4153
+ const ctx = React52__namespace.useContext(TimelineItemContext);
4154
+ const isEven = propIsEven ?? ctx?.isEven ?? false;
4155
+ const align = propAlign ?? ctx?.align ?? "left";
4156
+ const contentClass = cn(
4157
+ "pb-8 flex flex-col gap-1 w-full",
4158
+ align === "left" && "col-start-2 text-left",
4159
+ align === "right" && "col-start-1 text-right",
4160
+ align === "alternate" && (isEven ? "md:col-start-3 col-start-2 text-left" : "md:col-start-1 col-start-2 md:text-right text-left"),
4161
+ className
4162
+ );
4163
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: contentClass, ...props });
4164
+ }
4165
+ );
4166
+ TimelineContent.displayName = "TimelineContent";
4167
+ var TimelineTitle = React52__namespace.forwardRef(
4168
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
4169
+ "h4",
4170
+ {
4171
+ ref,
4172
+ className: cn("m-0 text-sm font-semibold tracking-[-0.01em] text-foreground", className),
4173
+ ...props,
4174
+ children
4175
+ }
4176
+ )
4177
+ );
4178
+ TimelineTitle.displayName = "TimelineTitle";
4179
+ var TimelineTime = React52__namespace.forwardRef(
4180
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
4181
+ "time",
4182
+ {
4183
+ ref,
4184
+ className: cn("text-[0.75rem] text-muted-foreground font-normal", className),
4185
+ ...props
4186
+ }
4187
+ )
4188
+ );
4189
+ TimelineTime.displayName = "TimelineTime";
4190
+ function useStepper({ initialStep = 0, stepsCount }) {
4191
+ const safeStepsCount = Math.max(1, stepsCount);
4192
+ const [activeStep, setActiveStep] = React52__namespace.useState(initialStep);
4193
+ const [completedSteps, setCompletedSteps] = React52__namespace.useState([]);
4194
+ const setStep = React52__namespace.useCallback((step) => {
4195
+ if (step >= 0 && step < safeStepsCount) {
4196
+ setActiveStep(step);
4197
+ }
4198
+ }, [safeStepsCount]);
4199
+ const nextStep = React52__namespace.useCallback(() => {
4200
+ setActiveStep((prev) => Math.min(prev + 1, safeStepsCount - 1));
4201
+ }, [safeStepsCount]);
4202
+ const prevStep = React52__namespace.useCallback(() => {
4203
+ setActiveStep((prev) => Math.max(prev - 1, 0));
4204
+ }, []);
4205
+ const completeStep = React52__namespace.useCallback((step) => {
4206
+ setCompletedSteps((prev) => {
4207
+ if (step < 0 || step >= safeStepsCount) return prev;
4208
+ if (prev.includes(step)) return prev;
4209
+ return [...prev, step].sort((a, b) => a - b);
4210
+ });
4211
+ }, [safeStepsCount]);
4212
+ const uncompleteStep = React52__namespace.useCallback((step) => {
4213
+ setCompletedSteps((prev) => prev.filter((s) => s !== step));
4214
+ }, []);
4215
+ const reset = React52__namespace.useCallback(() => {
4216
+ setActiveStep(initialStep);
4217
+ setCompletedSteps([]);
4218
+ }, [initialStep]);
4219
+ return {
4220
+ activeStep,
4221
+ completedSteps,
4222
+ setStep,
4223
+ nextStep,
4224
+ prevStep,
4225
+ completeStep,
4226
+ uncompleteStep,
4227
+ reset,
4228
+ isFirstStep: activeStep === 0,
4229
+ isLastStep: activeStep === safeStepsCount - 1
4230
+ };
4231
+ }
4232
+ var StepperContext = React52__namespace.createContext(null);
4233
+ var StepperItemContext = React52__namespace.createContext(null);
4234
+ var Stepper = React52__namespace.forwardRef(
4235
+ ({ value, defaultValue, onValueChange, orientation = "horizontal", linear = true, children, className, ...props }, ref) => {
4236
+ const [localValue, setLocalValue] = React52__namespace.useState(defaultValue ?? 0);
4237
+ const isControlled = value !== void 0;
4238
+ const activeStep = isControlled ? value : localValue;
4239
+ const [steps, setSteps] = React52__namespace.useState([]);
4240
+ const [completedSteps, setCompletedSteps] = React52__namespace.useState([]);
4241
+ const registerStep = React52__namespace.useCallback((val) => {
4242
+ setSteps((prev) => prev.includes(val) ? prev : [...prev, val].sort((a, b) => a - b));
4243
+ }, []);
4244
+ const unregisterStep = React52__namespace.useCallback((val) => {
4245
+ setSteps((prev) => prev.filter((v) => v !== val));
4246
+ }, []);
4247
+ const setStep = React52__namespace.useCallback(
4248
+ (step) => {
4249
+ if (!isControlled) {
4250
+ setLocalValue(step);
4251
+ }
4252
+ onValueChange?.(step);
4253
+ if (linear) {
4254
+ setCompletedSteps((prev) => {
4255
+ const priorSteps = steps.filter((s) => s < step);
4256
+ const nextCompleted = Array.from(/* @__PURE__ */ new Set([...prev, ...priorSteps])).sort((a, b) => a - b);
4257
+ return nextCompleted;
4258
+ });
4259
+ }
4260
+ },
4261
+ [isControlled, onValueChange, linear, steps]
4262
+ );
4263
+ const contextValue = React52__namespace.useMemo(
4264
+ () => ({
4265
+ activeStep,
4266
+ orientation,
4267
+ linear,
4268
+ setStep,
4269
+ completedSteps,
4270
+ registerStep,
4271
+ unregisterStep,
4272
+ steps
4273
+ }),
4274
+ [activeStep, orientation, linear, setStep, completedSteps, registerStep, unregisterStep, steps]
4275
+ );
4276
+ return /* @__PURE__ */ jsxRuntime.jsx(StepperContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
4277
+ "div",
4278
+ {
4279
+ ref,
4280
+ className: cn(
4281
+ "w-full",
4282
+ orientation === "vertical" ? "flex flex-col gap-6" : "space-y-6",
4283
+ className
4284
+ ),
4285
+ ...props,
4286
+ children
4287
+ }
4288
+ ) });
4289
+ }
4290
+ );
4291
+ Stepper.displayName = "Stepper";
4292
+ var StepperContent = React52__namespace.forwardRef(
4293
+ ({ value, className, children, ...props }, ref) => {
4294
+ const ctx = React52__namespace.useContext(StepperContext);
4295
+ if (!ctx) throw new Error("StepperContent must be used within a Stepper");
4296
+ const isActive = ctx.activeStep === value;
4297
+ if (!isActive) return null;
4298
+ return /* @__PURE__ */ jsxRuntime.jsx(
4299
+ "div",
4300
+ {
4301
+ ref,
4302
+ role: "tabpanel",
4303
+ tabIndex: 0,
4304
+ className: cn("focus-visible:outline-none w-full", className),
4305
+ ...props,
4306
+ children
4307
+ }
4308
+ );
4309
+ }
4310
+ );
4311
+ StepperContent.displayName = "StepperContent";
4312
+ var StepperList = React52__namespace.forwardRef(
4313
+ ({ className, children, ...props }, ref) => {
4314
+ const ctx = React52__namespace.useContext(StepperContext);
4315
+ if (!ctx) throw new Error("StepperList must be used within a Stepper");
4316
+ return /* @__PURE__ */ jsxRuntime.jsx(
4317
+ "div",
4318
+ {
4319
+ ref,
4320
+ role: "tablist",
4321
+ "aria-orientation": ctx.orientation,
4322
+ className: cn(
4323
+ ctx.orientation === "horizontal" ? "flex items-center justify-between w-full relative gap-4" : "flex flex-col items-start gap-6 relative w-full",
4324
+ className
4325
+ ),
4326
+ ...props,
4327
+ children
4328
+ }
4329
+ );
4330
+ }
4331
+ );
4332
+ StepperList.displayName = "StepperList";
4333
+ var StepperItem = React52__namespace.forwardRef(
4334
+ ({ value, disabled = false, className, children, ...props }, ref) => {
4335
+ const ctx = React52__namespace.useContext(StepperContext);
4336
+ if (!ctx) throw new Error("StepperItem must be used within a Stepper");
4337
+ const { registerStep, unregisterStep } = ctx;
4338
+ React52__namespace.useEffect(() => {
4339
+ registerStep(value);
4340
+ return () => unregisterStep(value);
4341
+ }, [value, registerStep, unregisterStep]);
4342
+ const isLast = ctx.steps[ctx.steps.length - 1] === value;
4343
+ return /* @__PURE__ */ jsxRuntime.jsx(StepperItemContext.Provider, { value: { value, disabled, isLast }, children: /* @__PURE__ */ jsxRuntime.jsx(
4344
+ "div",
4345
+ {
4346
+ ref,
4347
+ className: cn(
4348
+ "group relative flex items-center gap-3 z-10",
4349
+ ctx.orientation === "vertical" ? "flex items-start w-full" : "",
4350
+ className
4351
+ ),
4352
+ ...props,
4353
+ children
4354
+ }
4355
+ ) });
4356
+ }
4357
+ );
4358
+ StepperItem.displayName = "StepperItem";
4359
+ var StepperSeparator = React52__namespace.forwardRef(
4360
+ ({ className, ...props }, ref) => {
4361
+ const ctx = React52__namespace.useContext(StepperContext);
4362
+ if (!ctx) throw new Error("StepperSeparator must be used within a Stepper");
4363
+ return /* @__PURE__ */ jsxRuntime.jsx(
4364
+ "div",
4365
+ {
4366
+ ref,
4367
+ className: cn(
4368
+ ctx.orientation === "horizontal" ? "flex-1 h-[2px] bg-border transition-all duration-300" : "w-[2px] bg-border absolute left-[17px] top-8 bottom-0 -ml-px z-0",
4369
+ className
4370
+ ),
4371
+ ...props
4372
+ }
4373
+ );
4374
+ }
4375
+ );
4376
+ StepperSeparator.displayName = "StepperSeparator";
4377
+ var StepperTrigger = React52__namespace.forwardRef(
4378
+ ({ className, children, onClick, onKeyDown, ...props }, ref) => {
4379
+ const ctx = React52__namespace.useContext(StepperContext);
4380
+ const itemCtx = React52__namespace.useContext(StepperItemContext);
4381
+ if (!ctx || !itemCtx) {
4382
+ throw new Error("StepperTrigger must be used within a StepperItem inside a Stepper");
4383
+ }
4384
+ const isCompleted = ctx.completedSteps.includes(itemCtx.value) || itemCtx.value < ctx.activeStep;
4385
+ const isActive = ctx.activeStep === itemCtx.value;
4386
+ const isClickable = !ctx.linear || isCompleted || isActive;
4387
+ const disabled = itemCtx.disabled || !isClickable;
4388
+ const handleClick = (e) => {
4389
+ if (disabled) {
4390
+ e.preventDefault();
4391
+ return;
4392
+ }
4393
+ ctx.setStep(itemCtx.value);
4394
+ onClick?.(e);
4395
+ };
4396
+ const handleKeyDown = (e) => {
4397
+ onKeyDown?.(e);
4398
+ const triggers = Array.from(
4399
+ e.currentTarget.closest('[role="tablist"]')?.querySelectorAll('[role="tab"]') || []
4400
+ );
4401
+ const currentIndex = triggers.indexOf(e.currentTarget);
4402
+ if (currentIndex === -1) return;
4403
+ let targetIndex = -1;
4404
+ if (e.key === "ArrowRight" || e.key === "ArrowDown") {
4405
+ targetIndex = Math.min(currentIndex + 1, triggers.length - 1);
4406
+ } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
4407
+ targetIndex = Math.max(currentIndex - 1, 0);
4408
+ }
4409
+ if (targetIndex !== -1 && triggers[targetIndex]) {
4410
+ e.preventDefault();
4411
+ triggers[targetIndex].focus();
4412
+ }
4413
+ };
4414
+ return /* @__PURE__ */ jsxRuntime.jsx(
4415
+ "button",
4416
+ {
4417
+ ref,
4418
+ type: "button",
4419
+ role: "tab",
4420
+ "aria-selected": isActive,
4421
+ "aria-disabled": disabled,
4422
+ tabIndex: isActive ? 0 : -1,
4423
+ onClick: handleClick,
4424
+ onKeyDown: handleKeyDown,
4425
+ className: cn(
4426
+ "flex items-center gap-3 bg-transparent border-0 p-0 text-left cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary rounded-md disabled:cursor-not-allowed disabled:opacity-50",
4427
+ ctx.orientation === "vertical" ? "w-full" : "",
4428
+ className
4429
+ ),
4430
+ ...props,
4431
+ children
4432
+ }
4433
+ );
4434
+ }
4435
+ );
4436
+ StepperTrigger.displayName = "StepperTrigger";
4437
+ var StepperIndicator = React52__namespace.forwardRef(
4438
+ ({ className, children, ...props }, ref) => {
4439
+ const ctx = React52__namespace.useContext(StepperContext);
4440
+ const itemCtx = React52__namespace.useContext(StepperItemContext);
4441
+ if (!ctx || !itemCtx) {
4442
+ throw new Error("StepperIndicator must be used within a StepperItem inside a Stepper");
4443
+ }
4444
+ const isCompleted = ctx.completedSteps.includes(itemCtx.value) || itemCtx.value < ctx.activeStep;
4445
+ const isActive = ctx.activeStep === itemCtx.value;
4446
+ return /* @__PURE__ */ jsxRuntime.jsx(
4447
+ "span",
4448
+ {
4449
+ ref,
4450
+ className: cn(
4451
+ "flex h-9 w-9 shrink-0 items-center justify-center rounded-full border text-sm font-semibold transition-all duration-200",
4452
+ isCompleted ? "bg-primary border-primary text-primary-foreground" : isActive ? "border-primary text-primary bg-primary/10 ring-2 ring-primary/20" : "border-border text-muted-foreground bg-muted/40",
4453
+ className
4454
+ ),
4455
+ ...props,
4456
+ children: children ?? (isCompleted ? "\u2713" : itemCtx.value + 1)
4457
+ }
4458
+ );
4459
+ }
4460
+ );
4461
+ StepperIndicator.displayName = "StepperIndicator";
4462
+ var StepperTitle = React52__namespace.forwardRef(
4463
+ ({ className, ...props }, ref) => {
4464
+ const ctx = React52__namespace.useContext(StepperContext);
4465
+ const itemCtx = React52__namespace.useContext(StepperItemContext);
4466
+ if (!ctx || !itemCtx) {
4467
+ throw new Error("StepperTitle must be used within a StepperItem inside a Stepper");
4468
+ }
4469
+ const isActive = ctx.activeStep === itemCtx.value;
4470
+ return /* @__PURE__ */ jsxRuntime.jsx(
4471
+ "span",
4472
+ {
4473
+ ref,
4474
+ className: cn(
4475
+ "text-sm font-medium transition-colors duration-200",
4476
+ isActive ? "text-foreground font-semibold" : "text-muted-foreground",
4477
+ className
4478
+ ),
4479
+ ...props
4480
+ }
4481
+ );
4482
+ }
4483
+ );
4484
+ StepperTitle.displayName = "StepperTitle";
4485
+ var StepperDescription = React52__namespace.forwardRef(
4486
+ ({ className, ...props }, ref) => {
4487
+ const itemCtx = React52__namespace.useContext(StepperItemContext);
4488
+ if (!itemCtx) throw new Error("StepperDescription must be used within a StepperItem");
4489
+ return /* @__PURE__ */ jsxRuntime.jsx(
4490
+ "span",
4491
+ {
4492
+ ref,
4493
+ className: cn("text-xs text-muted-foreground text-left block", className),
4494
+ ...props
4495
+ }
4496
+ );
4497
+ }
4498
+ );
4499
+ StepperDescription.displayName = "StepperDescription";
4500
+ var AppShellBanner = React52__namespace.forwardRef(
4501
+ ({ className, variant = "primary", closable, onClose, children, ...props }, ref) => {
4502
+ const variantClass = {
4503
+ primary: "bg-primary text-primary-foreground",
4504
+ accent: "bg-secondary text-secondary-foreground",
4505
+ muted: "bg-surface border-b border-border text-muted-foreground"
4506
+ }[variant];
4507
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4508
+ "div",
4509
+ {
4510
+ ref,
4511
+ className: cn("px-4 py-2 text-sm font-medium text-center flex items-center justify-center relative z-30", variantClass, className),
4512
+ ...props,
4513
+ children: [
4514
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children }),
4515
+ closable && /* @__PURE__ */ jsxRuntime.jsx(
4516
+ "button",
4517
+ {
4518
+ type: "button",
4519
+ onClick: onClose,
4520
+ className: "p-1 rounded opacity-80 hover:opacity-100 transition-opacity ml-2 cursor-pointer",
4521
+ "aria-label": "Close banner",
4522
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
4523
+ }
4524
+ )
4525
+ ]
4526
+ }
4527
+ );
4528
+ }
4529
+ );
4530
+ AppShellBanner.displayName = "AppShellBanner";
4531
+ var AppShellHeader = React52__namespace.forwardRef(
4532
+ ({
4533
+ className,
4534
+ variant = "glass",
4535
+ position = "sticky",
4536
+ bordered = true,
4537
+ children,
4538
+ mobileNav,
4539
+ ...props
4540
+ }, ref) => {
4541
+ const [mobileOpen, setMobileOpen] = React52__namespace.useState(false);
4542
+ React52__namespace.useEffect(() => {
4543
+ const handleKeyDown = (e) => {
4544
+ if (e.key === "Escape" && mobileOpen) {
4545
+ setMobileOpen(false);
4546
+ }
4547
+ };
4548
+ window.addEventListener("keydown", handleKeyDown);
4549
+ return () => window.removeEventListener("keydown", handleKeyDown);
4550
+ }, [mobileOpen]);
4551
+ const positionClass = {
4552
+ sticky: "sticky top-0 z-40",
4553
+ fixed: "fixed top-0 left-0 right-0 z-40",
4554
+ static: "relative z-40"
4555
+ }[position];
4556
+ const variantClass = {
4557
+ glass: "bg-surface/80 backdrop-blur-md text-foreground",
4558
+ solid: "bg-surface text-foreground",
4559
+ transparent: "bg-transparent text-foreground"
4560
+ }[variant];
4561
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4562
+ /* @__PURE__ */ jsxRuntime.jsx(
4563
+ "header",
4564
+ {
4565
+ ref,
4566
+ className: cn(
4567
+ "w-full transition-colors",
4568
+ positionClass,
4569
+ variantClass,
4570
+ bordered && "border-b border-border/60",
4571
+ className
4572
+ ),
4573
+ ...props,
4574
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between gap-4", children: [
4575
+ mobileNav && /* @__PURE__ */ jsxRuntime.jsx(
4576
+ "button",
4577
+ {
4578
+ type: "button",
4579
+ onClick: () => setMobileOpen(true),
4580
+ className: "md:hidden p-2 -ml-2 rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted transition-colors cursor-pointer",
4581
+ "aria-label": "Open navigation",
4582
+ children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
4583
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "12", x2: "21", y2: "12" }),
4584
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "6", x2: "21", y2: "6" }),
4585
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "18", x2: "21", y2: "18" })
4586
+ ] })
4587
+ }
4588
+ ),
4589
+ children
4590
+ ] })
4591
+ }
4592
+ ),
4593
+ mobileNav && mobileOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 md:hidden flex", children: [
4594
+ /* @__PURE__ */ jsxRuntime.jsx(
4595
+ "div",
4596
+ {
4597
+ "aria-hidden": "true",
4598
+ onClick: () => setMobileOpen(false),
4599
+ className: "fixed inset-0 bg-overlay backdrop-blur-[2px] transition-opacity duration-300"
4600
+ }
4601
+ ),
4602
+ /* @__PURE__ */ jsxRuntime.jsxs(
4603
+ "aside",
4604
+ {
4605
+ role: "dialog",
4606
+ "aria-modal": "true",
4607
+ "aria-label": "Mobile Navigation",
4608
+ className: "relative z-10 w-72 h-full bg-surface border-r border-border flex flex-col shadow-kj-lg",
4609
+ children: [
4610
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4 border-b border-border", children: [
4611
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-bold uppercase tracking-wider text-muted-foreground", children: "Navigation" }),
4612
+ /* @__PURE__ */ jsxRuntime.jsx(
4613
+ "button",
4614
+ {
4615
+ type: "button",
4616
+ onClick: () => setMobileOpen(false),
4617
+ className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors cursor-pointer",
4618
+ "aria-label": "Close navigation",
4619
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
4620
+ }
4621
+ )
4622
+ ] }),
4623
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto p-4", children: mobileNav })
4624
+ ]
4625
+ }
4626
+ )
4627
+ ] })
4628
+ ] });
4629
+ }
4630
+ );
4631
+ AppShellHeader.displayName = "AppShellHeader";
4632
+ var AppShellMain = React52__namespace.forwardRef(
4633
+ ({ className, width = "default", padded = true, children, ...props }, ref) => {
4634
+ const widthClass = {
4635
+ default: "max-w-7xl mx-auto w-full",
4636
+ narrow: "max-w-5xl mx-auto w-full",
4637
+ wide: "max-w-screen-2xl mx-auto w-full",
4638
+ full: "max-w-none w-full"
4639
+ }[width];
4640
+ return /* @__PURE__ */ jsxRuntime.jsx(
4641
+ "main",
4642
+ {
4643
+ ref,
4644
+ className: cn("flex-1", padded && "px-4 sm:px-6 lg:px-8 py-8 md:py-12", widthClass, className),
4645
+ ...props,
4646
+ children
4647
+ }
4648
+ );
4649
+ }
4650
+ );
4651
+ AppShellMain.displayName = "AppShellMain";
4652
+ var AppShellFooter = React52__namespace.forwardRef(
4653
+ ({ className, bordered = true, children, ...props }, ref) => {
4654
+ return /* @__PURE__ */ jsxRuntime.jsx(
4655
+ "footer",
4656
+ {
4657
+ ref,
4658
+ className: cn(
4659
+ "w-full bg-surface text-foreground py-12 mt-auto",
4660
+ bordered && "border-t border-border",
4661
+ className
4662
+ ),
4663
+ ...props,
4664
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children })
4665
+ }
4666
+ );
4667
+ }
4668
+ );
4669
+ AppShellFooter.displayName = "AppShellFooter";
4670
+ var AppShell = React52__namespace.forwardRef(
4671
+ ({
4672
+ className,
4673
+ banner,
4674
+ header,
4675
+ children,
4676
+ footer,
4677
+ contentWidth = "default",
4678
+ headerPosition = "sticky",
4679
+ headerVariant = "glass",
4680
+ paddedContent = true,
4681
+ mobileNav,
4682
+ ...props
4683
+ }, ref) => {
4684
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4685
+ "div",
4686
+ {
4687
+ ref,
4688
+ className: cn("min-h-screen bg-canvas text-foreground flex flex-col antialiased", className),
4689
+ ...props,
4690
+ children: [
4691
+ banner && /* @__PURE__ */ jsxRuntime.jsx(AppShellBanner, { children: banner }),
4692
+ header && /* @__PURE__ */ jsxRuntime.jsx(AppShellHeader, { variant: headerVariant, position: headerPosition, mobileNav, children: header }),
4693
+ /* @__PURE__ */ jsxRuntime.jsx(AppShellMain, { width: contentWidth, padded: paddedContent, children }),
4694
+ footer && /* @__PURE__ */ jsxRuntime.jsx(AppShellFooter, { children: footer })
4695
+ ]
4696
+ }
4697
+ );
4698
+ }
4699
+ );
4700
+ AppShell.displayName = "AppShell";
4701
+ AppShell.Banner = AppShellBanner;
4702
+ AppShell.Header = AppShellHeader;
4703
+ AppShell.Main = AppShellMain;
4704
+ AppShell.Footer = AppShellFooter;
4705
+ var sizeClasses = {
4706
+ sm: { wrapper: "kj-rating-sm gap-1", star: "w-4 h-4", text: "text-xs" },
4707
+ md: { wrapper: "kj-rating-md gap-1.5", star: "w-5 h-5", text: "text-sm" },
4708
+ lg: { wrapper: "kj-rating-lg gap-2", star: "w-6 h-6", text: "text-base" },
4709
+ xl: { wrapper: "kj-rating-xl gap-2.5", star: "w-8 h-8", text: "text-lg" }
4710
+ };
4711
+ var iconPaths = {
4712
+ star: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z",
4713
+ heart: "M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z",
4714
+ flame: "M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z",
4715
+ shield: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67 0C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",
4716
+ thumb: "M7 10v12M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"
4717
+ };
4718
+ function roundToPrecision(value, precision) {
4719
+ const inv = 1 / precision;
4720
+ return Math.round(value * inv) / inv;
4721
+ }
4722
+ function isCssColor(str) {
4723
+ return str.startsWith("#") || str.startsWith("rgb") || str.startsWith("hsl");
4724
+ }
4725
+ var Rating = React52__namespace.forwardRef(
4726
+ ({
4727
+ value: controlledValue,
4728
+ defaultValue = 0,
4729
+ max = 5,
4730
+ precision = 1,
4731
+ size = "md",
4732
+ icon = "star",
4733
+ color = "#f59e0b",
4734
+ emptyColor = "#e5e7eb",
4735
+ allowClear = true,
4736
+ disabled = false,
4737
+ readOnly = false,
4738
+ hoverPreview = true,
4739
+ showValue = false,
4740
+ showCount = false,
4741
+ count,
4742
+ name,
4743
+ onChange,
4744
+ onHoverChange,
4745
+ className,
4746
+ onKeyDown,
4747
+ onMouseLeave,
4748
+ "aria-label": ariaLabel,
4749
+ ...props
4750
+ }, ref) => {
4751
+ const isControlled = controlledValue !== void 0;
4752
+ const [internalValue, setInternalValue] = React52__namespace.useState(
4753
+ controlledValue ?? defaultValue
4754
+ );
4755
+ const [hoverValue, setHoverValue] = React52__namespace.useState(null);
4756
+ const instanceId = React52__namespace.useId();
4757
+ React52__namespace.useEffect(() => {
4758
+ if (isControlled) {
4759
+ setInternalValue(controlledValue);
4760
+ }
4761
+ }, [isControlled, controlledValue]);
4762
+ const currentValue = isControlled ? controlledValue : internalValue;
4763
+ const displayValue = hoverPreview && hoverValue !== null ? hoverValue : currentValue;
4764
+ const handleValueChange = (newValue) => {
4765
+ if (disabled || readOnly) return;
4766
+ const clamped = Math.max(0, Math.min(max, roundToPrecision(newValue, precision)));
4767
+ if (!isControlled) {
4768
+ setInternalValue(clamped);
4769
+ }
4770
+ onChange?.(clamped);
4771
+ };
4772
+ const getEventValue = (e, starIndex) => {
4773
+ const target = e.currentTarget;
4774
+ const width = target.offsetWidth;
4775
+ const nativeEv = e.nativeEvent;
4776
+ const offsetX = nativeEv?.offsetX ?? nativeEv?.nativeEvent?.offsetX ?? e.offsetX;
4777
+ if (width > 0 && offsetX !== void 0 && offsetX !== null) {
4778
+ const ratio = Math.max(1e-3, Math.min(1, offsetX / width));
4779
+ const stepInStar = Math.ceil(ratio / precision) * precision;
4780
+ return Math.min(max, Math.max(precision, starIndex - 1 + stepInStar));
4781
+ }
4782
+ return starIndex;
4783
+ };
4784
+ const handleStarClick = (e, starIndex) => {
4785
+ if (disabled || readOnly) return;
4786
+ const targetValue = getEventValue(e, starIndex);
4787
+ let nextValue = targetValue;
4788
+ if (allowClear && targetValue === currentValue) {
4789
+ nextValue = 0;
4790
+ }
4791
+ handleValueChange(nextValue);
4792
+ };
4793
+ const handleStarMouseMove = (e, starIndex) => {
4794
+ if (disabled || readOnly) return;
4795
+ if (hoverPreview) {
4796
+ const hoveredVal = getEventValue(e, starIndex);
4797
+ setHoverValue(hoveredVal);
4798
+ onHoverChange?.(hoveredVal);
4799
+ }
4800
+ };
4801
+ const handleKeyDown = (e) => {
4802
+ if (disabled || readOnly) {
4803
+ onKeyDown?.(e);
4804
+ return;
4805
+ }
4806
+ let nextVal = null;
4807
+ switch (e.key) {
4808
+ case "ArrowRight":
4809
+ case "ArrowUp":
4810
+ nextVal = Math.min(max, currentValue + precision);
4811
+ break;
4812
+ case "ArrowLeft":
4813
+ case "ArrowDown":
4814
+ nextVal = Math.max(0, currentValue - precision);
4815
+ break;
4816
+ case "Home":
4817
+ nextVal = 0;
4818
+ break;
4819
+ case "End":
4820
+ nextVal = max;
4821
+ break;
4822
+ }
4823
+ if (nextVal !== null) {
4824
+ e.preventDefault();
4825
+ handleValueChange(nextVal);
4826
+ }
4827
+ onKeyDown?.(e);
4828
+ };
4829
+ const handleContainerMouseLeave = (e) => {
4830
+ if (hoverPreview) {
4831
+ setHoverValue(null);
4832
+ onHoverChange?.(null);
4833
+ }
4834
+ onMouseLeave?.(e);
4835
+ };
4836
+ const sizing = sizeClasses[size] || sizeClasses.md;
4837
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4838
+ "div",
4839
+ {
4840
+ ref,
4841
+ role: readOnly ? "img" : "radiogroup",
4842
+ tabIndex: disabled || readOnly ? -1 : 0,
4843
+ "aria-valuenow": displayValue,
4844
+ "aria-valuemin": 0,
4845
+ "aria-valuemax": max,
4846
+ "aria-disabled": disabled || void 0,
4847
+ "aria-readonly": readOnly || void 0,
4848
+ "aria-label": ariaLabel || (readOnly ? `Rated ${displayValue} out of ${max}` : "Rating"),
4849
+ onKeyDown: handleKeyDown,
4850
+ onMouseLeave: handleContainerMouseLeave,
4851
+ className: cn(
4852
+ "inline-flex items-center select-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-md",
4853
+ disabled && "opacity-50 cursor-not-allowed",
4854
+ readOnly && "cursor-default",
4855
+ !disabled && !readOnly && "cursor-pointer",
4856
+ sizing.wrapper,
4857
+ className
4858
+ ),
4859
+ ...props,
4860
+ children: [
4861
+ name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: currentValue }),
4862
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center gap-0.5", children: Array.from({ length: max }, (_, index) => {
4863
+ const starIndex = index + 1;
4864
+ const fillFraction = Math.max(
4865
+ 0,
4866
+ Math.min(1, displayValue - index)
4867
+ );
4868
+ const gradientId = `rating-grad-${instanceId}-${index}-${Math.round(
4869
+ fillFraction * 100
4870
+ )}`;
4871
+ const CustomIconComponent = typeof icon === "function" || typeof icon === "object" ? icon : null;
4872
+ const builtInIconType = typeof icon === "string" ? icon : "star";
4873
+ const pathD = iconPaths[builtInIconType] || iconPaths.star;
4874
+ return /* @__PURE__ */ jsxRuntime.jsx(
4875
+ "button",
4876
+ {
4877
+ type: "button",
4878
+ tabIndex: -1,
4879
+ "data-testid": "rating-star",
4880
+ role: readOnly ? void 0 : "radio",
4881
+ "aria-checked": readOnly ? void 0 : displayValue >= starIndex,
4882
+ "aria-label": `${starIndex} of ${max} stars`,
4883
+ disabled,
4884
+ onClick: (e) => handleStarClick(e, starIndex),
4885
+ onMouseMove: (e) => handleStarMouseMove(e, starIndex),
4886
+ onMouseEnter: (e) => handleStarMouseMove(e, starIndex),
4887
+ className: cn(
4888
+ "p-0.5 focus:outline-none transition-transform active:scale-95 disabled:scale-100",
4889
+ sizing.star
4890
+ ),
4891
+ children: CustomIconComponent ? /* @__PURE__ */ jsxRuntime.jsx(
4892
+ CustomIconComponent,
4893
+ {
4894
+ className: cn(
4895
+ "w-full h-full",
4896
+ fillFraction >= 0.5 ? !isCssColor(color) && color : !isCssColor(emptyColor) && emptyColor
4897
+ )
4898
+ }
4899
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
4900
+ "svg",
4901
+ {
4902
+ viewBox: "0 0 24 24",
4903
+ className: "w-full h-full",
4904
+ xmlns: "http://www.w3.org/2000/svg",
4905
+ children: [
4906
+ fillFraction > 0 && fillFraction < 1 && /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs(
4907
+ "linearGradient",
4908
+ {
4909
+ id: gradientId,
4910
+ x1: "0%",
4911
+ y1: "0%",
4912
+ x2: "100%",
4913
+ y2: "0%",
4914
+ children: [
4915
+ isCssColor(color) ? /* @__PURE__ */ jsxRuntime.jsx(
4916
+ "stop",
4917
+ {
4918
+ offset: `${fillFraction * 100}%`,
4919
+ stopColor: color
4920
+ }
4921
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
4922
+ "stop",
4923
+ {
4924
+ offset: `${fillFraction * 100}%`,
4925
+ stopColor: "currentColor",
4926
+ className: color
4927
+ }
4928
+ ),
4929
+ isCssColor(emptyColor) ? /* @__PURE__ */ jsxRuntime.jsx(
4930
+ "stop",
4931
+ {
4932
+ offset: `${fillFraction * 100}%`,
4933
+ stopColor: emptyColor
4934
+ }
4935
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
4936
+ "stop",
4937
+ {
4938
+ offset: `${fillFraction * 100}%`,
4939
+ stopColor: "currentColor",
4940
+ className: emptyColor
4941
+ }
4942
+ )
4943
+ ]
4944
+ }
4945
+ ) }),
4946
+ /* @__PURE__ */ jsxRuntime.jsx(
4947
+ "path",
4948
+ {
4949
+ d: pathD,
4950
+ fill: fillFraction === 1 ? isCssColor(color) ? color : void 0 : fillFraction === 0 ? isCssColor(emptyColor) ? emptyColor : void 0 : `url(#${gradientId})`,
4951
+ className: fillFraction === 1 ? !isCssColor(color) ? color : void 0 : fillFraction === 0 ? !isCssColor(emptyColor) ? emptyColor : void 0 : void 0,
4952
+ stroke: "none"
4953
+ }
4954
+ )
4955
+ ]
4956
+ }
4957
+ )
4958
+ },
4959
+ index
4960
+ );
4961
+ }) }),
4962
+ showValue && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-medium text-foreground ml-1.5", sizing.text), children: displayValue }),
4963
+ showCount && count !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-muted-foreground ml-1", sizing.text), children: [
4964
+ "(",
4965
+ count,
4966
+ ")"
4967
+ ] })
4968
+ ]
4969
+ }
4970
+ );
4971
+ }
4972
+ );
4973
+ Rating.displayName = "Rating";
4974
+ var RatingField = React52__namespace.forwardRef(
4975
+ ({
4976
+ id: customId,
4977
+ label,
4978
+ helperText,
4979
+ errorMessage,
4980
+ required,
4981
+ className,
4982
+ containerClassName,
4983
+ "aria-describedby": ariaDescribedBy,
4984
+ ...ratingProps
4985
+ }, ref) => {
4986
+ const generatedId = React52__namespace.useId();
4987
+ const id = customId || generatedId;
4988
+ const helperId = helperText ? `${id}-helper` : void 0;
4989
+ const errorId = errorMessage ? `${id}-error` : void 0;
4990
+ const describedBy = [ariaDescribedBy, helperId, errorId].filter(Boolean).join(" ") || void 0;
4991
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1.5", containerClassName), children: [
4992
+ label && /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: id, required, children: label }),
4993
+ /* @__PURE__ */ jsxRuntime.jsx(
4994
+ Rating,
4995
+ {
4996
+ ref,
4997
+ id,
4998
+ className,
4999
+ "aria-describedby": describedBy,
5000
+ ...ratingProps
5001
+ }
5002
+ ),
5003
+ helperText && /* @__PURE__ */ jsxRuntime.jsx(Hint, { id: helperId, children: helperText }),
5004
+ errorMessage && /* @__PURE__ */ jsxRuntime.jsx(Hint, { id: errorId, error: true, children: errorMessage })
5005
+ ] });
5006
+ }
5007
+ );
5008
+ RatingField.displayName = "RatingField";
5009
+ var RatingSummary = React52__namespace.forwardRef(
5010
+ ({
5011
+ average,
5012
+ totalCount,
5013
+ distribution,
5014
+ max = 5,
5015
+ size = "md",
5016
+ icon = "star",
5017
+ className,
5018
+ ...props
5019
+ }, ref) => {
5020
+ const formattedAverage = Number.isInteger(average) ? average.toString() : average.toFixed(1);
5021
+ const formattedTotalCount = totalCount.toLocaleString();
5022
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5023
+ "div",
5024
+ {
5025
+ ref,
5026
+ className: cn(
5027
+ "flex flex-col gap-6 sm:flex-row sm:items-center sm:gap-8 p-4 rounded-xl border bg-card text-card-foreground shadow-sm",
5028
+ className
5029
+ ),
5030
+ ...props,
5031
+ children: [
5032
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center p-4 rounded-lg bg-muted/40 text-center min-w-[140px]", children: [
5033
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-4xl font-bold tracking-tight text-foreground", children: formattedAverage }),
5034
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-1.5", children: /* @__PURE__ */ jsxRuntime.jsx(
5035
+ Rating,
5036
+ {
5037
+ value: average,
5038
+ max,
5039
+ size,
5040
+ icon,
5041
+ readOnly: true,
5042
+ allowClear: false,
5043
+ hoverPreview: false
5044
+ }
5045
+ ) }),
5046
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
5047
+ formattedTotalCount,
5048
+ " total ratings"
5049
+ ] })
5050
+ ] }),
5051
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex flex-col gap-2.5", children: distribution.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
5052
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "w-12 text-right font-medium text-foreground whitespace-nowrap", children: [
5053
+ item.stars,
5054
+ " star"
5055
+ ] }),
5056
+ /* @__PURE__ */ jsxRuntime.jsx(
5057
+ Progress,
5058
+ {
5059
+ value: item.percentage,
5060
+ "aria-label": `${item.stars} star ratings: ${item.percentage}%`,
5061
+ className: "h-2.5 flex-1"
5062
+ }
5063
+ ),
5064
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "w-12 text-right text-xs text-muted-foreground font-mono", children: [
5065
+ item.percentage,
5066
+ "%"
5067
+ ] })
5068
+ ] }, item.stars)) })
5069
+ ]
5070
+ }
5071
+ );
5072
+ }
5073
+ );
5074
+ RatingSummary.displayName = "RatingSummary";
5075
+ var PricingCard = React52__namespace.forwardRef(
5076
+ ({
5077
+ className,
5078
+ name,
5079
+ price,
5080
+ period,
5081
+ description,
5082
+ features = [],
5083
+ variant,
5084
+ badge,
5085
+ popular = false,
5086
+ ctaText = "Get Started",
5087
+ onCtaClick,
5088
+ ctaHref,
5089
+ cta,
5090
+ disabled = false,
5091
+ ...props
5092
+ }, ref) => {
5093
+ const resolvedVariant = variant || (popular ? "featured" : "default");
5094
+ const displayBadge = badge || (popular ? "Most Popular" : void 0);
5095
+ const isFeatured = resolvedVariant === "featured";
5096
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5097
+ Card,
5098
+ {
5099
+ ref,
5100
+ className: cn(
5101
+ "relative flex flex-col p-6 transition-all duration-300",
5102
+ isFeatured ? "border-amber-500/80 shadow-kj-lg ring-1 ring-amber-500/30" : resolvedVariant === "outline" ? "border-border/80 bg-transparent shadow-none" : "border-border shadow-kj-sm",
5103
+ className
5104
+ ),
5105
+ ...props,
5106
+ children: [
5107
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 flex items-start justify-between gap-3", children: [
5108
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5109
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-bold tracking-tight text-foreground", children: name }),
5110
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: description })
5111
+ ] }),
5112
+ displayBadge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-amber-500 px-3 py-0.5 text-[0.7rem] font-bold uppercase tracking-wider text-black shadow-sm shrink-0 mt-0.5", children: displayBadge })
5113
+ ] }),
5114
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 flex items-baseline gap-1", children: [
5115
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-3xl font-extrabold tracking-tight text-foreground", children: price }),
5116
+ period && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: period })
5117
+ ] }),
5118
+ features.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mb-6 flex flex-1 flex-col gap-2.5 p-0 text-xs list-none", children: features.map((feature, idx) => {
5119
+ const text = typeof feature === "string" ? feature : feature.text;
5120
+ const included = typeof feature === "string" ? true : feature.included ?? true;
5121
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center gap-2.5", children: [
5122
+ /* @__PURE__ */ jsxRuntime.jsx(
5123
+ "span",
5124
+ {
5125
+ className: cn(
5126
+ "flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[0.65rem] font-bold",
5127
+ included ? "bg-amber-500/15 text-amber-600 dark:text-amber-400" : "bg-muted text-muted-foreground/60"
5128
+ ),
5129
+ children: included ? "\u2713" : "\u2715"
5130
+ }
5131
+ ),
5132
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(included ? "text-foreground" : "text-muted-foreground line-through opacity-70"), children: text })
5133
+ ] }, idx);
5134
+ }) }),
5135
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto pt-2", children: cta ? cta : ctaHref ? (
5136
+ /* eslint-disable-next-line jsx-a11y/anchor-is-valid */
5137
+ /* @__PURE__ */ jsxRuntime.jsx(
5138
+ "a",
5139
+ {
5140
+ href: disabled ? void 0 : ctaHref,
5141
+ "aria-disabled": disabled || void 0,
5142
+ tabIndex: disabled ? -1 : void 0,
5143
+ className: cn(
5144
+ buttonVariants({ variant: isFeatured ? "primary" : "outline" }),
5145
+ "w-full justify-center",
5146
+ disabled && "pointer-events-none opacity-50"
5147
+ ),
5148
+ children: ctaText
5149
+ }
5150
+ )
5151
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
5152
+ Button,
5153
+ {
5154
+ variant: isFeatured ? "primary" : "outline",
5155
+ className: "w-full justify-center",
5156
+ onClick: onCtaClick,
5157
+ disabled,
5158
+ children: ctaText
5159
+ }
5160
+ ) })
5161
+ ]
5162
+ }
5163
+ );
5164
+ }
5165
+ );
5166
+ PricingCard.displayName = "PricingCard";
5167
+ var BlogCard = React52__namespace.forwardRef(
5168
+ ({
5169
+ className,
5170
+ title,
5171
+ description,
5172
+ coverUrl,
5173
+ coverAlt,
5174
+ category,
5175
+ readTime,
5176
+ publishedAt,
5177
+ author,
5178
+ orientation = "vertical",
5179
+ href,
5180
+ ...props
5181
+ }, ref) => {
5182
+ const isHorizontal = orientation === "horizontal";
5183
+ const isInteractive = Boolean(href || props.onClick);
5184
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5185
+ Card,
5186
+ {
5187
+ ref,
5188
+ as: href ? "a" : "div",
5189
+ href,
5190
+ interactive: isInteractive,
5191
+ className: cn(
5192
+ "group flex overflow-hidden transition-all duration-300",
5193
+ isHorizontal ? "flex-col sm:flex-row" : "flex-col",
5194
+ className
5195
+ ),
5196
+ ...props,
5197
+ children: [
5198
+ coverUrl && /* @__PURE__ */ jsxRuntime.jsx(
5199
+ "div",
5200
+ {
5201
+ className: cn(
5202
+ "relative overflow-hidden bg-muted shrink-0",
5203
+ isHorizontal ? "w-full sm:w-2/5 min-h-[160px]" : "w-full aspect-[16/9]"
5204
+ ),
5205
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5206
+ "img",
5207
+ {
5208
+ src: coverUrl,
5209
+ alt: coverAlt || title,
5210
+ className: "h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"
5211
+ }
5212
+ )
5213
+ }
5214
+ ),
5215
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col justify-between p-5", children: [
5216
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5217
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center gap-2 text-[0.75rem] text-muted-foreground", children: [
5218
+ category && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", children: category }),
5219
+ (readTime || publishedAt) && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5220
+ publishedAt,
5221
+ " ",
5222
+ publishedAt && readTime && "\u2022",
5223
+ " ",
5224
+ readTime
5225
+ ] })
5226
+ ] }),
5227
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-bold tracking-tight text-foreground transition-colors group-hover:text-primary", children: title }),
5228
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-xs text-muted-foreground line-clamp-2", children: description })
5229
+ ] }),
5230
+ author && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center gap-2.5 border-t border-border/60 pt-3", children: [
5231
+ /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: author.avatarUrl, alt: author.name, size: "sm", children: author.name.charAt(0) }),
5232
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col text-xs", children: [
5233
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: author.name }),
5234
+ author.role && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.7rem] text-muted-foreground", children: author.role })
5235
+ ] })
5236
+ ] })
5237
+ ] })
5238
+ ]
5239
+ }
5240
+ );
5241
+ }
5242
+ );
5243
+ BlogCard.displayName = "BlogCard";
5244
+ var ProjectCard = React52__namespace.forwardRef(
5245
+ ({
5246
+ className,
5247
+ title,
5248
+ description,
5249
+ status,
5250
+ techStack = [],
5251
+ metrics = [],
5252
+ updatedAt,
5253
+ actions,
5254
+ href,
5255
+ ...props
5256
+ }, ref) => {
5257
+ const isInteractive = Boolean(href || props.onClick);
5258
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5259
+ Card,
5260
+ {
5261
+ ref,
5262
+ as: href ? "a" : "div",
5263
+ href,
5264
+ interactive: isInteractive,
5265
+ className: cn(
5266
+ "group flex flex-col justify-between p-5 transition-all duration-300",
5267
+ className
5268
+ ),
5269
+ ...props,
5270
+ children: [
5271
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5272
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
5273
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-bold tracking-tight text-foreground transition-colors group-hover:text-primary", children: title }),
5274
+ status && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: status.variant || "neutral", className: "shrink-0 text-[0.65rem]", children: status.label })
5275
+ ] }),
5276
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-xs text-muted-foreground line-clamp-2", children: description }),
5277
+ techStack.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3.5 flex flex-wrap gap-1.5", children: techStack.map((tech) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "neutral", className: "text-[0.65rem] py-0 px-2 font-mono", children: tech }, tech)) })
5278
+ ] }),
5279
+ (metrics.length > 0 || updatedAt || actions) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center justify-between border-t border-border/60 pt-3 text-[0.75rem] text-muted-foreground", children: [
5280
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
5281
+ metrics.map((metric, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
5282
+ "span",
5283
+ {
5284
+ className: "flex items-center gap-1 font-mono font-medium",
5285
+ children: [
5286
+ metric.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: metric.icon }),
5287
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: metric.value }),
5288
+ metric.label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/70", children: metric.label })
5289
+ ]
5290
+ },
5291
+ metric.label ? `${metric.label}-${idx}` : idx
5292
+ )),
5293
+ updatedAt && /* @__PURE__ */ jsxRuntime.jsx("span", { children: updatedAt })
5294
+ ] }),
5295
+ actions && /* @__PURE__ */ jsxRuntime.jsx(
5296
+ "div",
5297
+ {
5298
+ onClick: (e) => e.stopPropagation(),
5299
+ className: "flex items-center gap-1 shrink-0",
5300
+ children: actions
5301
+ }
5302
+ )
5303
+ ] })
5304
+ ]
5305
+ }
5306
+ );
5307
+ }
5308
+ );
5309
+ ProjectCard.displayName = "ProjectCard";
5310
+ function formatRelativeTime(date) {
5311
+ const d = typeof date === "string" ? new Date(date) : date;
5312
+ if (isNaN(d.getTime())) return "";
5313
+ const diffMs = Date.now() - d.getTime();
5314
+ const diffMin = Math.floor(diffMs / 6e4);
5315
+ const diffH = Math.floor(diffMs / 36e5);
5316
+ const diffD = Math.floor(diffMs / 864e5);
5317
+ if (diffMin < 1) return "Just now";
5318
+ if (diffMin < 60) return `${diffMin} min ago`;
5319
+ if (diffH < 24) return diffH === 1 ? "1 hour ago" : `${diffH} hours ago`;
5320
+ if (diffD === 1) return "Yesterday";
5321
+ if (diffD < 7) return `${diffD} days ago`;
5322
+ return d.toLocaleDateString(void 0, { month: "short", day: "numeric" });
5323
+ }
5324
+ function useInboxState(initial) {
5325
+ const [items, setItems] = React52__namespace.useState(initial);
5326
+ const unreadCount = items.filter((i) => !i.read).length;
5327
+ const markRead = React52__namespace.useCallback((id) => {
5328
+ setItems(
5329
+ (prev) => prev.map((item) => item.id === id ? { ...item, read: true } : item)
5330
+ );
5331
+ }, []);
5332
+ const markAllRead = React52__namespace.useCallback(() => {
5333
+ setItems((prev) => prev.map((item) => ({ ...item, read: true })));
5334
+ }, []);
5335
+ const dismiss = React52__namespace.useCallback((id) => {
5336
+ setItems((prev) => prev.filter((item) => item.id !== id));
5337
+ }, []);
5338
+ return { items, unreadCount, markRead, markAllRead, dismiss };
5339
+ }
5340
+ var InboxContext = React52__namespace.createContext(null);
5341
+ function useInboxContext(part) {
5342
+ const ctx = React52__namespace.useContext(InboxContext);
5343
+ if (!ctx) throw new Error(`${part} must be used inside <InboxPopover>`);
5344
+ return ctx;
5345
+ }
5346
+ function InboxPopover({
5347
+ children,
5348
+ className,
5349
+ open: openProp,
5350
+ onOpenChange
5351
+ }) {
5352
+ const [openState, setOpenState] = React52__namespace.useState(false);
5353
+ const controlled = openProp !== void 0;
5354
+ const open = controlled ? openProp : openState;
5355
+ const triggerRef = React52__namespace.useRef(null);
5356
+ const ref = React52__namespace.useRef(null);
5357
+ const setOpen = React52__namespace.useCallback(
5358
+ (v) => {
5359
+ if (!controlled) setOpenState(v);
5360
+ onOpenChange?.(v);
5361
+ },
5362
+ [controlled, onOpenChange]
5363
+ );
5364
+ React52__namespace.useEffect(() => {
5365
+ if (!open) return;
5366
+ const onDoc = (e) => {
5367
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
5368
+ };
5369
+ const onEsc = (e) => {
5370
+ if (e.key === "Escape") {
5371
+ setOpen(false);
5372
+ triggerRef.current?.focus();
5373
+ }
5374
+ };
5375
+ document.addEventListener("mousedown", onDoc);
5376
+ document.addEventListener("keydown", onEsc);
5377
+ return () => {
5378
+ document.removeEventListener("mousedown", onDoc);
5379
+ document.removeEventListener("keydown", onEsc);
5380
+ };
5381
+ }, [open, setOpen]);
5382
+ const ctxValue = React52__namespace.useMemo(() => ({ open, setOpen, triggerRef }), [open, setOpen]);
5383
+ return /* @__PURE__ */ jsxRuntime.jsx(InboxContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("relative inline-block", className), children }) });
5384
+ }
5385
+ function InboxTrigger({
5386
+ unreadCount,
5387
+ label = "Notifications",
5388
+ className,
5389
+ onClick,
5390
+ ...props
5391
+ }) {
5392
+ const ctx = useInboxContext("InboxTrigger");
5393
+ const setRef = (node) => {
5394
+ ctx.triggerRef.current = node;
5395
+ };
5396
+ const displayCount = unreadCount == null || unreadCount <= 0 ? null : unreadCount > 99 ? "99+" : String(unreadCount);
5397
+ const defaultLabel = displayCount ? `${label} (${displayCount} unread)` : label;
5398
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5399
+ "button",
5400
+ {
5401
+ ref: setRef,
5402
+ type: "button",
5403
+ "aria-label": defaultLabel,
5404
+ "aria-haspopup": "dialog",
5405
+ "aria-expanded": ctx.open,
5406
+ className: cn(
5407
+ "relative inline-flex items-center justify-center w-9 h-9 rounded-full",
5408
+ "bg-surface border border-border text-muted-foreground",
5409
+ "hover:bg-muted hover:text-foreground transition-colors",
5410
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
5411
+ className
5412
+ ),
5413
+ onClick: (e) => {
5414
+ ctx.setOpen(!ctx.open);
5415
+ onClick?.(e);
5416
+ },
5417
+ ...props,
5418
+ children: [
5419
+ /* @__PURE__ */ jsxRuntime.jsxs(
5420
+ "svg",
5421
+ {
5422
+ width: 16,
5423
+ height: 16,
5424
+ viewBox: "0 0 24 24",
5425
+ fill: "none",
5426
+ stroke: "currentColor",
5427
+ strokeWidth: 2,
5428
+ strokeLinecap: "round",
5429
+ strokeLinejoin: "round",
5430
+ "aria-hidden": "true",
5431
+ children: [
5432
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
5433
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
5434
+ ]
5435
+ }
5436
+ ),
5437
+ displayCount != null && /* @__PURE__ */ jsxRuntime.jsx(
5438
+ "span",
5439
+ {
5440
+ "aria-hidden": "true",
5441
+ className: cn(
5442
+ "absolute -top-0.5 -right-0.5 min-w-[16px] h-4 px-1",
5443
+ "rounded-full bg-primary text-primary-foreground",
5444
+ "text-[9px] font-bold leading-4 flex items-center justify-center"
5445
+ ),
5446
+ children: displayCount
5447
+ }
5448
+ )
5449
+ ]
5450
+ }
5451
+ );
5452
+ }
5453
+ function NotificationItem({ item, onDismiss, className }) {
5454
+ const leadingSlot = item.avatarSrc ? /* @__PURE__ */ jsxRuntime.jsx(
5455
+ "img",
5456
+ {
5457
+ src: item.avatarSrc,
5458
+ alt: item.avatarFallback ?? "",
5459
+ className: "w-7 h-7 rounded-full object-cover flex-shrink-0"
5460
+ }
5461
+ ) : item.avatarFallback ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-7 h-7 rounded-full bg-primary/20 text-primary text-[10px] font-bold flex items-center justify-center flex-shrink-0 select-none", children: item.avatarFallback }) : item.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-7 h-7 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 text-primary", children: item.icon }) : null;
5462
+ const textBlock = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
5463
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-sm leading-snug", item.read ? "text-muted-foreground" : "text-foreground"), children: item.title }),
5464
+ item.body && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-0.5 truncate", children: item.body }),
5465
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-1", children: formatRelativeTime(item.timestamp) })
5466
+ ] });
5467
+ const sharedClass = cn(
5468
+ "group relative flex items-start gap-2.5 px-3.5 py-2.5 w-full text-left",
5469
+ "border-b border-border last:border-0",
5470
+ !item.read && "bg-primary/[0.04]",
5471
+ "hover:bg-muted/50 transition-colors",
5472
+ className
5473
+ );
5474
+ const mainContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5475
+ leadingSlot,
5476
+ textBlock
5477
+ ] });
5478
+ const mainAction = item.href ? /* @__PURE__ */ jsxRuntime.jsx(
5479
+ "a",
5480
+ {
5481
+ href: item.href,
5482
+ onClick: () => item.onClick?.(item.id),
5483
+ className: "flex-1 flex items-start gap-2.5 min-w-0 text-left outline-none",
5484
+ children: mainContent
5485
+ }
5486
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
5487
+ "button",
5488
+ {
5489
+ type: "button",
5490
+ onClick: () => item.onClick?.(item.id),
5491
+ className: "flex-1 flex items-start gap-2.5 min-w-0 text-left outline-none",
5492
+ children: mainContent
5493
+ }
5494
+ );
5495
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: sharedClass, children: [
5496
+ mainAction,
5497
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 flex-shrink-0 mt-0.5", children: [
5498
+ /* @__PURE__ */ jsxRuntime.jsx(
5499
+ "button",
5500
+ {
5501
+ type: "button",
5502
+ "aria-label": "Dismiss",
5503
+ onClick: (e) => {
5504
+ e.preventDefault();
5505
+ e.stopPropagation();
5506
+ onDismiss?.(item.id);
5507
+ },
5508
+ className: cn(
5509
+ "text-muted-foreground hover:text-foreground transition-colors",
5510
+ "opacity-0 group-hover:opacity-100 focus:opacity-100",
5511
+ "text-base leading-none p-0.5 rounded"
5512
+ ),
5513
+ children: "\xD7"
5514
+ }
5515
+ ),
5516
+ /* @__PURE__ */ jsxRuntime.jsx(
5517
+ "span",
5518
+ {
5519
+ "aria-label": item.read ? void 0 : "Unread",
5520
+ "aria-hidden": item.read ? true : void 0,
5521
+ className: cn(
5522
+ "w-[7px] h-[7px] rounded-full flex-shrink-0 mt-1",
5523
+ item.read ? "border border-border" : "bg-primary"
5524
+ )
5525
+ }
5526
+ )
5527
+ ] })
5528
+ ] });
5529
+ }
5530
+ function InboxContent({
5531
+ items,
5532
+ onMarkAllRead,
5533
+ onDismiss,
5534
+ viewAllHref,
5535
+ viewAllLabel = "View all notifications",
5536
+ emptyState,
5537
+ width = 360,
5538
+ maxHeight = 320,
5539
+ className
5540
+ }) {
5541
+ const ctx = useInboxContext("InboxContent");
5542
+ const ref = React52__namespace.useRef(null);
5543
+ React52__namespace.useEffect(() => {
5544
+ if (ctx.open) ref.current?.focus();
5545
+ }, [ctx.open]);
5546
+ if (!ctx.open) return null;
5547
+ const allRead = items.length === 0 || items.every((i) => i.read);
5548
+ const defaultEmptyState = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-10 px-5 text-center", children: [
5549
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-10 h-10 rounded-full bg-muted flex items-center justify-center mb-3 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
5550
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
5551
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
5552
+ ] }) }),
5553
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-foreground", children: "All caught up" }),
5554
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: "No new notifications" })
5555
+ ] });
5556
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5557
+ "div",
5558
+ {
5559
+ ref,
5560
+ role: "dialog",
5561
+ "aria-label": "Notifications",
5562
+ tabIndex: -1,
5563
+ style: { width },
5564
+ className: cn(
5565
+ "absolute right-0 top-[calc(100%+6px)] z-40",
5566
+ "bg-surface border border-border rounded-kj-md shadow-kj-lg outline-none",
5567
+ "animate-[kjpop_.12s_ease]",
5568
+ className
5569
+ ),
5570
+ children: [
5571
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3.5 py-2.5 border-b border-border", children: [
5572
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-foreground", children: "Notifications" }),
5573
+ /* @__PURE__ */ jsxRuntime.jsx(
5574
+ "button",
5575
+ {
5576
+ type: "button",
5577
+ disabled: allRead,
5578
+ "aria-disabled": allRead,
5579
+ onClick: allRead ? void 0 : onMarkAllRead,
5580
+ className: cn(
5581
+ "text-xs font-medium transition-colors",
5582
+ allRead ? "text-muted-foreground cursor-not-allowed" : "text-primary hover:text-primary/80"
5583
+ ),
5584
+ children: "Mark all read"
5585
+ }
5586
+ )
5587
+ ] }),
5588
+ items.length === 0 ? emptyState ?? defaultEmptyState : /* @__PURE__ */ jsxRuntime.jsx(
5589
+ "div",
5590
+ {
5591
+ className: "overflow-y-auto",
5592
+ style: { maxHeight },
5593
+ children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
5594
+ NotificationItem,
5595
+ {
5596
+ item,
5597
+ onDismiss
5598
+ },
5599
+ item.id
5600
+ ))
5601
+ }
5602
+ ),
5603
+ items.length > 0 && viewAllHref && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border px-3.5 py-2.5 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs(
5604
+ "a",
5605
+ {
5606
+ href: viewAllHref,
5607
+ className: "text-xs font-medium text-primary hover:text-primary/80 transition-colors",
5608
+ children: [
5609
+ viewAllLabel,
5610
+ " \u2192"
5611
+ ]
5612
+ }
5613
+ ) })
5614
+ ]
5615
+ }
5616
+ );
5617
+ }
5618
+ var DEFAULT_COLOR_SWATCHES = [
5619
+ "#EF4444",
5620
+ // Red
5621
+ "#F97316",
5622
+ // Orange
5623
+ "#F59E0B",
5624
+ // Amber
5625
+ "#10B981",
5626
+ // Emerald
5627
+ "#14B8A6",
5628
+ // Teal
5629
+ "#06B6D4",
5630
+ // Sky
5631
+ "#3B82F6",
5632
+ // Blue
5633
+ "#6366F1",
5634
+ // Indigo
5635
+ "#8B5CF6",
5636
+ // Purple
5637
+ "#EC4899",
5638
+ // Pink
5639
+ "#64748B",
5640
+ // Slate
5641
+ "#1E293B"
5642
+ // Charcoal
5643
+ ];
5644
+ function isValidHex(hex) {
5645
+ const trimmed = hex.trim();
5646
+ const clean = trimmed.startsWith("#") ? trimmed.slice(1) : trimmed;
5647
+ return /^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(clean);
5648
+ }
5649
+ function normalizeHex(hex) {
5650
+ let clean = hex.trim();
5651
+ if (!clean.startsWith("#")) clean = `#${clean}`;
5652
+ if (/^#[0-9A-Fa-f]{3}$/.test(clean)) {
5653
+ clean = `#${clean[1]}${clean[1]}${clean[2]}${clean[2]}${clean[3]}${clean[3]}`;
5654
+ }
5655
+ return clean.toUpperCase();
5656
+ }
5657
+ function hexToHsl(hex) {
5658
+ if (!isValidHex(hex)) return { h: 0, s: 0, l: 0 };
5659
+ const normalized = normalizeHex(hex);
5660
+ const r = parseInt(normalized.slice(1, 3), 16) / 255;
5661
+ const g = parseInt(normalized.slice(3, 5), 16) / 255;
5662
+ const b = parseInt(normalized.slice(5, 7), 16) / 255;
5663
+ const max = Math.max(r, g, b);
5664
+ const min = Math.min(r, g, b);
5665
+ let h = 0;
5666
+ let s = 0;
5667
+ const l = (max + min) / 2;
5668
+ if (max !== min) {
5669
+ const d = max - min;
5670
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
5671
+ switch (max) {
5672
+ case r:
5673
+ h = (g - b) / d + (g < b ? 6 : 0);
5674
+ break;
5675
+ case g:
5676
+ h = (b - r) / d + 2;
5677
+ break;
5678
+ case b:
5679
+ h = (r - g) / d + 4;
5680
+ break;
5681
+ }
5682
+ h /= 6;
5683
+ }
5684
+ return {
5685
+ h: Math.round(h * 360),
5686
+ s: Math.round(s * 100),
5687
+ l: Math.round(l * 100)
5688
+ };
5689
+ }
5690
+ function hslToHex(h, s, l) {
5691
+ const normalizedH = (h % 360 + 360) % 360;
5692
+ const sPct = s / 100;
5693
+ const lPct = l / 100;
5694
+ const c = (1 - Math.abs(2 * lPct - 1)) * sPct;
5695
+ const x = c * (1 - Math.abs(normalizedH / 60 % 2 - 1));
5696
+ const m = lPct - c / 2;
5697
+ let r = 0;
5698
+ let g = 0;
5699
+ let b = 0;
5700
+ if (0 <= normalizedH && normalizedH < 60) {
5701
+ r = c;
5702
+ g = x;
5703
+ b = 0;
5704
+ } else if (60 <= normalizedH && normalizedH < 120) {
5705
+ r = x;
5706
+ g = c;
5707
+ b = 0;
5708
+ } else if (120 <= normalizedH && normalizedH < 180) {
5709
+ r = 0;
5710
+ g = c;
5711
+ b = x;
5712
+ } else if (180 <= normalizedH && normalizedH < 240) {
5713
+ r = 0;
5714
+ g = x;
5715
+ b = c;
5716
+ } else if (240 <= normalizedH && normalizedH < 300) {
5717
+ r = x;
5718
+ g = 0;
5719
+ b = c;
5720
+ } else if (300 <= normalizedH && normalizedH < 360) {
5721
+ r = c;
5722
+ g = 0;
5723
+ b = x;
5724
+ }
5725
+ const toHex = (n) => {
5726
+ const hex = Math.round((n + m) * 255).toString(16);
5727
+ return hex.length === 1 ? `0${hex}` : hex;
5728
+ };
5729
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
5730
+ }
5731
+ var ColorPickerSwatch = React52__namespace.forwardRef(({ color, selected = false, size = "md", className, style, ...props }, ref) => {
5732
+ const sizeClasses2 = {
5733
+ sm: "w-5 h-5",
5734
+ md: "w-7 h-7",
5735
+ lg: "w-9 h-9"
5736
+ };
5737
+ return /* @__PURE__ */ jsxRuntime.jsx(
5738
+ "button",
5739
+ {
5740
+ ref,
5741
+ type: "button",
5742
+ "aria-pressed": selected,
5743
+ style: { backgroundColor: color, ...style },
5744
+ className: cn(
5745
+ "relative shrink-0 rounded-full border border-border/50 shadow-sm transition-transform hover:scale-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary flex items-center justify-center text-white text-xs font-bold",
5746
+ sizeClasses2[size],
5747
+ selected && "ring-2 ring-primary ring-offset-2 ring-offset-surface",
5748
+ className
5749
+ ),
5750
+ ...props,
5751
+ children: selected && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2713" })
5752
+ }
5753
+ );
5754
+ });
5755
+ ColorPickerSwatch.displayName = "ColorPickerSwatch";
5756
+ var ColorPicker = React52__namespace.forwardRef(
5757
+ ({
5758
+ value,
5759
+ defaultValue = "#3B82F6",
5760
+ onChange,
5761
+ swatches = DEFAULT_COLOR_SWATCHES,
5762
+ disabled = false,
5763
+ showHexInput = true,
5764
+ className,
5765
+ ...props
5766
+ }, ref) => {
5767
+ const isControlled = value !== void 0;
5768
+ const [localColor, setLocalColor] = React52__namespace.useState(
5769
+ normalizeHex(defaultValue)
5770
+ );
5771
+ const color = isControlled ? normalizeHex(value) : localColor;
5772
+ const [hexInputValue, setHexInputValue] = React52__namespace.useState(color);
5773
+ React52__namespace.useEffect(() => {
5774
+ setHexInputValue(color);
5775
+ }, [color]);
5776
+ const handleColorChange = React52__namespace.useCallback(
5777
+ (newHex) => {
5778
+ const normalized = normalizeHex(newHex);
5779
+ if (!isControlled) {
5780
+ setLocalColor(normalized);
5781
+ }
5782
+ onChange?.(normalized);
5783
+ },
5784
+ [isControlled, onChange]
5785
+ );
5786
+ const hsl = React52__namespace.useMemo(() => hexToHsl(color), [color]);
5787
+ const handleHueChange = (e) => {
5788
+ const h = Number(e.target.value);
5789
+ const s = hsl.s === 0 ? 100 : hsl.s;
5790
+ const l = hsl.s === 0 ? 50 : hsl.l;
5791
+ const newHex = hslToHex(h, s, l);
5792
+ handleColorChange(newHex);
5793
+ };
5794
+ const handleHexSubmit = () => {
5795
+ if (isValidHex(hexInputValue)) {
5796
+ handleColorChange(hexInputValue);
5797
+ } else {
5798
+ setHexInputValue(color);
5799
+ }
5800
+ };
5801
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("inline-block", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
5802
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
5803
+ "button",
5804
+ {
5805
+ type: "button",
5806
+ disabled,
5807
+ "aria-label": `Select color, current ${color}`,
5808
+ className: cn(
5809
+ "inline-flex items-center gap-2.5 px-3 py-1.5 rounded-kj-md border border-border bg-surface text-sm font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50"
5810
+ ),
5811
+ children: [
5812
+ /* @__PURE__ */ jsxRuntime.jsx(
5813
+ "span",
5814
+ {
5815
+ style: { backgroundColor: color },
5816
+ className: "w-5 h-5 rounded-full border border-border/50 shadow-sm shrink-0"
5817
+ }
5818
+ ),
5819
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-xs uppercase", children: color }),
5820
+ /* @__PURE__ */ jsxRuntime.jsx(
5821
+ "svg",
5822
+ {
5823
+ width: 12,
5824
+ height: 12,
5825
+ viewBox: "0 0 24 24",
5826
+ fill: "none",
5827
+ stroke: "currentColor",
5828
+ strokeWidth: 2,
5829
+ className: "text-muted-foreground ml-auto",
5830
+ "aria-hidden": "true",
5831
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
5832
+ }
5833
+ )
5834
+ ]
5835
+ }
5836
+ ) }),
5837
+ /* @__PURE__ */ jsxRuntime.jsxs(PopoverContent, { side: "bottom", align: "start", className: "w-64 p-3.5 space-y-3.5", children: [
5838
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 p-2 rounded-kj-md bg-muted/40 border border-border", children: [
5839
+ /* @__PURE__ */ jsxRuntime.jsx(
5840
+ "span",
5841
+ {
5842
+ style: { backgroundColor: color },
5843
+ className: "w-8 h-8 rounded-full border border-border/50 shadow-sm shrink-0"
5844
+ }
5845
+ ),
5846
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5847
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Selected Color" }),
5848
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-mono font-bold text-foreground uppercase", children: color })
5849
+ ] })
5850
+ ] }),
5851
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
5852
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold text-muted-foreground", children: "Preset Swatches" }),
5853
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-6 gap-2", children: swatches.map((swatch) => {
5854
+ const normalizedSwatch = normalizeHex(swatch);
5855
+ return /* @__PURE__ */ jsxRuntime.jsx(
5856
+ ColorPickerSwatch,
5857
+ {
5858
+ color: swatch,
5859
+ selected: normalizedSwatch === color,
5860
+ "aria-label": `Select color ${swatch}`,
5861
+ onClick: () => handleColorChange(swatch)
5862
+ },
5863
+ swatch
5864
+ );
5865
+ }) })
5866
+ ] }),
5867
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
5868
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold text-muted-foreground", children: "Hue" }),
5869
+ /* @__PURE__ */ jsxRuntime.jsx(
5870
+ "input",
5871
+ {
5872
+ type: "range",
5873
+ min: 0,
5874
+ max: 360,
5875
+ value: hsl.h,
5876
+ onChange: handleHueChange,
5877
+ "aria-label": "Hue slider",
5878
+ className: "w-full h-3 rounded-full appearance-none cursor-pointer",
5879
+ style: {
5880
+ background: "linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%)"
5881
+ }
5882
+ }
5883
+ )
5884
+ ] }),
5885
+ showHexInput && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
5886
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold text-muted-foreground", children: "Hex Code" }),
5887
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
5888
+ "input",
5889
+ {
5890
+ type: "text",
5891
+ "aria-label": "Hex Code",
5892
+ value: hexInputValue,
5893
+ onChange: (e) => setHexInputValue(e.target.value),
5894
+ onBlur: handleHexSubmit,
5895
+ onKeyDown: (e) => {
5896
+ if (e.key === "Enter") handleHexSubmit();
5897
+ },
5898
+ placeholder: "#000000",
5899
+ className: "flex-1 px-2.5 py-1 text-xs font-mono rounded-kj-md border border-border bg-surface text-foreground uppercase focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary"
5900
+ }
5901
+ ) })
5902
+ ] })
5903
+ ] })
5904
+ ] }) });
5905
+ }
5906
+ );
5907
+ ColorPicker.displayName = "ColorPicker";
5908
+ var ColorPickerField = React52__namespace.forwardRef(({ label, hint, error, required, ...props }, ref) => {
5909
+ return /* @__PURE__ */ jsxRuntime.jsxs(Field, { children: [
5910
+ label && /* @__PURE__ */ jsxRuntime.jsx(Label, { required, children: label }),
5911
+ /* @__PURE__ */ jsxRuntime.jsx(ColorPicker, { ref, ...props }),
5912
+ hint && /* @__PURE__ */ jsxRuntime.jsx(Hint, { children: hint }),
5913
+ error && /* @__PURE__ */ jsxRuntime.jsx(Hint, { error: true, children: error })
5914
+ ] });
5915
+ });
5916
+ ColorPickerField.displayName = "ColorPickerField";
5917
+ var COLUMN_CLASSES = {
5918
+ 2: "grid-cols-2",
5919
+ 3: "grid-cols-3",
5920
+ 4: "grid-cols-4",
5921
+ 5: "grid-cols-5"
5922
+ };
5923
+ var ASPECT_CLASSES = {
5924
+ square: "aspect-square",
5925
+ video: "aspect-video",
5926
+ "4/3": "aspect-[4/3]",
5927
+ auto: "aspect-auto"
5928
+ };
5929
+ function ImageGallery({
5930
+ images = [],
5931
+ columns = 3,
5932
+ aspectRatio = "square",
5933
+ maxVisible,
5934
+ className,
5935
+ thumbnailClassName,
5936
+ lightboxClassName,
5937
+ onImageClick
5938
+ }) {
5939
+ const [selectedIndex, setSelectedIndex] = React52__namespace.useState(null);
5940
+ const columnClass = COLUMN_CLASSES[columns] || "grid-cols-3";
5941
+ const aspectClass = ASPECT_CLASSES[aspectRatio] || (aspectRatio.startsWith("aspect-") ? aspectRatio : `aspect-[${aspectRatio}]`);
5942
+ const hasMaxVisible = typeof maxVisible === "number" && maxVisible > 0 && images.length > maxVisible;
5943
+ const visibleImages = hasMaxVisible ? images.slice(0, maxVisible) : images;
5944
+ const remainingCount = hasMaxVisible ? images.length - maxVisible + 1 : 0;
5945
+ const handleThumbnailClick = (index) => {
5946
+ setSelectedIndex(index);
5947
+ if (onImageClick) {
5948
+ onImageClick(index);
5949
+ }
5950
+ };
5951
+ const handleClose = React52__namespace.useCallback(() => {
5952
+ setSelectedIndex(null);
5953
+ }, []);
5954
+ const handleNext = React52__namespace.useCallback(() => {
5955
+ setSelectedIndex((prev) => prev === null ? null : (prev + 1) % images.length);
5956
+ }, [images.length]);
5957
+ const handlePrev = React52__namespace.useCallback(() => {
5958
+ setSelectedIndex((prev) => prev === null ? null : (prev - 1 + images.length) % images.length);
5959
+ }, [images.length]);
5960
+ React52__namespace.useEffect(() => {
5961
+ if (selectedIndex === null) return;
5962
+ const originalOverflow = document.body.style.overflow;
5963
+ const handleKeyDown = (e) => {
5964
+ if (e.key === "Escape") {
5965
+ handleClose();
5966
+ } else if (e.key === "ArrowRight") {
5967
+ handleNext();
5968
+ } else if (e.key === "ArrowLeft") {
5969
+ handlePrev();
5970
+ }
5971
+ };
5972
+ document.addEventListener("keydown", handleKeyDown);
5973
+ document.body.style.overflow = "hidden";
5974
+ return () => {
5975
+ document.removeEventListener("keydown", handleKeyDown);
5976
+ document.body.style.overflow = originalOverflow;
5977
+ };
5978
+ }, [selectedIndex, handleClose, handleNext, handlePrev]);
5979
+ const activeImage = selectedIndex !== null ? images[selectedIndex] : null;
5980
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5981
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("grid gap-3 w-full", columnClass, className), children: visibleImages.map((img, idx) => {
5982
+ const isLastOverlay = hasMaxVisible && idx === maxVisible - 1;
5983
+ const thumbSrc = img.thumbnailSrc || img.src;
5984
+ const defaultAlt = img.alt || `Thumbnail ${idx + 1}`;
5985
+ const buttonAriaLabel = isLastOverlay ? `View all ${images.length} images` : defaultAlt;
5986
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5987
+ "button",
5988
+ {
5989
+ type: "button",
5990
+ "aria-label": buttonAriaLabel,
5991
+ onClick: () => handleThumbnailClick(idx),
5992
+ className: cn(
5993
+ "relative group overflow-hidden rounded-kj-lg bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 cursor-pointer transition-all duration-200",
5994
+ aspectClass,
5995
+ thumbnailClassName
5996
+ ),
5997
+ children: [
5998
+ /* @__PURE__ */ jsxRuntime.jsx(
5999
+ "img",
6000
+ {
6001
+ src: thumbSrc,
6002
+ alt: img.alt || `Thumbnail ${idx + 1}`,
6003
+ className: "w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
6004
+ }
6005
+ ),
6006
+ isLastOverlay && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 bg-black/60 backdrop-blur-[2px] flex items-center justify-center text-white font-bold text-xl group-hover:bg-black/70 transition-colors", children: [
6007
+ "+",
6008
+ remainingCount
6009
+ ] })
6010
+ ]
6011
+ },
6012
+ idx
6013
+ );
6014
+ }) }),
6015
+ selectedIndex !== null && activeImage && /* @__PURE__ */ jsxRuntime.jsxs(
6016
+ "div",
6017
+ {
6018
+ role: "dialog",
6019
+ "aria-modal": "true",
6020
+ "aria-label": "Image gallery lightbox",
6021
+ onClick: (e) => e.target === e.currentTarget && handleClose(),
6022
+ className: cn(
6023
+ "fixed inset-0 z-[100] bg-black/85 backdrop-blur-md flex flex-col justify-between p-4 sm:p-6 transition-opacity duration-200 animate-in fade-in-0",
6024
+ lightboxClassName
6025
+ ),
6026
+ children: [
6027
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between w-full text-white z-10", children: [
6028
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-white/80 select-none", children: [
6029
+ selectedIndex + 1,
6030
+ " of ",
6031
+ images.length
6032
+ ] }),
6033
+ /* @__PURE__ */ jsxRuntime.jsx(
6034
+ "button",
6035
+ {
6036
+ type: "button",
6037
+ onClick: handleClose,
6038
+ "aria-label": "Close",
6039
+ className: "p-2 rounded-full text-white/80 hover:text-white hover:bg-white/10 transition-colors cursor-pointer",
6040
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
6041
+ }
6042
+ )
6043
+ ] }),
6044
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 flex items-center justify-between gap-4 my-auto min-h-0 w-full", children: [
6045
+ images.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
6046
+ "button",
6047
+ {
6048
+ type: "button",
6049
+ onClick: handlePrev,
6050
+ "aria-label": "Previous image",
6051
+ className: "p-3 rounded-full text-white/80 hover:text-white hover:bg-white/10 transition-colors cursor-pointer z-10 shrink-0",
6052
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) })
6053
+ }
6054
+ ),
6055
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex flex-col items-center justify-center h-full min-h-0 px-2 select-none", children: /* @__PURE__ */ jsxRuntime.jsx(
6056
+ "img",
6057
+ {
6058
+ src: activeImage.src,
6059
+ alt: activeImage.alt || `Image ${selectedIndex + 1}`,
6060
+ className: "max-h-[70vh] max-w-full object-contain rounded-kj-md shadow-2xl transition-transform"
6061
+ }
6062
+ ) }),
6063
+ images.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
6064
+ "button",
6065
+ {
6066
+ type: "button",
6067
+ onClick: handleNext,
6068
+ "aria-label": "Next image",
6069
+ className: "p-3 rounded-full text-white/80 hover:text-white hover:bg-white/10 transition-colors cursor-pointer z-10 shrink-0",
6070
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) })
6071
+ }
6072
+ )
6073
+ ] }),
6074
+ (activeImage.title || activeImage.caption) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center text-center text-white pb-2 z-10", children: [
6075
+ activeImage.title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-semibold text-white", children: activeImage.title }),
6076
+ activeImage.caption && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-white/70 max-w-lg mt-0.5", children: activeImage.caption })
6077
+ ] })
6078
+ ]
6079
+ }
6080
+ )
6081
+ ] });
6082
+ }
2499
6083
 
2500
6084
  exports.Accordion = Accordion;
2501
6085
  exports.AccordionContent = AccordionContent;
2502
6086
  exports.AccordionItem = AccordionItem;
2503
6087
  exports.AccordionTrigger = AccordionTrigger;
2504
6088
  exports.Alert = Alert;
6089
+ exports.AppShell = AppShell;
6090
+ exports.AppShellBanner = AppShellBanner;
6091
+ exports.AppShellFooter = AppShellFooter;
6092
+ exports.AppShellHeader = AppShellHeader;
6093
+ exports.AppShellMain = AppShellMain;
2505
6094
  exports.Avatar = Avatar;
2506
6095
  exports.AvatarGroup = AvatarGroup;
2507
6096
  exports.Badge = Badge;
6097
+ exports.BlogCard = BlogCard;
2508
6098
  exports.BottomNavigation = BottomNavigation;
2509
6099
  exports.BottomSheet = BottomSheet;
2510
6100
  exports.BottomSheetContent = BottomSheetContent;
@@ -2516,6 +6106,7 @@ exports.Breadcrumb = Breadcrumb;
2516
6106
  exports.BreadcrumbItem = BreadcrumbItem;
2517
6107
  exports.BreadcrumbSeparator = BreadcrumbSeparator;
2518
6108
  exports.Button = Button;
6109
+ exports.Calendar = Calendar;
2519
6110
  exports.Card = Card;
2520
6111
  exports.CardContent = CardContent;
2521
6112
  exports.CardDescription = CardDescription;
@@ -2525,10 +6116,20 @@ exports.CardTitle = CardTitle;
2525
6116
  exports.Checkbox = Checkbox;
2526
6117
  exports.CheckboxField = CheckboxField;
2527
6118
  exports.CodeBlock = CodeBlock;
6119
+ exports.ColorPicker = ColorPicker;
6120
+ exports.ColorPickerField = ColorPickerField;
6121
+ exports.ColorPickerSwatch = ColorPickerSwatch;
6122
+ exports.Combobox = Combobox;
6123
+ exports.ComboboxField = ComboboxField;
2528
6124
  exports.CommandPalette = CommandPalette;
2529
6125
  exports.ConfirmDialog = ConfirmDialog;
6126
+ exports.DEFAULT_COLOR_SWATCHES = DEFAULT_COLOR_SWATCHES;
2530
6127
  exports.DashboardShell = DashboardShell;
2531
6128
  exports.DataTable = DataTable;
6129
+ exports.DatePicker = DatePicker;
6130
+ exports.DatePickerField = DatePickerField;
6131
+ exports.DateRangePicker = DateRangePicker;
6132
+ exports.DateRangePickerField = DateRangePickerField;
2532
6133
  exports.DetailPageLayout = DetailPageLayout;
2533
6134
  exports.Drawer = Drawer;
2534
6135
  exports.DropdownMenu = DropdownMenu;
@@ -2536,12 +6137,19 @@ exports.DropdownMenuContent = DropdownMenuContent;
2536
6137
  exports.DropdownMenuItem = DropdownMenuItem;
2537
6138
  exports.DropdownMenuSeparator = DropdownMenuSeparator;
2538
6139
  exports.DropdownMenuTrigger = DropdownMenuTrigger;
6140
+ exports.Dropzone = Dropzone;
2539
6141
  exports.EmptyState = EmptyState;
2540
6142
  exports.ErrorState = ErrorState;
2541
6143
  exports.Fab = Fab;
2542
6144
  exports.Field = Field;
6145
+ exports.FileUpload = FileUpload;
6146
+ exports.FileUploadField = FileUploadField;
2543
6147
  exports.FormField = FormField;
2544
6148
  exports.Hint = Hint;
6149
+ exports.ImageGallery = ImageGallery;
6150
+ exports.InboxContent = InboxContent;
6151
+ exports.InboxPopover = InboxPopover;
6152
+ exports.InboxTrigger = InboxTrigger;
2545
6153
  exports.Input = Input;
2546
6154
  exports.Kbd = Kbd;
2547
6155
  exports.Label = Label;
@@ -2550,22 +6158,42 @@ exports.Modal = Modal;
2550
6158
  exports.ModalActions = ModalActions;
2551
6159
  exports.ModalDescription = ModalDescription;
2552
6160
  exports.ModalTitle = ModalTitle;
6161
+ exports.NotificationItem = NotificationItem;
2553
6162
  exports.PageHeader = PageHeader;
2554
6163
  exports.Pagination = Pagination;
2555
6164
  exports.Popover = Popover;
2556
6165
  exports.PopoverContent = PopoverContent;
2557
6166
  exports.PopoverTrigger = PopoverTrigger;
6167
+ exports.PricingCard = PricingCard;
2558
6168
  exports.Progress = Progress;
6169
+ exports.ProgressRing = ProgressRing;
6170
+ exports.ProgressRingField = ProgressRingField;
6171
+ exports.ProjectCard = ProjectCard;
2559
6172
  exports.Radio = Radio;
6173
+ exports.RangeCalendar = RangeCalendar;
6174
+ exports.Rating = Rating;
6175
+ exports.RatingField = RatingField;
6176
+ exports.RatingSummary = RatingSummary;
6177
+ exports.SectionHeader = SectionHeader;
2560
6178
  exports.Segmented = Segmented;
2561
6179
  exports.Select = Select;
2562
6180
  exports.SelectField = SelectField;
6181
+ exports.Separator = Separator;
2563
6182
  exports.SettingsLayout = SettingsLayout;
2564
6183
  exports.SidebarNav = SidebarNav;
2565
6184
  exports.Skeleton = Skeleton;
2566
6185
  exports.Slider = Slider;
2567
6186
  exports.Spinner = Spinner;
2568
6187
  exports.Stat = Stat;
6188
+ exports.Stepper = Stepper;
6189
+ exports.StepperContent = StepperContent;
6190
+ exports.StepperDescription = StepperDescription;
6191
+ exports.StepperIndicator = StepperIndicator;
6192
+ exports.StepperItem = StepperItem;
6193
+ exports.StepperList = StepperList;
6194
+ exports.StepperSeparator = StepperSeparator;
6195
+ exports.StepperTitle = StepperTitle;
6196
+ exports.StepperTrigger = StepperTrigger;
2569
6197
  exports.Switch = Switch;
2570
6198
  exports.Table = Table;
2571
6199
  exports.TableBody = TableBody;
@@ -2581,12 +6209,28 @@ exports.TabsList = TabsList;
2581
6209
  exports.TabsTrigger = TabsTrigger;
2582
6210
  exports.TextField = TextField;
2583
6211
  exports.Textarea = Textarea;
6212
+ exports.Timeline = Timeline;
6213
+ exports.TimelineConnector = TimelineConnector;
6214
+ exports.TimelineContent = TimelineContent;
6215
+ exports.TimelineDot = TimelineDot;
6216
+ exports.TimelineItem = TimelineItem;
6217
+ exports.TimelineSeparator = TimelineSeparator;
6218
+ exports.TimelineTime = TimelineTime;
6219
+ exports.TimelineTitle = TimelineTitle;
2584
6220
  exports.ToastProvider = ToastProvider;
6221
+ exports.ToggleGroup = ToggleGroup;
2585
6222
  exports.Tooltip = Tooltip;
2586
6223
  exports.badgeVariants = badgeVariants;
2587
6224
  exports.buttonVariants = buttonVariants;
2588
6225
  exports.cn = cn;
6226
+ exports.formatRelativeTime = formatRelativeTime;
6227
+ exports.hexToHsl = hexToHsl;
6228
+ exports.hslToHex = hslToHex;
6229
+ exports.isValidHex = isValidHex;
6230
+ exports.normalizeHex = normalizeHex;
2589
6231
  exports.sliderThumbCSS = sliderThumbCSS;
6232
+ exports.useInboxState = useInboxState;
6233
+ exports.useStepper = useStepper;
2590
6234
  exports.useToast = useToast;
2591
6235
  //# sourceMappingURL=index.cjs.map
2592
6236
  //# sourceMappingURL=index.cjs.map