@jameskabz/nextcraft-ui 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +94 -0
  2. package/dist/chunk-6F7FN2ZF.js +671 -0
  3. package/dist/chunk-6F7FN2ZF.js.map +1 -0
  4. package/dist/chunk-7Q4Z47HT.js +657 -0
  5. package/dist/chunk-7Q4Z47HT.js.map +1 -0
  6. package/dist/chunk-7SKDTIEK.js +49 -0
  7. package/dist/chunk-7SKDTIEK.js.map +1 -0
  8. package/dist/chunk-FEFH5O5K.js +49 -0
  9. package/dist/chunk-FEFH5O5K.js.map +1 -0
  10. package/dist/chunk-M2EKVXB6.js +127 -0
  11. package/dist/chunk-M2EKVXB6.js.map +1 -0
  12. package/dist/chunk-SBLIF6UU.js +1029 -0
  13. package/dist/chunk-SBLIF6UU.js.map +1 -0
  14. package/dist/chunk-VQ6T3HIX.js +9 -0
  15. package/dist/chunk-VQ6T3HIX.js.map +1 -0
  16. package/dist/chunk-YVZL4GET.js +328 -0
  17. package/dist/chunk-YVZL4GET.js.map +1 -0
  18. package/dist/chunk-ZRV4Y374.js +582 -0
  19. package/dist/chunk-ZRV4Y374.js.map +1 -0
  20. package/dist/craft/components.cjs +1838 -0
  21. package/dist/craft/components.cjs.map +1 -0
  22. package/dist/craft/components.d.cts +369 -0
  23. package/dist/craft/components.d.ts +369 -0
  24. package/dist/craft/components.js +78 -0
  25. package/dist/craft/components.js.map +1 -0
  26. package/dist/craft/forms.cjs +1376 -0
  27. package/dist/craft/forms.cjs.map +1 -0
  28. package/dist/craft/forms.d.cts +101 -0
  29. package/dist/craft/forms.d.ts +101 -0
  30. package/dist/craft/forms.js +14 -0
  31. package/dist/craft/forms.js.map +1 -0
  32. package/dist/craft/layout.cjs +410 -0
  33. package/dist/craft/layout.cjs.map +1 -0
  34. package/dist/craft/layout.d.cts +170 -0
  35. package/dist/craft/layout.d.ts +170 -0
  36. package/dist/craft/layout.js +27 -0
  37. package/dist/craft/layout.js.map +1 -0
  38. package/dist/craft/table.cjs +662 -0
  39. package/dist/craft/table.cjs.map +1 -0
  40. package/dist/craft/table.d.cts +99 -0
  41. package/dist/craft/table.d.ts +99 -0
  42. package/dist/craft/table.js +15 -0
  43. package/dist/craft/table.js.map +1 -0
  44. package/dist/craft/theme.cjs +166 -0
  45. package/dist/craft/theme.cjs.map +1 -0
  46. package/dist/craft/theme.d.cts +10 -0
  47. package/dist/craft/theme.d.ts +10 -0
  48. package/dist/craft/theme.js +12 -0
  49. package/dist/craft/theme.js.map +1 -0
  50. package/dist/index.cjs +2374 -317
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +10 -277
  53. package/dist/index.d.ts +10 -277
  54. package/dist/index.js +92 -1347
  55. package/dist/index.js.map +1 -1
  56. package/dist/styles.css +359 -4
  57. package/dist/theme-context-EVI9PfKv.d.cts +22 -0
  58. package/dist/theme-context-EVI9PfKv.d.ts +22 -0
  59. package/package.json +30 -1
package/dist/index.cjs CHANGED
@@ -31,23 +31,44 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AppShell: () => AppShell,
34
+ AppTemplate: () => AppTemplate,
34
35
  AuthLayout: () => AuthLayout,
35
36
  Breadcrumbs: () => Breadcrumbs,
36
37
  Container: () => Container,
38
+ CraftAlert: () => CraftAlert,
37
39
  CraftBadge: () => CraftBadge,
38
40
  CraftButton: () => CraftButton,
39
41
  CraftCard: () => CraftCard,
40
42
  CraftCheckbox: () => CraftCheckbox,
43
+ CraftCommandPalette: () => CraftCommandPalette,
44
+ CraftConfirmDialog: () => CraftConfirmDialog,
45
+ CraftCreateEditDrawer: () => CraftCreateEditDrawer,
41
46
  CraftCurrencyInput: () => CraftCurrencyInput,
47
+ CraftDataTable: () => CraftDataTable,
42
48
  CraftDatePicker: () => CraftDatePicker,
43
49
  CraftDrawer: () => CraftDrawer,
50
+ CraftDropdownMenu: () => CraftDropdownMenu,
44
51
  CraftEmptyState: () => CraftEmptyState,
52
+ CraftErrorState: () => CraftErrorState,
53
+ CraftFilterBar: () => CraftFilterBar,
54
+ CraftForm: () => CraftForm,
55
+ CraftFormBuilder: () => CraftFormBuilder,
56
+ CraftFormField: () => CraftFormField,
57
+ CraftIcon: () => CraftIcon,
58
+ CraftIconProvider: () => CraftIconProvider,
45
59
  CraftInput: () => CraftInput,
60
+ CraftLink: () => CraftLink,
61
+ CraftLoadingState: () => CraftLoadingState,
46
62
  CraftModal: () => CraftModal,
47
63
  CraftNumberInput: () => CraftNumberInput,
64
+ CraftPagination: () => CraftPagination,
65
+ CraftPopover: () => CraftPopover,
48
66
  CraftSelect: () => CraftSelect,
49
67
  CraftSkeleton: () => CraftSkeleton,
68
+ CraftStatCard: () => CraftStatCard,
69
+ CraftSubmitButton: () => CraftSubmitButton,
50
70
  CraftSwitch: () => CraftSwitch,
71
+ CraftTableToolbar: () => CraftTableToolbar,
51
72
  CraftTabs: () => CraftTabs,
52
73
  CraftTextarea: () => CraftTextarea,
53
74
  CraftToastHost: () => CraftToastHost,
@@ -59,6 +80,7 @@ __export(index_exports, {
59
80
  ThemeProvider: () => ThemeProvider,
60
81
  ThemeSwitcher: () => ThemeSwitcher,
61
82
  TopNav: () => TopNav,
83
+ layoutConfigSchema: () => layoutConfigSchema,
62
84
  useCraftToast: () => useCraftToast,
63
85
  useTheme: () => useTheme
64
86
  });
@@ -403,20 +425,149 @@ function CraftBadge({
403
425
  );
404
426
  }
405
427
 
406
- // src/components/craft-card.tsx
428
+ // src/components/craft-alert.tsx
407
429
  var import_jsx_runtime9 = require("react/jsx-runtime");
408
- function CraftCard({ className, tone, elevated = true, ...props }) {
409
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
430
+ var variantClasses3 = {
431
+ info: "border-[rgb(var(--nc-accent-1)/0.45)] bg-[rgb(var(--nc-accent-1)/0.12)]",
432
+ success: "border-[rgb(var(--nc-accent-2)/0.45)] bg-[rgb(var(--nc-accent-2)/0.12)]",
433
+ warning: "border-[rgb(var(--nc-accent-3)/0.45)] bg-[rgb(var(--nc-accent-3)/0.12)]",
434
+ error: "border-[rgb(var(--nc-accent-3)/0.65)] bg-[rgb(var(--nc-accent-3)/0.18)]"
435
+ };
436
+ function CraftAlert({
437
+ title,
438
+ description,
439
+ variant = "info",
440
+ icon,
441
+ actions,
442
+ tone,
443
+ className,
444
+ ...props
445
+ }) {
446
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
447
+ "div",
448
+ {
449
+ className: cn(
450
+ "rounded-2xl border p-4 text-[rgb(var(--nc-fg))] backdrop-blur-xl",
451
+ variantClasses3[variant],
452
+ className
453
+ ),
454
+ "data-nc-theme": tone,
455
+ ...props,
456
+ children: [
457
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-start gap-3", children: [
458
+ icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mt-1 text-[rgb(var(--nc-fg))]", children: icon }),
459
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-1", children: [
460
+ title && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm font-semibold", children: title }),
461
+ description && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: description })
462
+ ] })
463
+ ] }),
464
+ actions && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mt-3 flex flex-wrap gap-2", children: actions })
465
+ ]
466
+ }
467
+ );
468
+ }
469
+
470
+ // src/components/craft-error-state.tsx
471
+ var import_jsx_runtime10 = require("react/jsx-runtime");
472
+ function CraftErrorState({
473
+ title = "Something went wrong",
474
+ description = "Try again or check your connection.",
475
+ actionLabel = "Retry",
476
+ onAction,
477
+ action,
478
+ tone,
479
+ className,
480
+ ...props
481
+ }) {
482
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
483
+ "div",
484
+ {
485
+ className: cn(
486
+ "rounded-3xl border border-[rgb(var(--nc-border)/0.35)] bg-[rgb(var(--nc-surface)/0.12)] p-6 text-[rgb(var(--nc-fg))] shadow-[0_12px_30px_rgba(0,0,0,0.25)] backdrop-blur-xl",
487
+ className
488
+ ),
489
+ "data-nc-theme": tone,
490
+ ...props,
491
+ children: [
492
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-2", children: [
493
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-lg font-semibold", children: title }),
494
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: description })
495
+ ] }),
496
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-4", children: action != null ? action : onAction && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CraftButton, { size: "sm", onClick: onAction, children: actionLabel }) })
497
+ ]
498
+ }
499
+ );
500
+ }
501
+
502
+ // src/components/craft-loading-state.tsx
503
+ var import_jsx_runtime11 = require("react/jsx-runtime");
504
+ var sizeClasses2 = {
505
+ sm: "h-4 w-4 border-2",
506
+ md: "h-6 w-6 border-2",
507
+ lg: "h-8 w-8 border-[3px]"
508
+ };
509
+ function CraftLoadingState({
510
+ label = "Loading...",
511
+ size = "md",
512
+ tone,
513
+ className,
514
+ ...props
515
+ }) {
516
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
517
+ "div",
518
+ {
519
+ className: cn("flex items-center gap-3 text-[rgb(var(--nc-fg))]", className),
520
+ "data-nc-theme": tone,
521
+ ...props,
522
+ children: [
523
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
524
+ "span",
525
+ {
526
+ className: cn(
527
+ "inline-block animate-spin rounded-full border-[rgb(var(--nc-accent-1)/0.25)] border-t-[rgb(var(--nc-accent-1))]",
528
+ sizeClasses2[size]
529
+ ),
530
+ "aria-hidden": "true"
531
+ }
532
+ ),
533
+ label && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: label })
534
+ ]
535
+ }
536
+ );
537
+ }
538
+
539
+ // src/components/craft-card.tsx
540
+ var import_jsx_runtime12 = require("react/jsx-runtime");
541
+ var intensityClasses2 = {
542
+ subtle: "backdrop-blur-md bg-opacity-50",
543
+ medium: "backdrop-blur-xl bg-opacity-70",
544
+ strong: "backdrop-blur-2xl bg-opacity-90"
545
+ };
546
+ function CraftCard({
547
+ className,
548
+ tone,
549
+ elevated = true,
550
+ intensity = "medium",
551
+ bordered = true,
552
+ children,
553
+ ...props
554
+ }) {
555
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
410
556
  "div",
411
557
  {
412
558
  className: cn(
413
- "rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-6 text-[rgb(var(--nc-fg))] backdrop-blur-xl",
414
- elevated && "shadow-[0_18px_40px_rgba(0,0,0,0.35)]",
559
+ "relative overflow-hidden rounded-3xl p-6 text-[rgb(var(--nc-fg))]",
560
+ intensityClasses2[intensity],
561
+ "bg-linear-to-br from-[rgb(var(--nc-accent-1)/0.15)] via-[rgb(var(--nc-accent-2)/0.10)] to-[rgb(var(--nc-accent-3)/0.15)]",
562
+ bordered ? "border-2 border-[rgb(var(--nc-accent-1)/0.3)]" : "border-0",
563
+ elevated ? "shadow-[0_8px_32px_rgba(0,0,0,0.3)] hover:shadow-[0_8px_40px_rgba(0,0,0,0.4)]" : "shadow-none",
564
+ "before:absolute before:inset-0 before:bg-linear-to-br before:from-white/10 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity before:duration-300",
415
565
  "transition-all duration-300",
416
566
  className
417
567
  ),
418
568
  "data-nc-theme": tone,
419
- ...props
569
+ ...props,
570
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "relative z-10", children })
420
571
  }
421
572
  );
422
573
  }
@@ -424,7 +575,7 @@ function CraftCard({ className, tone, elevated = true, ...props }) {
424
575
  // src/components/craft-modal.tsx
425
576
  var React6 = __toESM(require("react"), 1);
426
577
  var import_react_dom = require("react-dom");
427
- var import_jsx_runtime10 = require("react/jsx-runtime");
578
+ var import_jsx_runtime13 = require("react/jsx-runtime");
428
579
  var FOCUSABLE_SELECTORS = [
429
580
  "a[href]",
430
581
  "button:not([disabled])",
@@ -498,48 +649,49 @@ function CraftModal({
498
649
  return () => document.removeEventListener("keydown", handleKey);
499
650
  }, [isOpen, setOpen]);
500
651
  const ref = useFocusTrap(isOpen);
501
- const content = isOpen ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center px-4 py-8", children: [
502
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
652
+ const content = isOpen ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center px-4 py-8", children: [
653
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
503
654
  "div",
504
655
  {
505
656
  className: "absolute inset-0 backdrop-blur-sm",
506
657
  onClick: () => setOpen(false)
507
658
  }
508
659
  ),
509
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
660
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
510
661
  "div",
511
662
  {
512
663
  ref,
513
664
  tabIndex: -1,
514
665
  className: cn(
515
- "relative z-10 w-full max-w-lg rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-6 text-[rgb(var(--nc-fg))] shadow-[0_20px_60px_rgba(0,0,0,0.45)] backdrop-blur-2xl",
666
+ "relative z-10 w-full max-w-7xl rounded-3xl border border-[rgb(var(--nc-border)/0.45)] p-6 text-[rgb(var(--nc-fg))] shadow-[0_20px_60px_rgba(0,0,0,0.45)] backdrop-blur-2xl",
667
+ "max-h-[calc(100vh-1rem)] overflow-y-auto",
516
668
  className
517
669
  ),
518
670
  "data-nc-theme": tone,
519
671
  children: [
520
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-start justify-between gap-4", children: [
521
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-1", children: [
522
- title && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-2xl font-semibold", children: title }),
523
- description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
672
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-start justify-between gap-4", children: [
673
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
674
+ title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: "text-2xl font-semibold", children: title }),
675
+ description && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
524
676
  ] }),
525
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
677
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
526
678
  "button",
527
679
  {
528
680
  className: "rounded-full border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-2 text-[rgb(var(--nc-fg-soft))] transition hover:text-[rgb(var(--nc-fg))]",
529
681
  onClick: () => setOpen(false),
530
682
  "aria-label": "Close",
531
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { viewBox: "0 0 20 20", className: "h-4 w-4", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" }) })
683
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { viewBox: "0 0 20 20", className: "h-4 w-4", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" }) })
532
684
  }
533
685
  )
534
686
  ] }),
535
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-5 space-y-4", children }),
536
- footer && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-6", children: footer })
687
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mt-5 space-y-4", children }),
688
+ footer && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mt-6", children: footer })
537
689
  ]
538
690
  }
539
691
  )
540
692
  ] }) : null;
541
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
542
- trigger && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
693
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
694
+ trigger && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
543
695
  "span",
544
696
  {
545
697
  onClick: () => setOpen(true),
@@ -559,7 +711,7 @@ function CraftModal({
559
711
  // src/components/craft-drawer.tsx
560
712
  var React7 = __toESM(require("react"), 1);
561
713
  var import_react_dom2 = require("react-dom");
562
- var import_jsx_runtime11 = require("react/jsx-runtime");
714
+ var import_jsx_runtime14 = require("react/jsx-runtime");
563
715
  function CraftDrawer({
564
716
  open,
565
717
  defaultOpen = false,
@@ -590,15 +742,15 @@ function CraftDrawer({
590
742
  document.addEventListener("keydown", handleKey);
591
743
  return () => document.removeEventListener("keydown", handleKey);
592
744
  }, [isOpen, setOpen]);
593
- const content = isOpen ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "fixed inset-0 z-50 overflow-hidden", children: [
594
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
745
+ const content = isOpen ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "fixed inset-0 z-50 overflow-hidden", children: [
746
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
595
747
  "div",
596
748
  {
597
749
  className: "absolute inset-0 backdrop-blur-sm",
598
750
  onClick: () => setOpen(false)
599
751
  }
600
752
  ),
601
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
753
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
602
754
  "div",
603
755
  {
604
756
  className: cn(
@@ -608,26 +760,26 @@ function CraftDrawer({
608
760
  ),
609
761
  "data-nc-theme": tone,
610
762
  children: [
611
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between border-b border-[rgb(var(--nc-border)/0.3)] p-6", children: [
612
- title && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-xl font-semibold", children: title }),
613
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
763
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center justify-between border-b border-[rgb(var(--nc-border)/0.3)] p-6", children: [
764
+ title && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: "text-xl font-semibold", children: title }),
765
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
614
766
  "button",
615
767
  {
616
768
  className: "rounded-full border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-2 text-[rgb(var(--nc-fg-soft))] transition hover:text-[rgb(var(--nc-fg))]",
617
769
  onClick: () => setOpen(false),
618
770
  "aria-label": "Close",
619
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { viewBox: "0 0 20 20", className: "h-4 w-4", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" }) })
771
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("svg", { viewBox: "0 0 20 20", className: "h-4 w-4", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" }) })
620
772
  }
621
773
  )
622
774
  ] }),
623
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "p-6 space-y-4 overflow-y-auto h-[calc(100%-5.5rem)]", children }),
624
- footer && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "border-t border-[rgb(var(--nc-border)/0.3)] p-6", children: footer })
775
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "p-6 space-y-4 overflow-y-auto h-[calc(100%-5.5rem)]", children }),
776
+ footer && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "border-t border-[rgb(var(--nc-border)/0.3)] p-6", children: footer })
625
777
  ]
626
778
  }
627
779
  )
628
780
  ] }) : null;
629
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
630
- trigger && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
781
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
782
+ trigger && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
631
783
  "span",
632
784
  {
633
785
  onClick: () => setOpen(true),
@@ -646,7 +798,7 @@ function CraftDrawer({
646
798
 
647
799
  // src/components/craft-tabs.tsx
648
800
  var React8 = __toESM(require("react"), 1);
649
- var import_jsx_runtime12 = require("react/jsx-runtime");
801
+ var import_jsx_runtime15 = require("react/jsx-runtime");
650
802
  function CraftTabs({
651
803
  value,
652
804
  defaultValue,
@@ -684,14 +836,14 @@ function CraftTabs({
684
836
  setValue(next.value);
685
837
  }
686
838
  };
687
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: cn("space-y-4", className), "data-nc-theme": tone, children: [
688
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
839
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cn("space-y-4", className), "data-nc-theme": tone, children: [
840
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
689
841
  "div",
690
842
  {
691
843
  className: "inline-flex flex-wrap items-center gap-2 rounded-full border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-2",
692
844
  role: "tablist",
693
845
  onKeyDown,
694
- children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
846
+ children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
695
847
  "button",
696
848
  {
697
849
  role: "tab",
@@ -707,16 +859,16 @@ function CraftTabs({
707
859
  ))
708
860
  }
709
861
  ),
710
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rounded-2xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-4 text-[rgb(var(--nc-fg))]", children: panels[activeValue] })
862
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rounded-2xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-4 text-[rgb(var(--nc-fg))]", children: panels[activeValue] })
711
863
  ] });
712
864
  }
713
865
 
714
866
  // src/components/craft-tooltip.tsx
715
867
  var React9 = __toESM(require("react"), 1);
716
- var import_jsx_runtime13 = require("react/jsx-runtime");
868
+ var import_jsx_runtime16 = require("react/jsx-runtime");
717
869
  function CraftTooltip({ content, tone, children, side = "top" }) {
718
870
  const [open, setOpen] = React9.useState(false);
719
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
871
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
720
872
  "span",
721
873
  {
722
874
  className: "relative inline-flex",
@@ -726,7 +878,7 @@ function CraftTooltip({ content, tone, children, side = "top" }) {
726
878
  onBlur: () => setOpen(false),
727
879
  children: [
728
880
  children,
729
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
881
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
730
882
  "span",
731
883
  {
732
884
  className: cn(
@@ -750,8 +902,8 @@ function CraftTooltip({ content, tone, children, side = "top" }) {
750
902
 
751
903
  // src/components/craft-toast.tsx
752
904
  var React10 = __toESM(require("react"), 1);
753
- var import_jsx_runtime14 = require("react/jsx-runtime");
754
- var variantClasses3 = {
905
+ var import_jsx_runtime17 = require("react/jsx-runtime");
906
+ var variantClasses4 = {
755
907
  info: "border-[color:rgb(var(--nc-accent-1)/0.4)]",
756
908
  success: "border-emerald-400/40",
757
909
  warning: "border-amber-400/40",
@@ -770,26 +922,26 @@ function useCraftToast() {
770
922
  return { toasts, push, remove };
771
923
  }
772
924
  function CraftToastHost({ toasts, onDismiss, tone }) {
773
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
925
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
774
926
  "div",
775
927
  {
776
928
  className: "fixed right-6 top-6 z-50 flex w-full max-w-sm flex-col gap-3",
777
929
  "data-nc-theme": tone,
778
930
  children: toasts.map((toast) => {
779
931
  var _a;
780
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
932
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
781
933
  "div",
782
934
  {
783
935
  className: cn(
784
936
  "rounded-2xl border bg-[rgb(var(--nc-surface)/0.12)] p-4 text-[rgb(var(--nc-fg))] shadow-[0_15px_35px_rgba(0,0,0,0.35)] backdrop-blur-xl",
785
- variantClasses3[(_a = toast.variant) != null ? _a : "info"]
937
+ variantClasses4[(_a = toast.variant) != null ? _a : "info"]
786
938
  ),
787
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-start justify-between gap-4", children: [
788
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
789
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm font-semibold", children: toast.title }),
790
- toast.description && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-xs text-[rgb(var(--nc-fg-muted))]", children: toast.description })
939
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-start justify-between gap-4", children: [
940
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
941
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm font-semibold", children: toast.title }),
942
+ toast.description && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-xs text-[rgb(var(--nc-fg-muted))]", children: toast.description })
791
943
  ] }),
792
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
944
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
793
945
  "button",
794
946
  {
795
947
  className: "text-[rgb(var(--nc-fg-soft))] hover:text-[rgb(var(--nc-fg))]",
@@ -807,9 +959,9 @@ function CraftToastHost({ toasts, onDismiss, tone }) {
807
959
  }
808
960
 
809
961
  // src/components/craft-skeleton.tsx
810
- var import_jsx_runtime15 = require("react/jsx-runtime");
962
+ var import_jsx_runtime18 = require("react/jsx-runtime");
811
963
  function CraftSkeleton({ className, tone, ...props }) {
812
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
964
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
813
965
  "div",
814
966
  {
815
967
  className: cn(
@@ -825,7 +977,7 @@ function CraftSkeleton({ className, tone, ...props }) {
825
977
  }
826
978
 
827
979
  // src/components/craft-empty-state.tsx
828
- var import_jsx_runtime16 = require("react/jsx-runtime");
980
+ var import_jsx_runtime19 = require("react/jsx-runtime");
829
981
  function CraftEmptyState({
830
982
  className,
831
983
  tone,
@@ -835,7 +987,7 @@ function CraftEmptyState({
835
987
  action,
836
988
  ...props
837
989
  }) {
838
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
990
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
839
991
  "div",
840
992
  {
841
993
  className: cn(
@@ -846,69 +998,51 @@ function CraftEmptyState({
846
998
  "data-nc-theme": tone,
847
999
  ...props,
848
1000
  children: [
849
- icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-2xl bg-[rgb(var(--nc-accent-1)/0.2)] text-[rgb(var(--nc-accent-1))]", children: icon }),
850
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { className: "text-xl font-semibold", children: title }),
851
- description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "mt-2 text-sm text-[rgb(var(--nc-fg-muted))]", children: description }),
852
- action && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "mt-6 flex justify-center", children: action })
1001
+ icon && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-2xl bg-[rgb(var(--nc-accent-1)/0.2)] text-[rgb(var(--nc-accent-1))]", children: icon }),
1002
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: "text-xl font-semibold", children: title }),
1003
+ description && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mt-2 text-sm text-[rgb(var(--nc-fg-muted))]", children: description }),
1004
+ action && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "mt-6 flex justify-center", children: action })
853
1005
  ]
854
1006
  }
855
1007
  );
856
1008
  }
857
1009
 
858
- // src/components/craft-date-picker.tsx
1010
+ // src/components/craft-popover.tsx
859
1011
  var React11 = __toESM(require("react"), 1);
860
- var import_jsx_runtime17 = require("react/jsx-runtime");
861
- var WEEK_DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
862
- function formatDate(date) {
863
- const year = date.getFullYear();
864
- const month = `${date.getMonth() + 1}`.padStart(2, "0");
865
- const day = `${date.getDate()}`.padStart(2, "0");
866
- return `${year}-${month}-${day}`;
867
- }
868
- function parseDate(value) {
869
- if (!value) return null;
870
- const [year, month, day] = value.split("-").map(Number);
871
- if (!year || !month || !day) return null;
872
- return new Date(year, month - 1, day);
873
- }
874
- function isSameDay(a, b) {
875
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
876
- }
877
- function isOutsideRange(date, min, max) {
878
- const minDate = parseDate(min);
879
- const maxDate = parseDate(max);
880
- if (minDate && date < minDate) return true;
881
- if (maxDate && date > maxDate) return true;
882
- return false;
883
- }
884
- function CraftDatePicker({
885
- value,
886
- defaultValue,
887
- onChange,
1012
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1013
+ var alignClasses = {
1014
+ start: "left-0",
1015
+ center: "left-1/2 -translate-x-1/2",
1016
+ end: "right-0"
1017
+ };
1018
+ function CraftPopover({
1019
+ open,
1020
+ defaultOpen = false,
1021
+ onOpenChange,
1022
+ trigger,
1023
+ content,
1024
+ align = "start",
1025
+ sideOffset = 10,
888
1026
  tone,
889
- min,
890
- max,
891
- placeholder = "Select date",
892
- className
1027
+ className,
1028
+ contentClassName
893
1029
  }) {
894
- const [open, setOpen] = React11.useState(false);
895
- const [uncontrolledValue, setUncontrolledValue] = React11.useState(defaultValue != null ? defaultValue : "");
896
- const isControlled = value !== void 0;
897
- const selectedValue = isControlled ? value != null ? value : "" : uncontrolledValue;
898
- const selectedDate = parseDate(selectedValue);
899
- const initialMonth = selectedDate != null ? selectedDate : /* @__PURE__ */ new Date();
900
- const [viewDate, setViewDate] = React11.useState(initialMonth);
901
- React11.useEffect(() => {
902
- if (selectedDate) setViewDate(selectedDate);
903
- }, [selectedDate]);
904
- const wrapperRef = React11.useRef(null);
1030
+ const [uncontrolledOpen, setUncontrolledOpen] = React11.useState(defaultOpen);
1031
+ const isControlled = typeof open === "boolean";
1032
+ const isOpen = isControlled ? open : uncontrolledOpen;
1033
+ const rootRef = React11.useRef(null);
1034
+ const setOpen = React11.useCallback(
1035
+ (next) => {
1036
+ if (!isControlled) setUncontrolledOpen(next);
1037
+ onOpenChange == null ? void 0 : onOpenChange(next);
1038
+ },
1039
+ [isControlled, onOpenChange]
1040
+ );
905
1041
  React11.useEffect(() => {
906
- if (!open) return;
1042
+ if (!isOpen) return;
907
1043
  const handleClick = (event) => {
908
- var _a;
909
- if (!((_a = wrapperRef.current) == null ? void 0 : _a.contains(event.target))) {
910
- setOpen(false);
911
- }
1044
+ if (!rootRef.current) return;
1045
+ if (!rootRef.current.contains(event.target)) setOpen(false);
912
1046
  };
913
1047
  const handleKey = (event) => {
914
1048
  if (event.key === "Escape") setOpen(false);
@@ -919,81 +1053,438 @@ function CraftDatePicker({
919
1053
  document.removeEventListener("mousedown", handleClick);
920
1054
  document.removeEventListener("keydown", handleKey);
921
1055
  };
922
- }, [open]);
923
- const setValue = React11.useCallback(
924
- (next) => {
925
- if (!isControlled) setUncontrolledValue(next);
926
- onChange == null ? void 0 : onChange(next);
1056
+ }, [isOpen, setOpen]);
1057
+ const triggerNode = React11.isValidElement(trigger) ? React11.cloneElement(trigger, {
1058
+ onClick: (event) => {
1059
+ const handler = trigger.props.onClick;
1060
+ handler == null ? void 0 : handler(event);
1061
+ if (!event.defaultPrevented) setOpen(!isOpen);
927
1062
  },
928
- [isControlled, onChange]
929
- );
930
- const monthStart = new Date(viewDate.getFullYear(), viewDate.getMonth(), 1);
931
- const monthEnd = new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 0);
932
- const startDay = monthStart.getDay();
933
- const daysInMonth = monthEnd.getDate();
934
- const cells = Array.from({ length: startDay + daysInMonth }, (_, i) => {
935
- const dayNumber = i - startDay + 1;
936
- if (dayNumber < 1) return null;
937
- return new Date(viewDate.getFullYear(), viewDate.getMonth(), dayNumber);
938
- });
939
- const handleDaySelect = (date) => {
940
- if (isOutsideRange(date, min, max)) return;
941
- const next = formatDate(date);
942
- setValue(next);
943
- setOpen(false);
944
- };
945
- const handleKeyDown = (event) => {
946
- if (!open) return;
947
- if (!selectedDate) return;
948
- const next = new Date(selectedDate);
949
- if (event.key === "ArrowRight") next.setDate(next.getDate() + 1);
950
- if (event.key === "ArrowLeft") next.setDate(next.getDate() - 1);
951
- if (event.key === "ArrowDown") next.setDate(next.getDate() + 7);
952
- if (event.key === "ArrowUp") next.setDate(next.getDate() - 7);
953
- if (event.key === "Enter") {
954
- event.preventDefault();
955
- handleDaySelect(selectedDate);
956
- return;
957
- }
958
- if (next.getTime() !== selectedDate.getTime()) {
959
- event.preventDefault();
960
- if (!isOutsideRange(next, min, max)) {
961
- setValue(formatDate(next));
962
- setViewDate(next);
963
- }
1063
+ "aria-expanded": isOpen,
1064
+ "aria-haspopup": "dialog"
1065
+ }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1066
+ "button",
1067
+ {
1068
+ type: "button",
1069
+ onClick: () => setOpen(!isOpen),
1070
+ className: "inline-flex",
1071
+ "aria-expanded": isOpen,
1072
+ "aria-haspopup": "dialog",
1073
+ children: trigger
964
1074
  }
965
- };
966
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "relative w-full", "data-nc-theme": tone, ref: wrapperRef, children: [
967
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
968
- "button",
1075
+ );
1076
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: cn("relative inline-flex", className), ref: rootRef, children: [
1077
+ triggerNode,
1078
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1079
+ "div",
969
1080
  {
970
- type: "button",
971
- onClick: () => setOpen((prev) => !prev),
972
1081
  className: cn(
973
- "flex w-full items-center justify-between rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] px-5 py-3 text-left text-base text-[rgb(var(--nc-fg))] backdrop-blur-xl",
974
- "shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
975
- "transition-all duration-300",
976
- "border-[rgb(var(--nc-border)/0.35)]",
977
- "focus:outline-none focus:ring-4 focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
978
- className
1082
+ "absolute z-40 w-max min-w-48 rounded-2xl border border-[rgb(var(--nc-border)/0.35)] bg-[rgb(var(--nc-surface)/0.08)] p-3 text-[rgb(var(--nc-fg))] shadow-[0_18px_40px_rgba(0,0,0,0.35)] backdrop-blur-2xl",
1083
+ alignClasses[align],
1084
+ contentClassName
979
1085
  ),
980
- children: [
981
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: selectedValue ? "text-[rgb(var(--nc-fg))]" : "text-[rgb(var(--nc-fg-soft))]", children: selectedValue || placeholder }),
982
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: "h-4 w-4 text-[rgb(var(--nc-fg-soft))]", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M6 2a1 1 0 011 1v1h6V3a1 1 0 112 0v1h1a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2h1V3a1 1 0 011-1zm10 6H4v8h12V8z" }) })
983
- ]
1086
+ style: { marginTop: sideOffset },
1087
+ role: "dialog",
1088
+ "data-nc-theme": tone,
1089
+ children: content
984
1090
  }
985
- ),
986
- open && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
987
- "div",
1091
+ )
1092
+ ] });
1093
+ }
1094
+
1095
+ // src/components/craft-dropdown-menu.tsx
1096
+ var React12 = __toESM(require("react"), 1);
1097
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1098
+ function CraftDropdownMenu({
1099
+ trigger,
1100
+ items = [],
1101
+ content,
1102
+ open,
1103
+ defaultOpen = false,
1104
+ onOpenChange,
1105
+ align = "end",
1106
+ tone,
1107
+ className,
1108
+ menuClassName
1109
+ }) {
1110
+ const [uncontrolledOpen, setUncontrolledOpen] = React12.useState(defaultOpen);
1111
+ const isControlled = typeof open === "boolean";
1112
+ const isOpen = isControlled ? open : uncontrolledOpen;
1113
+ const setOpen = React12.useCallback(
1114
+ (next) => {
1115
+ if (!isControlled) setUncontrolledOpen(next);
1116
+ onOpenChange == null ? void 0 : onOpenChange(next);
1117
+ },
1118
+ [isControlled, onOpenChange]
1119
+ );
1120
+ const menuContent = content != null ? content : items.length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: cn("space-y-1", menuClassName), role: "menu", children: items.map((item, index) => {
1121
+ var _a;
1122
+ const key = (_a = item.id) != null ? _a : `${index}-${String(item.label)}`;
1123
+ const itemClasses = cn(
1124
+ "flex w-full items-start gap-3 rounded-xl px-3 py-2 text-left text-sm transition",
1125
+ item.disabled ? "cursor-not-allowed text-[rgb(var(--nc-fg-soft))] opacity-60" : "text-[rgb(var(--nc-fg))] hover:bg-[rgb(var(--nc-surface)/0.12)]"
1126
+ );
1127
+ const contentNode = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
1128
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "mt-0.5", children: item.icon }),
1129
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "flex-1", children: [
1130
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "block font-medium", children: item.label }),
1131
+ item.description && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "block text-xs text-[rgb(var(--nc-fg-muted))]", children: item.description })
1132
+ ] })
1133
+ ] });
1134
+ if (item.href) {
1135
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1136
+ "a",
1137
+ {
1138
+ href: item.href,
1139
+ className: itemClasses,
1140
+ role: "menuitem",
1141
+ onClick: () => {
1142
+ var _a2;
1143
+ if (item.disabled) return;
1144
+ (_a2 = item.onSelect) == null ? void 0 : _a2.call(item);
1145
+ setOpen(false);
1146
+ },
1147
+ children: contentNode
1148
+ },
1149
+ key
1150
+ );
1151
+ }
1152
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1153
+ "button",
988
1154
  {
989
- className: cn(
990
- "absolute left-0 top-full z-20 mt-3 w-full rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/1.52)] p-4 text-[rgb(var(--nc-fg))] shadow-[0_20px_60px_rgba(0,0,0,0.55)] backdrop-blur-10xl"
1155
+ type: "button",
1156
+ className: itemClasses,
1157
+ role: "menuitem",
1158
+ onClick: () => {
1159
+ var _a2;
1160
+ if (item.disabled) return;
1161
+ (_a2 = item.onSelect) == null ? void 0 : _a2.call(item);
1162
+ setOpen(false);
1163
+ },
1164
+ children: contentNode
1165
+ },
1166
+ key
1167
+ );
1168
+ }) }) : null;
1169
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1170
+ CraftPopover,
1171
+ {
1172
+ trigger,
1173
+ content: menuContent,
1174
+ open: isOpen,
1175
+ onOpenChange: setOpen,
1176
+ align,
1177
+ tone,
1178
+ className
1179
+ }
1180
+ );
1181
+ }
1182
+
1183
+ // src/components/craft-command-palette.tsx
1184
+ var React13 = __toESM(require("react"), 1);
1185
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1186
+ function CraftCommandPalette({
1187
+ items,
1188
+ open,
1189
+ defaultOpen = false,
1190
+ onOpenChange,
1191
+ trigger,
1192
+ title = "Command Palette",
1193
+ placeholder = "Search commands...",
1194
+ emptyText = "No results found.",
1195
+ tone,
1196
+ className
1197
+ }) {
1198
+ const [uncontrolledOpen, setUncontrolledOpen] = React13.useState(defaultOpen);
1199
+ const isControlled = typeof open === "boolean";
1200
+ const isOpen = isControlled ? open : uncontrolledOpen;
1201
+ const [query, setQuery] = React13.useState("");
1202
+ const setOpen = React13.useCallback(
1203
+ (next) => {
1204
+ if (!isControlled) setUncontrolledOpen(next);
1205
+ onOpenChange == null ? void 0 : onOpenChange(next);
1206
+ },
1207
+ [isControlled, onOpenChange]
1208
+ );
1209
+ const filtered = React13.useMemo(() => {
1210
+ const q = query.trim().toLowerCase();
1211
+ if (!q) return items;
1212
+ return items.filter((item) => {
1213
+ var _a, _b;
1214
+ const haystack = [
1215
+ item.label,
1216
+ (_a = item.description) != null ? _a : "",
1217
+ ...(_b = item.keywords) != null ? _b : []
1218
+ ].join(" ").toLowerCase();
1219
+ return haystack.includes(q);
1220
+ });
1221
+ }, [items, query]);
1222
+ React13.useEffect(() => {
1223
+ if (!isOpen) setQuery("");
1224
+ }, [isOpen]);
1225
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1226
+ CraftModal,
1227
+ {
1228
+ open: isOpen,
1229
+ onOpenChange: setOpen,
1230
+ trigger,
1231
+ title,
1232
+ tone,
1233
+ className: cn("max-w-xl", className),
1234
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-4", children: [
1235
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1236
+ CraftInput,
1237
+ {
1238
+ type: "search",
1239
+ placeholder,
1240
+ value: query,
1241
+ onChange: (event) => setQuery(event.target.value)
1242
+ }
1243
+ ),
1244
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-2", children: [
1245
+ filtered.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "rounded-2xl border border-[rgb(var(--nc-border)/0.35)] bg-[rgb(var(--nc-surface)/0.12)] p-4 text-sm text-[rgb(var(--nc-fg-muted))]", children: emptyText }),
1246
+ filtered.map((item) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1247
+ "button",
1248
+ {
1249
+ type: "button",
1250
+ disabled: item.disabled,
1251
+ onClick: () => {
1252
+ var _a;
1253
+ if (item.disabled) return;
1254
+ (_a = item.onSelect) == null ? void 0 : _a.call(item);
1255
+ setOpen(false);
1256
+ },
1257
+ className: cn(
1258
+ "flex w-full items-start gap-3 rounded-2xl border border-[rgb(var(--nc-border)/0.35)] bg-[rgb(var(--nc-surface)/0.08)] px-4 py-3 text-left transition",
1259
+ item.disabled ? "cursor-not-allowed opacity-60" : "hover:bg-[rgb(var(--nc-surface)/0.16)]"
1260
+ ),
1261
+ children: [
1262
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "mt-1", children: item.icon }),
1263
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { children: [
1264
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "block text-sm font-semibold", children: item.label }),
1265
+ item.description && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "block text-xs text-[rgb(var(--nc-fg-muted))]", children: item.description })
1266
+ ] })
1267
+ ]
1268
+ },
1269
+ item.id
1270
+ ))
1271
+ ] })
1272
+ ] })
1273
+ }
1274
+ );
1275
+ }
1276
+
1277
+ // src/components/craft-link.tsx
1278
+ var import_link = __toESM(require("next/link"), 1);
1279
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1280
+ var variantClasses5 = {
1281
+ default: "text-[rgb(var(--nc-accent-1))] hover:text-[rgb(var(--nc-accent-1))]",
1282
+ muted: "text-[rgb(var(--nc-fg-muted))] hover:text-[rgb(var(--nc-fg))]",
1283
+ button: "inline-flex items-center rounded-xl border border-[rgb(var(--nc-border)/0.35)] bg-[rgb(var(--nc-surface)/0.12)] px-4 py-2 text-sm font-semibold text-[rgb(var(--nc-fg))] transition hover:bg-[rgb(var(--nc-surface)/0.2)]",
1284
+ ghost: "inline-flex items-center rounded-xl px-4 py-2 text-sm font-semibold text-[rgb(var(--nc-fg))] transition hover:bg-[rgb(var(--nc-surface)/0.18)]"
1285
+ };
1286
+ function CraftLink({
1287
+ variant = "default",
1288
+ underline = false,
1289
+ tone,
1290
+ className,
1291
+ children,
1292
+ ...props
1293
+ }) {
1294
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1295
+ import_link.default,
1296
+ {
1297
+ className: cn(
1298
+ "transition-colors",
1299
+ variantClasses5[variant],
1300
+ underline && "underline underline-offset-4",
1301
+ className
1302
+ ),
1303
+ "data-nc-theme": tone,
1304
+ ...props,
1305
+ children
1306
+ }
1307
+ );
1308
+ }
1309
+
1310
+ // src/components/craft-stat-card.tsx
1311
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1312
+ var trendClasses = {
1313
+ up: "text-emerald-300",
1314
+ down: "text-rose-300",
1315
+ neutral: "text-[rgb(var(--nc-fg-muted))]"
1316
+ };
1317
+ function CraftStatCard({
1318
+ label,
1319
+ value,
1320
+ delta,
1321
+ trend = "neutral",
1322
+ icon,
1323
+ footer,
1324
+ tone,
1325
+ className,
1326
+ ...props
1327
+ }) {
1328
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
1329
+ CraftCard,
1330
+ {
1331
+ className: cn("space-y-3", className),
1332
+ tone,
1333
+ ...props,
1334
+ children: [
1335
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center justify-between", children: [
1336
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: label }),
1337
+ icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "text-[rgb(var(--nc-fg-soft))]", children: icon })
1338
+ ] }),
1339
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-3xl font-semibold", children: value }),
1340
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center justify-between text-xs", children: [
1341
+ delta && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: trendClasses[trend], children: delta }),
1342
+ footer && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: footer })
1343
+ ] })
1344
+ ]
1345
+ }
1346
+ );
1347
+ }
1348
+
1349
+ // src/components/craft-date-picker.tsx
1350
+ var React14 = __toESM(require("react"), 1);
1351
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1352
+ var WEEK_DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
1353
+ function formatDate(date) {
1354
+ const year = date.getFullYear();
1355
+ const month = `${date.getMonth() + 1}`.padStart(2, "0");
1356
+ const day = `${date.getDate()}`.padStart(2, "0");
1357
+ return `${year}-${month}-${day}`;
1358
+ }
1359
+ function parseDate(value) {
1360
+ if (!value) return null;
1361
+ const [year, month, day] = value.split("-").map(Number);
1362
+ if (!year || !month || !day) return null;
1363
+ return new Date(year, month - 1, day);
1364
+ }
1365
+ function isSameDay(a, b) {
1366
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
1367
+ }
1368
+ function isOutsideRange(date, min, max) {
1369
+ const minDate = parseDate(min);
1370
+ const maxDate = parseDate(max);
1371
+ if (minDate && date < minDate) return true;
1372
+ if (maxDate && date > maxDate) return true;
1373
+ return false;
1374
+ }
1375
+ function CraftDatePicker({
1376
+ value,
1377
+ defaultValue,
1378
+ onChange,
1379
+ tone,
1380
+ min,
1381
+ max,
1382
+ placeholder = "Select date",
1383
+ className
1384
+ }) {
1385
+ const [open, setOpen] = React14.useState(false);
1386
+ const [uncontrolledValue, setUncontrolledValue] = React14.useState(defaultValue != null ? defaultValue : "");
1387
+ const isControlled = value !== void 0;
1388
+ const selectedValue = isControlled ? value != null ? value : "" : uncontrolledValue;
1389
+ const selectedDate = parseDate(selectedValue);
1390
+ const initialMonth = selectedDate != null ? selectedDate : /* @__PURE__ */ new Date();
1391
+ const [viewDate, setViewDate] = React14.useState(initialMonth);
1392
+ React14.useEffect(() => {
1393
+ if (selectedDate) setViewDate(selectedDate);
1394
+ }, [selectedDate]);
1395
+ const wrapperRef = React14.useRef(null);
1396
+ React14.useEffect(() => {
1397
+ if (!open) return;
1398
+ const handleClick = (event) => {
1399
+ var _a;
1400
+ if (!((_a = wrapperRef.current) == null ? void 0 : _a.contains(event.target))) {
1401
+ setOpen(false);
1402
+ }
1403
+ };
1404
+ const handleKey = (event) => {
1405
+ if (event.key === "Escape") setOpen(false);
1406
+ };
1407
+ document.addEventListener("mousedown", handleClick);
1408
+ document.addEventListener("keydown", handleKey);
1409
+ return () => {
1410
+ document.removeEventListener("mousedown", handleClick);
1411
+ document.removeEventListener("keydown", handleKey);
1412
+ };
1413
+ }, [open]);
1414
+ const setValue = React14.useCallback(
1415
+ (next) => {
1416
+ if (!isControlled) setUncontrolledValue(next);
1417
+ onChange == null ? void 0 : onChange(next);
1418
+ },
1419
+ [isControlled, onChange]
1420
+ );
1421
+ const monthStart = new Date(viewDate.getFullYear(), viewDate.getMonth(), 1);
1422
+ const monthEnd = new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 0);
1423
+ const startDay = monthStart.getDay();
1424
+ const daysInMonth = monthEnd.getDate();
1425
+ const cells = Array.from({ length: startDay + daysInMonth }, (_, i) => {
1426
+ const dayNumber = i - startDay + 1;
1427
+ if (dayNumber < 1) return null;
1428
+ return new Date(viewDate.getFullYear(), viewDate.getMonth(), dayNumber);
1429
+ });
1430
+ const handleDaySelect = (date) => {
1431
+ if (isOutsideRange(date, min, max)) return;
1432
+ const next = formatDate(date);
1433
+ setValue(next);
1434
+ setOpen(false);
1435
+ };
1436
+ const handleKeyDown = (event) => {
1437
+ if (!open) return;
1438
+ if (!selectedDate) return;
1439
+ const next = new Date(selectedDate);
1440
+ if (event.key === "ArrowRight") next.setDate(next.getDate() + 1);
1441
+ if (event.key === "ArrowLeft") next.setDate(next.getDate() - 1);
1442
+ if (event.key === "ArrowDown") next.setDate(next.getDate() + 7);
1443
+ if (event.key === "ArrowUp") next.setDate(next.getDate() - 7);
1444
+ if (event.key === "Enter") {
1445
+ event.preventDefault();
1446
+ handleDaySelect(selectedDate);
1447
+ return;
1448
+ }
1449
+ if (next.getTime() !== selectedDate.getTime()) {
1450
+ event.preventDefault();
1451
+ if (!isOutsideRange(next, min, max)) {
1452
+ setValue(formatDate(next));
1453
+ setViewDate(next);
1454
+ }
1455
+ }
1456
+ };
1457
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "relative w-full", "data-nc-theme": tone, ref: wrapperRef, children: [
1458
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1459
+ "button",
1460
+ {
1461
+ type: "button",
1462
+ onClick: () => setOpen((prev) => !prev),
1463
+ className: cn(
1464
+ "flex w-full items-center justify-between rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] px-5 py-3 text-left text-base text-[rgb(var(--nc-fg))] backdrop-blur-xl",
1465
+ "shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
1466
+ "transition-all duration-300",
1467
+ "border-[rgb(var(--nc-border)/0.35)]",
1468
+ "focus:outline-none focus:ring-4 focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
1469
+ className
1470
+ ),
1471
+ children: [
1472
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: selectedValue ? "text-[rgb(var(--nc-fg))]" : "text-[rgb(var(--nc-fg-soft))]", children: selectedValue || placeholder }),
1473
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("svg", { className: "h-4 w-4 text-[rgb(var(--nc-fg-soft))]", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "M6 2a1 1 0 011 1v1h6V3a1 1 0 112 0v1h1a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2h1V3a1 1 0 011-1zm10 6H4v8h12V8z" }) })
1474
+ ]
1475
+ }
1476
+ ),
1477
+ open && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1478
+ "div",
1479
+ {
1480
+ className: cn(
1481
+ "absolute left-0 top-full z-20 mt-3 w-full rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/1.52)] p-4 text-[rgb(var(--nc-fg))] shadow-[0_20px_60px_rgba(0,0,0,0.55)] backdrop-blur-10xl"
991
1482
  ),
992
1483
  onKeyDown: handleKeyDown,
993
1484
  tabIndex: -1,
994
1485
  children: [
995
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between", children: [
996
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1486
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
1487
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
997
1488
  "button",
998
1489
  {
999
1490
  type: "button",
@@ -1004,8 +1495,8 @@ function CraftDatePicker({
1004
1495
  children: "Prev"
1005
1496
  }
1006
1497
  ),
1007
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "text-sm font-semibold", children: viewDate.toLocaleString(void 0, { month: "long", year: "numeric" }) }),
1008
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1498
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-sm font-semibold", children: viewDate.toLocaleString(void 0, { month: "long", year: "numeric" }) }),
1499
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1009
1500
  "button",
1010
1501
  {
1011
1502
  type: "button",
@@ -1017,94 +1508,1522 @@ function CraftDatePicker({
1017
1508
  }
1018
1509
  )
1019
1510
  ] }),
1020
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "mt-4 grid grid-cols-7 gap-2 text-xs text-[rgb(var(--nc-fg-muted))]", children: WEEK_DAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "text-center", children: day }, day)) }),
1021
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "mt-2 grid grid-cols-7 gap-2", children: cells.map((date, index) => {
1022
- if (!date) return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", {}, `empty-${index}`);
1023
- const disabled = isOutsideRange(date, min, max);
1024
- const selected = selectedDate && isSameDay(date, selectedDate);
1025
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1511
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-4 grid grid-cols-7 gap-2 text-xs text-[rgb(var(--nc-fg-muted))]", children: WEEK_DAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-center", children: day }, day)) }),
1512
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-2 grid grid-cols-7 gap-2", children: cells.map((date, index) => {
1513
+ if (!date) return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", {}, `empty-${index}`);
1514
+ const disabled = isOutsideRange(date, min, max);
1515
+ const selected = selectedDate && isSameDay(date, selectedDate);
1516
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1517
+ "button",
1518
+ {
1519
+ type: "button",
1520
+ onClick: () => handleDaySelect(date),
1521
+ disabled,
1522
+ className: cn(
1523
+ "rounded-lg py-2 text-sm transition-all",
1524
+ selected ? "bg-[rgb(var(--nc-accent-1)/0.3)] text-[rgb(var(--nc-fg))]" : "text-[rgb(var(--nc-fg-muted))] hover:bg-[rgb(var(--nc-surface)/0.12)]",
1525
+ disabled && "opacity-40 hover:bg-transparent"
1526
+ ),
1527
+ children: date.getDate()
1528
+ },
1529
+ date.toISOString()
1530
+ );
1531
+ }) })
1532
+ ]
1533
+ }
1534
+ )
1535
+ ] });
1536
+ }
1537
+
1538
+ // src/components/craft-icon.tsx
1539
+ var React15 = __toESM(require("react"), 1);
1540
+ var import_dynamic = require("lucide-react/dynamic");
1541
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1542
+ var CraftIconContext = React15.createContext(null);
1543
+ function CraftIconProvider({ icons, children }) {
1544
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(CraftIconContext.Provider, { value: icons, children });
1545
+ }
1546
+ function CraftIcon({
1547
+ name,
1548
+ className,
1549
+ "aria-label": ariaLabel,
1550
+ icons,
1551
+ useLucide = true
1552
+ }) {
1553
+ const contextRegistry = React15.useContext(CraftIconContext);
1554
+ const registry = icons != null ? icons : contextRegistry;
1555
+ const icon = registry == null ? void 0 : registry[name];
1556
+ if (!icon) {
1557
+ if (!useLucide) return null;
1558
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1559
+ import_dynamic.DynamicIcon,
1560
+ {
1561
+ name,
1562
+ className,
1563
+ "aria-hidden": ariaLabel ? void 0 : true,
1564
+ "aria-label": ariaLabel
1565
+ }
1566
+ );
1567
+ }
1568
+ if (React15.isValidElement(icon)) {
1569
+ return React15.cloneElement(icon, {
1570
+ className: cn(icon.props.className, className),
1571
+ "aria-hidden": ariaLabel ? void 0 : true,
1572
+ "aria-label": ariaLabel
1573
+ });
1574
+ }
1575
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className, "aria-label": ariaLabel, children: icon });
1576
+ }
1577
+
1578
+ // src/components/craft-number-input.tsx
1579
+ var React16 = __toESM(require("react"), 1);
1580
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1581
+ var CraftNumberInput = React16.forwardRef(({ className, tone, ...props }, ref) => {
1582
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "relative w-full", "data-nc-theme": tone, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1583
+ "input",
1584
+ {
1585
+ ref,
1586
+ type: "number",
1587
+ className: cn(
1588
+ "w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl",
1589
+ "shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
1590
+ "focus:outline-none focus:ring-4",
1591
+ "transition-all duration-300",
1592
+ "disabled:opacity-50 disabled:cursor-not-allowed",
1593
+ "border-[rgb(var(--nc-border)/0.35)]",
1594
+ "focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
1595
+ "px-5 py-3 text-base",
1596
+ className
1597
+ ),
1598
+ ...props
1599
+ }
1600
+ ) });
1601
+ });
1602
+ CraftNumberInput.displayName = "CraftNumberInput";
1603
+
1604
+ // src/components/craft-currency-input.tsx
1605
+ var React17 = __toESM(require("react"), 1);
1606
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1607
+ var CraftCurrencyInput = React17.forwardRef(({ className, tone, currencySymbol = "$", ...props }, ref) => {
1608
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "relative w-full", "data-nc-theme": tone, children: [
1609
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "pointer-events-none absolute left-4 top-1/2 -translate-y-1/2 text-[rgb(var(--nc-fg-soft))]", children: currencySymbol }),
1610
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1611
+ "input",
1612
+ {
1613
+ ref,
1614
+ type: "text",
1615
+ inputMode: "decimal",
1616
+ className: cn(
1617
+ "w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl",
1618
+ "shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
1619
+ "focus:outline-none focus:ring-4",
1620
+ "transition-all duration-300",
1621
+ "disabled:opacity-50 disabled:cursor-not-allowed",
1622
+ "border-[rgb(var(--nc-border)/0.35)]",
1623
+ "focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
1624
+ "placeholder:text-[rgb(var(--nc-fg-soft))]",
1625
+ "px-5 py-3 pl-9 text-base",
1626
+ className
1627
+ ),
1628
+ ...props
1629
+ }
1630
+ )
1631
+ ] });
1632
+ });
1633
+ CraftCurrencyInput.displayName = "CraftCurrencyInput";
1634
+
1635
+ // src/components/craft-form.tsx
1636
+ var React18 = __toESM(require("react"), 1);
1637
+ var import_react_hook_form2 = require("react-hook-form");
1638
+
1639
+ // src/components/craft-submit-button.tsx
1640
+ var import_react_hook_form = require("react-hook-form");
1641
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1642
+ function CraftSubmitButton({
1643
+ className,
1644
+ tone,
1645
+ loading,
1646
+ loadingLabel = "Submitting...",
1647
+ disableWhenInvalid = true,
1648
+ disabled,
1649
+ children,
1650
+ ...props
1651
+ }) {
1652
+ var _a, _b, _c, _d;
1653
+ const form = (0, import_react_hook_form.useFormContext)();
1654
+ const isSubmitting = (_b = loading != null ? loading : (_a = form == null ? void 0 : form.formState) == null ? void 0 : _a.isSubmitting) != null ? _b : false;
1655
+ const isValid = (_d = (_c = form == null ? void 0 : form.formState) == null ? void 0 : _c.isValid) != null ? _d : true;
1656
+ const isDisabled = disabled || isSubmitting || disableWhenInvalid && !isValid;
1657
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1658
+ "button",
1659
+ {
1660
+ type: "submit",
1661
+ className: cn(
1662
+ "relative inline-flex items-center justify-center gap-2 rounded-xl px-6 py-2 text-sm font-semibold",
1663
+ "bg-linear-to-br from-[rgb(var(--nc-accent-1))] via-[rgb(var(--nc-accent-2))] to-[rgb(var(--nc-accent-3))]",
1664
+ "text-white shadow-[0_12px_30px_rgb(var(--nc-accent-1)/0.35)]",
1665
+ "transition-all duration-200",
1666
+ "hover:shadow-[0_16px_36px_rgb(var(--nc-accent-1)/0.5)] hover:scale-[1.02] active:scale-[0.98]",
1667
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[rgb(var(--nc-accent-1)/0.6)]",
1668
+ "disabled:opacity-60 disabled:cursor-not-allowed disabled:hover:scale-100",
1669
+ className
1670
+ ),
1671
+ "data-nc-theme": tone,
1672
+ disabled: isDisabled,
1673
+ ...props,
1674
+ children: [
1675
+ isSubmitting && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "inline-flex h-4 w-4 animate-spin rounded-full border-2 border-white/60 border-t-white" }),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: isSubmitting ? loadingLabel : children })
1677
+ ]
1678
+ }
1679
+ );
1680
+ }
1681
+
1682
+ // src/components/craft-form.tsx
1683
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1684
+ function CraftForm({
1685
+ form,
1686
+ onSubmit,
1687
+ open,
1688
+ defaultOpen = false,
1689
+ onOpenChange,
1690
+ trigger,
1691
+ title,
1692
+ description,
1693
+ submitLabel = "Save",
1694
+ cancelLabel = "Cancel",
1695
+ tone,
1696
+ className,
1697
+ children,
1698
+ footer,
1699
+ disableSubmitWhenInvalid = true,
1700
+ closeOnSubmit = true,
1701
+ formClassName
1702
+ }) {
1703
+ const [uncontrolledOpen, setUncontrolledOpen] = React18.useState(defaultOpen);
1704
+ const isControlled = typeof open === "boolean";
1705
+ const isOpen = isControlled ? open : uncontrolledOpen;
1706
+ const setOpen = React18.useCallback(
1707
+ (next) => {
1708
+ if (!isControlled) setUncontrolledOpen(next);
1709
+ onOpenChange == null ? void 0 : onOpenChange(next);
1710
+ },
1711
+ [isControlled, onOpenChange]
1712
+ );
1713
+ const formId = React18.useId();
1714
+ const handleSubmit = form.handleSubmit(async (values) => {
1715
+ await onSubmit(values);
1716
+ if (closeOnSubmit) setOpen(false);
1717
+ });
1718
+ const footerContent = footer != null ? footer : /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-wrap items-center justify-end gap-3", children: [
1719
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(CraftButton, { type: "button", variant: "ghost", onClick: () => setOpen(false), children: cancelLabel }),
1720
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1721
+ CraftSubmitButton,
1722
+ {
1723
+ form: formId,
1724
+ disableWhenInvalid: disableSubmitWhenInvalid,
1725
+ children: submitLabel
1726
+ }
1727
+ )
1728
+ ] });
1729
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_hook_form2.FormProvider, { ...form, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1730
+ CraftModal,
1731
+ {
1732
+ open: isOpen,
1733
+ onOpenChange: setOpen,
1734
+ trigger,
1735
+ title,
1736
+ description,
1737
+ tone,
1738
+ className,
1739
+ footer: footerContent,
1740
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1741
+ "form",
1742
+ {
1743
+ id: formId,
1744
+ onSubmit: handleSubmit,
1745
+ className: cn("space-y-5", formClassName),
1746
+ children
1747
+ }
1748
+ )
1749
+ }
1750
+ ) });
1751
+ }
1752
+
1753
+ // src/components/craft-form-builder.tsx
1754
+ var React19 = __toESM(require("react"), 1);
1755
+ var import_react_hook_form4 = require("react-hook-form");
1756
+
1757
+ // src/components/craft-form-field.tsx
1758
+ var import_react_hook_form3 = require("react-hook-form");
1759
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1760
+ function getFieldError(errors, name) {
1761
+ if (!errors || typeof errors !== "object") return void 0;
1762
+ const segments = name.split(".");
1763
+ let current = errors;
1764
+ for (const segment of segments) {
1765
+ if (!current || typeof current !== "object") return void 0;
1766
+ current = current[segment];
1767
+ }
1768
+ return current;
1769
+ }
1770
+ var baseInputClass = "w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)] focus:outline-none focus:ring-4 transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed border-[rgb(var(--nc-border)/0.35)] focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)] px-5 py-3 text-base placeholder:text-[rgb(var(--nc-fg-soft))]";
1771
+ function CraftFormField({
1772
+ name,
1773
+ label,
1774
+ description,
1775
+ type = "text",
1776
+ options = [],
1777
+ placeholder,
1778
+ tone,
1779
+ className,
1780
+ inputClassName,
1781
+ labelClassName,
1782
+ descriptionClassName,
1783
+ rules,
1784
+ disabled,
1785
+ fieldProps
1786
+ }) {
1787
+ const { register, control, formState } = (0, import_react_hook_form3.useFormContext)();
1788
+ const error = getFieldError(formState.errors, name);
1789
+ const errorMessage = typeof (error == null ? void 0 : error.message) === "string" ? error.message : void 0;
1790
+ if (type === "hidden") {
1791
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("input", { type: "hidden", ...register(name, rules) });
1792
+ }
1793
+ const labelNode = label ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1794
+ "label",
1795
+ {
1796
+ htmlFor: name,
1797
+ className: cn(
1798
+ "text-sm font-semibold text-[rgb(var(--nc-fg))]",
1799
+ labelClassName
1800
+ ),
1801
+ children: label
1802
+ }
1803
+ ) : null;
1804
+ const descriptionNode = description ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1805
+ "p",
1806
+ {
1807
+ className: cn(
1808
+ "text-xs text-[rgb(var(--nc-fg-muted))]",
1809
+ descriptionClassName
1810
+ ),
1811
+ children: description
1812
+ }
1813
+ ) : null;
1814
+ const errorNode = errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-xs text-[rgb(var(--nc-accent-3))]", children: errorMessage }) : null;
1815
+ const renderInput = () => {
1816
+ if (type === "textarea") {
1817
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1818
+ CraftTextarea,
1819
+ {
1820
+ id: name,
1821
+ placeholder,
1822
+ tone,
1823
+ className: inputClassName,
1824
+ disabled,
1825
+ ...fieldProps,
1826
+ ...register(name, rules)
1827
+ }
1828
+ );
1829
+ }
1830
+ if (type === "select" || type === "multiselect") {
1831
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1832
+ CraftSelect,
1833
+ {
1834
+ id: name,
1835
+ tone,
1836
+ className: inputClassName,
1837
+ multiple: type === "multiselect",
1838
+ disabled,
1839
+ ...fieldProps,
1840
+ ...register(name, rules),
1841
+ children: [
1842
+ placeholder && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("option", { value: "", disabled: true, children: placeholder }),
1843
+ options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1844
+ "option",
1845
+ {
1846
+ value: option.value,
1847
+ disabled: option.disabled,
1848
+ children: option.label
1849
+ },
1850
+ option.value
1851
+ ))
1852
+ ]
1853
+ }
1854
+ );
1855
+ }
1856
+ if (type === "checkbox") {
1857
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1858
+ CraftCheckbox,
1859
+ {
1860
+ tone,
1861
+ label,
1862
+ description,
1863
+ disabled,
1864
+ ...fieldProps,
1865
+ ...register(name, rules)
1866
+ }
1867
+ );
1868
+ }
1869
+ if (type === "switch") {
1870
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1871
+ CraftSwitch,
1872
+ {
1873
+ tone,
1874
+ label,
1875
+ disabled,
1876
+ ...fieldProps,
1877
+ ...register(name, rules)
1878
+ }
1879
+ );
1880
+ }
1881
+ if (type === "date") {
1882
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1883
+ import_react_hook_form3.Controller,
1884
+ {
1885
+ control,
1886
+ name,
1887
+ rules,
1888
+ render: ({ field }) => {
1889
+ var _a;
1890
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1891
+ CraftDatePicker,
1892
+ {
1893
+ value: (_a = field.value) != null ? _a : "",
1894
+ onChange: field.onChange,
1895
+ tone,
1896
+ placeholder,
1897
+ ...fieldProps
1898
+ }
1899
+ );
1900
+ }
1901
+ }
1902
+ );
1903
+ }
1904
+ if (type === "number") {
1905
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1906
+ CraftNumberInput,
1907
+ {
1908
+ id: name,
1909
+ tone,
1910
+ placeholder,
1911
+ className: inputClassName,
1912
+ disabled,
1913
+ ...fieldProps,
1914
+ ...register(name, rules)
1915
+ }
1916
+ );
1917
+ }
1918
+ if (type === "currency") {
1919
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1920
+ CraftCurrencyInput,
1921
+ {
1922
+ id: name,
1923
+ tone,
1924
+ placeholder,
1925
+ className: inputClassName,
1926
+ disabled,
1927
+ ...fieldProps,
1928
+ ...register(name, rules)
1929
+ }
1930
+ );
1931
+ }
1932
+ if (type === "radio") {
1933
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "grid gap-3", children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1934
+ "label",
1935
+ {
1936
+ className: cn(
1937
+ "flex items-center gap-3 rounded-2xl border border-[rgb(var(--nc-border)/0.35)] bg-[rgb(var(--nc-surface)/0.08)] px-4 py-3 text-sm text-[rgb(var(--nc-fg))]",
1938
+ "transition-all duration-200",
1939
+ "focus-within:ring-2 focus-within:ring-[rgb(var(--nc-accent-1)/0.5)]",
1940
+ option.disabled ? "opacity-60" : "cursor-pointer"
1941
+ ),
1942
+ "data-nc-theme": tone,
1943
+ children: [
1944
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1945
+ "input",
1946
+ {
1947
+ type: "radio",
1948
+ value: option.value,
1949
+ disabled: option.disabled || disabled,
1950
+ className: "h-4 w-4 accent-[rgb(var(--nc-accent-1))]",
1951
+ ...fieldProps,
1952
+ ...register(name, rules)
1953
+ }
1954
+ ),
1955
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: option.label })
1956
+ ]
1957
+ },
1958
+ option.value
1959
+ )) });
1960
+ }
1961
+ if (type === "range" || type === "slider") {
1962
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1963
+ "input",
1964
+ {
1965
+ id: name,
1966
+ type: "range",
1967
+ className: cn(
1968
+ "w-full accent-[rgb(var(--nc-accent-1))]",
1969
+ inputClassName
1970
+ ),
1971
+ disabled,
1972
+ ...fieldProps,
1973
+ ...register(name, rules)
1974
+ }
1975
+ );
1976
+ }
1977
+ if (type === "file" || type === "multifile") {
1978
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1979
+ "input",
1980
+ {
1981
+ id: name,
1982
+ type: "file",
1983
+ multiple: type === "multifile",
1984
+ className: cn(
1985
+ baseInputClass,
1986
+ "file:mr-4 file:rounded-xl file:border-0 file:bg-[rgb(var(--nc-surface)/0.35)] file:px-4 file:py-2 file:text-sm file:font-semibold file:text-[rgb(var(--nc-fg))]",
1987
+ inputClassName
1988
+ ),
1989
+ disabled,
1990
+ ...fieldProps,
1991
+ ...register(name, rules)
1992
+ }
1993
+ );
1994
+ }
1995
+ const inputType = type === "search" || type === "password" || type === "email" || type === "tel" || type === "url" || type === "time" || type === "datetime-local" || type === "month" || type === "week" || type === "color" ? type : "text";
1996
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1997
+ CraftInput,
1998
+ {
1999
+ id: name,
2000
+ type: inputType,
2001
+ placeholder,
2002
+ tone,
2003
+ className: inputClassName,
2004
+ disabled,
2005
+ ...fieldProps,
2006
+ ...register(name, rules)
2007
+ }
2008
+ );
2009
+ };
2010
+ const showLabel = type !== "checkbox" && type !== "switch";
2011
+ const showDescriptionAbove = type !== "checkbox" && type !== "switch";
2012
+ const showDescriptionBelow = type === "switch";
2013
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: cn("space-y-2", className), "data-nc-theme": tone, children: [
2014
+ showLabel ? labelNode : null,
2015
+ showDescriptionAbove ? descriptionNode : null,
2016
+ renderInput(),
2017
+ showDescriptionBelow ? descriptionNode : null,
2018
+ errorNode
2019
+ ] });
2020
+ }
2021
+
2022
+ // src/components/craft-form-builder.tsx
2023
+ var import_jsx_runtime32 = require("react/jsx-runtime");
2024
+ function defaultValueForField(field) {
2025
+ var _a, _b, _c, _d;
2026
+ if (field.defaultValue !== void 0) return field.defaultValue;
2027
+ switch (field.type) {
2028
+ case "checkbox":
2029
+ case "switch":
2030
+ return false;
2031
+ case "number":
2032
+ case "slider":
2033
+ case "range":
2034
+ return (_a = field.min) != null ? _a : 0;
2035
+ case "multifile":
2036
+ return [];
2037
+ case "file":
2038
+ return null;
2039
+ case "multiselect":
2040
+ return [];
2041
+ case "radio":
2042
+ return (_d = (_c = (_b = field.options) == null ? void 0 : _b[0]) == null ? void 0 : _c.value) != null ? _d : "";
2043
+ default:
2044
+ return "";
2045
+ }
2046
+ }
2047
+ function buildDefaultValues(fields, initialData) {
2048
+ const values = {};
2049
+ fields.forEach((field) => {
2050
+ const initialValue = initialData == null ? void 0 : initialData[field.name];
2051
+ if (initialValue !== void 0 && initialValue !== null) {
2052
+ values[field.name] = initialValue;
2053
+ } else {
2054
+ values[field.name] = defaultValueForField(field);
2055
+ }
2056
+ });
2057
+ return values;
2058
+ }
2059
+ function buildRules(field, getValues) {
2060
+ var _a;
2061
+ const rules = { ...field.rules };
2062
+ const mergeValidate = (current, next) => {
2063
+ if (!current) return next;
2064
+ if (typeof current === "function") {
2065
+ return (value) => {
2066
+ const result = current(
2067
+ value,
2068
+ getValues()
2069
+ );
2070
+ if (result !== true) return result;
2071
+ return next(value);
2072
+ };
2073
+ }
2074
+ if (typeof current === "object") {
2075
+ return (value) => {
2076
+ const entries = Object.entries(current);
2077
+ for (const [, validator] of entries) {
2078
+ const result = validator(
2079
+ value,
2080
+ getValues()
2081
+ );
2082
+ if (result !== true) return result;
2083
+ }
2084
+ return next(value);
2085
+ };
2086
+ }
2087
+ return next;
2088
+ };
2089
+ if (field.required && field.type !== "hidden") {
2090
+ if (field.type === "checkbox" || field.type === "switch") {
2091
+ rules.validate = mergeValidate(
2092
+ rules.validate,
2093
+ (value) => {
2094
+ var _a2;
2095
+ return value ? true : `${String((_a2 = field.label) != null ? _a2 : field.name)} is required`;
2096
+ }
2097
+ );
2098
+ } else if (field.type === "multiselect") {
2099
+ rules.validate = mergeValidate(
2100
+ rules.validate,
2101
+ (value) => {
2102
+ var _a2;
2103
+ return Array.isArray(value) && value.length > 0 ? true : `${String((_a2 = field.label) != null ? _a2 : field.name)} is required`;
2104
+ }
2105
+ );
2106
+ } else if (field.type === "file") {
2107
+ rules.validate = mergeValidate(
2108
+ rules.validate,
2109
+ (value) => {
2110
+ var _a2;
2111
+ return value instanceof FileList && value.length > 0 ? true : `${String((_a2 = field.label) != null ? _a2 : field.name)} is required`;
2112
+ }
2113
+ );
2114
+ } else if (field.type === "multifile") {
2115
+ rules.validate = mergeValidate(
2116
+ rules.validate,
2117
+ (value) => {
2118
+ var _a2;
2119
+ return Array.isArray(value) && value.length > 0 ? true : `${String((_a2 = field.label) != null ? _a2 : field.name)} is required`;
2120
+ }
2121
+ );
2122
+ } else {
2123
+ rules.required = `${String((_a = field.label) != null ? _a : field.name)} is required`;
2124
+ }
2125
+ }
2126
+ if (field.min !== void 0) {
2127
+ rules.min = { value: field.min, message: `Min ${field.min}` };
2128
+ }
2129
+ if (field.max !== void 0) {
2130
+ rules.max = { value: field.max, message: `Max ${field.max}` };
2131
+ }
2132
+ if (field.type === "email") {
2133
+ rules.pattern = {
2134
+ value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
2135
+ message: "Please enter a valid email address"
2136
+ };
2137
+ }
2138
+ if (field.type === "url") {
2139
+ rules.pattern = {
2140
+ value: /^https?:\/\/.+/,
2141
+ message: "Please enter a valid URL"
2142
+ };
2143
+ }
2144
+ if (field.validate) {
2145
+ rules.validate = mergeValidate(
2146
+ rules.validate,
2147
+ (value) => {
2148
+ var _a2;
2149
+ return (_a2 = field.validate) == null ? void 0 : _a2.call(field, value, getValues());
2150
+ }
2151
+ );
2152
+ }
2153
+ return rules;
2154
+ }
2155
+ function CraftFormBuilder({
2156
+ title = "Form",
2157
+ description,
2158
+ fields,
2159
+ initialData = null,
2160
+ open,
2161
+ defaultOpen = false,
2162
+ onOpenChange,
2163
+ trigger,
2164
+ submitLabel = "Submit",
2165
+ cancelLabel = "Cancel",
2166
+ resetLabel = "Reset",
2167
+ showReset = true,
2168
+ showCancel = true,
2169
+ tone,
2170
+ className,
2171
+ formClassName,
2172
+ loading = false,
2173
+ disableSubmitWhenInvalid = true,
2174
+ closeOnSubmit = true,
2175
+ closeOnCancel = true,
2176
+ onSubmit,
2177
+ onReset,
2178
+ onCancel,
2179
+ customValidation
2180
+ }) {
2181
+ const [uncontrolledOpen, setUncontrolledOpen] = React19.useState(defaultOpen);
2182
+ const isControlled = typeof open === "boolean";
2183
+ const isOpen = isControlled ? open : uncontrolledOpen;
2184
+ const setOpen = React19.useCallback(
2185
+ (next) => {
2186
+ if (!isControlled) setUncontrolledOpen(next);
2187
+ onOpenChange == null ? void 0 : onOpenChange(next);
2188
+ },
2189
+ [isControlled, onOpenChange]
2190
+ );
2191
+ const defaultValues = React19.useMemo(
2192
+ () => buildDefaultValues(fields, initialData),
2193
+ [fields, initialData]
2194
+ );
2195
+ const form = (0, import_react_hook_form4.useForm)({
2196
+ mode: "onChange",
2197
+ defaultValues
2198
+ });
2199
+ const formId = React19.useId();
2200
+ React19.useEffect(() => {
2201
+ form.reset(defaultValues);
2202
+ }, [defaultValues, form]);
2203
+ const handleSubmit = form.handleSubmit(async (values) => {
2204
+ if (customValidation) {
2205
+ const customErrors = customValidation(values);
2206
+ if (customErrors && Object.keys(customErrors).length > 0) {
2207
+ Object.entries(customErrors).forEach(([key, message]) => {
2208
+ if (message) {
2209
+ form.setError(key, {
2210
+ type: "custom",
2211
+ message: String(message)
2212
+ });
2213
+ }
2214
+ });
2215
+ return;
2216
+ }
2217
+ }
2218
+ await onSubmit(values);
2219
+ if (closeOnSubmit) setOpen(false);
2220
+ });
2221
+ const handleReset = () => {
2222
+ form.reset(defaultValues);
2223
+ onReset == null ? void 0 : onReset();
2224
+ };
2225
+ const handleCancel = () => {
2226
+ onCancel == null ? void 0 : onCancel();
2227
+ if (closeOnCancel) setOpen(false);
2228
+ };
2229
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react_hook_form4.FormProvider, { ...form, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2230
+ CraftModal,
2231
+ {
2232
+ open: isOpen,
2233
+ onOpenChange: setOpen,
2234
+ trigger,
2235
+ title,
2236
+ description,
2237
+ tone,
2238
+ className,
2239
+ footer: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-wrap items-center justify-end gap-3", children: [
2240
+ showReset && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2241
+ CraftButton,
2242
+ {
2243
+ type: "button",
2244
+ variant: "outline",
2245
+ onClick: handleReset,
2246
+ disabled: loading,
2247
+ children: resetLabel
2248
+ }
2249
+ ),
2250
+ showCancel && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2251
+ CraftButton,
2252
+ {
2253
+ type: "button",
2254
+ variant: "ghost",
2255
+ onClick: handleCancel,
2256
+ disabled: loading,
2257
+ children: cancelLabel
2258
+ }
2259
+ ),
2260
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2261
+ CraftSubmitButton,
2262
+ {
2263
+ loading,
2264
+ disableWhenInvalid: disableSubmitWhenInvalid,
2265
+ form: formId,
2266
+ children: submitLabel
2267
+ }
2268
+ )
2269
+ ] }),
2270
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2271
+ "form",
2272
+ {
2273
+ id: formId,
2274
+ onSubmit: handleSubmit,
2275
+ className: cn("space-y-5", formClassName),
2276
+ children: fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "space-y-2", children: [
2277
+ field.helpText && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-xs text-[rgb(var(--nc-fg-muted))]", children: field.helpText }),
2278
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2279
+ CraftFormField,
2280
+ {
2281
+ name: field.name,
2282
+ label: field.label,
2283
+ description: field.description,
2284
+ type: field.type,
2285
+ placeholder: field.placeholder,
2286
+ options: field.options,
2287
+ tone,
2288
+ disabled: field.disabled || loading,
2289
+ rules: buildRules(field, form.getValues),
2290
+ fieldProps: {
2291
+ min: field.min,
2292
+ max: field.max,
2293
+ step: field.step,
2294
+ rows: field.rows,
2295
+ accept: field.accept,
2296
+ multiple: field.type === "multifile",
2297
+ ...field.fieldProps
2298
+ }
2299
+ }
2300
+ )
2301
+ ] }, field.name))
2302
+ }
2303
+ )
2304
+ }
2305
+ ) });
2306
+ }
2307
+
2308
+ // src/components/craft-confirm-dialog.tsx
2309
+ var React20 = __toESM(require("react"), 1);
2310
+ var import_jsx_runtime33 = require("react/jsx-runtime");
2311
+ function CraftConfirmDialog({
2312
+ open,
2313
+ defaultOpen = false,
2314
+ onOpenChange,
2315
+ tone,
2316
+ title = "Confirm action",
2317
+ description,
2318
+ confirmLabel = "Confirm",
2319
+ cancelLabel = "Cancel",
2320
+ onConfirm,
2321
+ trigger,
2322
+ className,
2323
+ confirmVariant = "solid"
2324
+ }) {
2325
+ const [uncontrolledOpen, setUncontrolledOpen] = React20.useState(defaultOpen);
2326
+ const isControlled = typeof open === "boolean";
2327
+ const isOpen = isControlled ? open : uncontrolledOpen;
2328
+ const setOpen = React20.useCallback(
2329
+ (next) => {
2330
+ if (!isControlled) setUncontrolledOpen(next);
2331
+ onOpenChange == null ? void 0 : onOpenChange(next);
2332
+ },
2333
+ [isControlled, onOpenChange]
2334
+ );
2335
+ const [isLoading, setIsLoading] = React20.useState(false);
2336
+ const handleConfirm = async () => {
2337
+ if (!onConfirm) {
2338
+ setOpen(false);
2339
+ return;
2340
+ }
2341
+ setIsLoading(true);
2342
+ await onConfirm();
2343
+ setIsLoading(false);
2344
+ setOpen(false);
2345
+ };
2346
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2347
+ CraftModal,
2348
+ {
2349
+ open: isOpen,
2350
+ onOpenChange: setOpen,
2351
+ trigger,
2352
+ title,
2353
+ description,
2354
+ tone,
2355
+ className: cn("max-w-md", className),
2356
+ footer: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-wrap items-center justify-end gap-3", children: [
2357
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2358
+ CraftButton,
2359
+ {
2360
+ type: "button",
2361
+ variant: "ghost",
2362
+ onClick: () => setOpen(false),
2363
+ children: cancelLabel
2364
+ }
2365
+ ),
2366
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2367
+ CraftButton,
2368
+ {
2369
+ type: "button",
2370
+ variant: confirmVariant,
2371
+ disabled: isLoading,
2372
+ onClick: handleConfirm,
2373
+ children: isLoading ? "Working..." : confirmLabel
2374
+ }
2375
+ )
2376
+ ] }),
2377
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: description })
2378
+ }
2379
+ );
2380
+ }
2381
+
2382
+ // src/components/craft-create-edit-drawer.tsx
2383
+ var React21 = __toESM(require("react"), 1);
2384
+ var import_react_hook_form5 = require("react-hook-form");
2385
+ var import_jsx_runtime34 = require("react/jsx-runtime");
2386
+ function CraftCreateEditDrawer({
2387
+ mode = "create",
2388
+ form,
2389
+ onSubmit,
2390
+ open,
2391
+ defaultOpen = false,
2392
+ onOpenChange,
2393
+ trigger,
2394
+ title,
2395
+ description,
2396
+ submitLabel,
2397
+ cancelLabel = "Cancel",
2398
+ tone,
2399
+ className,
2400
+ children,
2401
+ footer,
2402
+ disableSubmitWhenInvalid = true,
2403
+ closeOnSubmit = true,
2404
+ side = "right"
2405
+ }) {
2406
+ const [uncontrolledOpen, setUncontrolledOpen] = React21.useState(defaultOpen);
2407
+ const isControlled = typeof open === "boolean";
2408
+ const isOpen = isControlled ? open : uncontrolledOpen;
2409
+ const setOpen = React21.useCallback(
2410
+ (next) => {
2411
+ if (!isControlled) setUncontrolledOpen(next);
2412
+ onOpenChange == null ? void 0 : onOpenChange(next);
2413
+ },
2414
+ [isControlled, onOpenChange]
2415
+ );
2416
+ const formId = React21.useId();
2417
+ const handleSubmit = form.handleSubmit(async (values) => {
2418
+ await onSubmit(values);
2419
+ if (closeOnSubmit) setOpen(false);
2420
+ });
2421
+ const resolvedTitle = title != null ? title : mode === "create" ? "Create item" : "Edit item";
2422
+ const resolvedSubmitLabel = submitLabel != null ? submitLabel : mode === "create" ? "Create" : "Save changes";
2423
+ const footerContent = footer != null ? footer : /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex flex-wrap items-center justify-end gap-3", children: [
2424
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(CraftButton, { type: "button", variant: "ghost", onClick: () => setOpen(false), children: cancelLabel }),
2425
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2426
+ CraftSubmitButton,
2427
+ {
2428
+ form: formId,
2429
+ disableWhenInvalid: disableSubmitWhenInvalid,
2430
+ children: resolvedSubmitLabel
2431
+ }
2432
+ )
2433
+ ] });
2434
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_react_hook_form5.FormProvider, { ...form, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2435
+ CraftDrawer,
2436
+ {
2437
+ open: isOpen,
2438
+ onOpenChange: setOpen,
2439
+ trigger,
2440
+ title: resolvedTitle,
2441
+ tone,
2442
+ side,
2443
+ className: cn("flex flex-col", className),
2444
+ footer: footerContent,
2445
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("form", { id: formId, onSubmit: handleSubmit, className: "space-y-5", children: [
2446
+ description && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: description }),
2447
+ children
2448
+ ] })
2449
+ }
2450
+ ) });
2451
+ }
2452
+
2453
+ // src/components/craft-filter-bar.tsx
2454
+ var import_jsx_runtime35 = require("react/jsx-runtime");
2455
+ function CraftFilterBar({
2456
+ title,
2457
+ description,
2458
+ searchValue,
2459
+ onSearchChange,
2460
+ searchPlaceholder = "Search...",
2461
+ actions,
2462
+ filters,
2463
+ tone,
2464
+ className
2465
+ }) {
2466
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
2467
+ "div",
2468
+ {
2469
+ className: cn(
2470
+ "rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-4 text-[rgb(var(--nc-fg))] shadow-[0_12px_36px_rgba(0,0,0,0.2)] backdrop-blur-2xl",
2471
+ className
2472
+ ),
2473
+ "data-nc-theme": tone,
2474
+ children: [
2475
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [
2476
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
2477
+ title && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h3", { className: "text-lg font-semibold", children: title }),
2478
+ description && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: description })
2479
+ ] }),
2480
+ actions && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "flex items-center gap-3", children: actions })
2481
+ ] }),
2482
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "mt-4 grid gap-4 md:grid-cols-[minmax(0,1fr)_auto]", children: [
2483
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
2484
+ CraftInput,
2485
+ {
2486
+ type: "search",
2487
+ placeholder: searchPlaceholder,
2488
+ value: searchValue != null ? searchValue : "",
2489
+ onChange: (event) => onSearchChange == null ? void 0 : onSearchChange(event.target.value),
2490
+ tone
2491
+ }
2492
+ ),
2493
+ filters && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "flex flex-wrap items-center gap-3", children: filters })
2494
+ ] })
2495
+ ]
2496
+ }
2497
+ );
2498
+ }
2499
+
2500
+ // src/components/craft-table-toolbar.tsx
2501
+ var import_jsx_runtime36 = require("react/jsx-runtime");
2502
+ function CraftTableToolbar({
2503
+ title,
2504
+ description,
2505
+ searchValue,
2506
+ onSearchChange,
2507
+ searchPlaceholder = "Search table...",
2508
+ actions,
2509
+ filters,
2510
+ bulkActions,
2511
+ tone,
2512
+ className
2513
+ }) {
2514
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
2515
+ "div",
2516
+ {
2517
+ className: cn(
2518
+ "rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-4 text-[rgb(var(--nc-fg))] shadow-[0_12px_36px_rgba(0,0,0,0.2)] backdrop-blur-2xl",
2519
+ className
2520
+ ),
2521
+ "data-nc-theme": tone,
2522
+ children: [
2523
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [
2524
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { children: [
2525
+ title && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h3", { className: "text-lg font-semibold", children: title }),
2526
+ description && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: description })
2527
+ ] }),
2528
+ actions && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex items-center gap-3", children: actions })
2529
+ ] }),
2530
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "mt-4 grid gap-4 lg:grid-cols-[minmax(0,1fr)_auto]", children: [
2531
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2532
+ CraftInput,
2533
+ {
2534
+ type: "search",
2535
+ placeholder: searchPlaceholder,
2536
+ value: searchValue != null ? searchValue : "",
2537
+ onChange: (event) => onSearchChange == null ? void 0 : onSearchChange(event.target.value),
2538
+ tone
2539
+ }
2540
+ ),
2541
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
2542
+ filters,
2543
+ bulkActions
2544
+ ] })
2545
+ ] })
2546
+ ]
2547
+ }
2548
+ );
2549
+ }
2550
+
2551
+ // src/components/craft-data-table.tsx
2552
+ var React22 = __toESM(require("react"), 1);
2553
+
2554
+ // src/components/craft-pagination.tsx
2555
+ var import_jsx_runtime37 = require("react/jsx-runtime");
2556
+ function getPageNumbers(pageIndex, pageCount, maxButtons = 5) {
2557
+ if (pageCount <= maxButtons) {
2558
+ return Array.from({ length: pageCount }, (_, i) => i);
2559
+ }
2560
+ const pages = [];
2561
+ const start = Math.max(0, pageIndex - 1);
2562
+ const end = Math.min(pageCount - 1, pageIndex + 1);
2563
+ pages.push(0);
2564
+ if (start > 1) pages.push("ellipsis");
2565
+ for (let i = start; i <= end; i += 1) {
2566
+ if (i !== 0 && i !== pageCount - 1) pages.push(i);
2567
+ }
2568
+ if (end < pageCount - 2) pages.push("ellipsis");
2569
+ pages.push(pageCount - 1);
2570
+ return pages;
2571
+ }
2572
+ function CraftPagination({
2573
+ pageIndex,
2574
+ pageCount,
2575
+ onPageChange,
2576
+ canPrevious = pageIndex > 0,
2577
+ canNext = pageIndex < pageCount - 1,
2578
+ pageSize,
2579
+ pageSizeOptions = [10, 20, 50],
2580
+ onPageSizeChange,
2581
+ tone,
2582
+ className
2583
+ }) {
2584
+ const pages = getPageNumbers(pageIndex, pageCount);
2585
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
2586
+ "div",
2587
+ {
2588
+ className: cn(
2589
+ "flex flex-wrap items-center justify-between gap-4",
2590
+ className
2591
+ ),
2592
+ "data-nc-theme": tone,
2593
+ children: [
2594
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center gap-2", children: [
2595
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2596
+ "button",
2597
+ {
2598
+ type: "button",
2599
+ className: cn(
2600
+ "rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-2 text-xs text-[rgb(var(--nc-fg))] transition",
2601
+ "hover:bg-[rgb(var(--nc-surface)/0.2)]",
2602
+ !canPrevious && "opacity-50 cursor-not-allowed"
2603
+ ),
2604
+ onClick: () => onPageChange(Math.max(pageIndex - 1, 0)),
2605
+ disabled: !canPrevious,
2606
+ children: "Prev"
2607
+ }
2608
+ ),
2609
+ pages.map(
2610
+ (page, index) => page === "ellipsis" ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "px-2 text-[rgb(var(--nc-fg-muted))]", children: "..." }, `ellipsis-${index}`) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1026
2611
  "button",
1027
2612
  {
1028
2613
  type: "button",
1029
- onClick: () => handleDaySelect(date),
1030
- disabled,
1031
2614
  className: cn(
1032
- "rounded-lg py-2 text-sm transition-all",
1033
- selected ? "bg-[rgb(var(--nc-accent-1)/0.3)] text-[rgb(var(--nc-fg))]" : "text-[rgb(var(--nc-fg-muted))] hover:bg-[rgb(var(--nc-surface)/0.12)]",
1034
- disabled && "opacity-40 hover:bg-transparent"
2615
+ "rounded-xl border px-3 py-2 text-xs transition",
2616
+ page === pageIndex ? "border-[rgb(var(--nc-accent-1)/0.6)] bg-[rgb(var(--nc-accent-1)/0.2)] text-[rgb(var(--nc-fg))]" : "border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] text-[rgb(var(--nc-fg-muted))] hover:text-[rgb(var(--nc-fg))] hover:bg-[rgb(var(--nc-surface)/0.2)]"
1035
2617
  ),
1036
- children: date.getDate()
2618
+ onClick: () => onPageChange(page),
2619
+ children: page + 1
1037
2620
  },
1038
- date.toISOString()
1039
- );
1040
- }) })
1041
- ]
1042
- }
1043
- )
1044
- ] });
2621
+ page
2622
+ )
2623
+ ),
2624
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2625
+ "button",
2626
+ {
2627
+ type: "button",
2628
+ className: cn(
2629
+ "rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-2 text-xs text-[rgb(var(--nc-fg))] transition",
2630
+ "hover:bg-[rgb(var(--nc-surface)/0.2)]",
2631
+ !canNext && "opacity-50 cursor-not-allowed"
2632
+ ),
2633
+ onClick: () => onPageChange(Math.min(pageIndex + 1, pageCount - 1)),
2634
+ disabled: !canNext,
2635
+ children: "Next"
2636
+ }
2637
+ )
2638
+ ] }),
2639
+ onPageSizeChange && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center gap-2 text-xs text-[rgb(var(--nc-fg-muted))]", children: [
2640
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: "Rows" }),
2641
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2642
+ "select",
2643
+ {
2644
+ className: "rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-2 py-1 text-xs text-[rgb(var(--nc-fg))]",
2645
+ value: pageSize,
2646
+ onChange: (event) => onPageSizeChange(Number(event.target.value)),
2647
+ children: pageSizeOptions.map((size) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("option", { value: size, children: size }, size))
2648
+ }
2649
+ )
2650
+ ] })
2651
+ ]
2652
+ }
2653
+ );
1045
2654
  }
1046
2655
 
1047
- // src/components/craft-number-input.tsx
1048
- var React12 = __toESM(require("react"), 1);
1049
- var import_jsx_runtime18 = require("react/jsx-runtime");
1050
- var CraftNumberInput = React12.forwardRef(({ className, tone, ...props }, ref) => {
1051
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "relative w-full", "data-nc-theme": tone, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1052
- "input",
1053
- {
1054
- ref,
1055
- type: "number",
1056
- className: cn(
1057
- "w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl",
1058
- "shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
1059
- "focus:outline-none focus:ring-4",
1060
- "transition-all duration-300",
1061
- "disabled:opacity-50 disabled:cursor-not-allowed",
1062
- "border-[rgb(var(--nc-border)/0.35)]",
1063
- "focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
1064
- "px-5 py-3 text-base",
1065
- className
1066
- ),
1067
- ...props
2656
+ // src/components/craft-data-table.tsx
2657
+ var import_jsx_runtime38 = require("react/jsx-runtime");
2658
+ function getColumnValue(column, row) {
2659
+ if (typeof column.accessor === "function") return column.accessor(row);
2660
+ const record = row;
2661
+ if (typeof column.accessor === "string") return record[column.accessor];
2662
+ return record[column.id];
2663
+ }
2664
+ function normalizeValue(value) {
2665
+ if (value === null || value === void 0) return "";
2666
+ if (typeof value === "number") return value;
2667
+ if (typeof value === "string") return value.toLowerCase();
2668
+ if (value instanceof Date) return value.getTime();
2669
+ return String(value).toLowerCase();
2670
+ }
2671
+ function CraftDataTable({
2672
+ data,
2673
+ columns,
2674
+ tone,
2675
+ className,
2676
+ loading = false,
2677
+ emptyState,
2678
+ toolbar,
2679
+ enableSorting = true,
2680
+ enableFiltering = true,
2681
+ enableColumnVisibility = true,
2682
+ enableRowSelection = true,
2683
+ enablePagination = true,
2684
+ showGlobalFilter,
2685
+ manualSorting = false,
2686
+ manualFiltering = false,
2687
+ manualPagination = false,
2688
+ sortBy,
2689
+ onSortChange,
2690
+ filters,
2691
+ onFiltersChange,
2692
+ globalFilter,
2693
+ onGlobalFilterChange,
2694
+ columnVisibility,
2695
+ onColumnVisibilityChange,
2696
+ selectedRowIds,
2697
+ onRowSelectionChange,
2698
+ getRowId,
2699
+ pageIndex,
2700
+ pageSize = 10,
2701
+ pageCount,
2702
+ onPageChange,
2703
+ onPageSizeChange
2704
+ }) {
2705
+ const [internalSort, setInternalSort] = React22.useState(null);
2706
+ const [internalFilters, setInternalFilters] = React22.useState({});
2707
+ const [internalGlobalFilter, setInternalGlobalFilter] = React22.useState("");
2708
+ const [internalVisibility, setInternalVisibility] = React22.useState(
2709
+ () => columns.reduce((acc, column) => {
2710
+ acc[column.id] = !column.hidden;
2711
+ return acc;
2712
+ }, {})
2713
+ );
2714
+ const [internalSelection, setInternalSelection] = React22.useState({});
2715
+ const [internalPageIndex, setInternalPageIndex] = React22.useState(0);
2716
+ const [showColumns, setShowColumns] = React22.useState(false);
2717
+ const resolvedSort = sortBy != null ? sortBy : internalSort;
2718
+ const resolvedFilters = filters != null ? filters : internalFilters;
2719
+ const resolvedGlobalFilter = globalFilter != null ? globalFilter : internalGlobalFilter;
2720
+ const resolvedVisibility = columnVisibility != null ? columnVisibility : internalVisibility;
2721
+ const resolvedSelection = selectedRowIds != null ? selectedRowIds : internalSelection;
2722
+ const resolvedPageIndex = pageIndex != null ? pageIndex : internalPageIndex;
2723
+ const setSort = (next) => {
2724
+ if (sortBy === void 0) setInternalSort(next);
2725
+ onSortChange == null ? void 0 : onSortChange(next);
2726
+ };
2727
+ const setFilters = (next) => {
2728
+ if (filters === void 0) setInternalFilters(next);
2729
+ onFiltersChange == null ? void 0 : onFiltersChange(next);
2730
+ };
2731
+ const setVisibility = (next) => {
2732
+ if (columnVisibility === void 0) setInternalVisibility(next);
2733
+ onColumnVisibilityChange == null ? void 0 : onColumnVisibilityChange(next);
2734
+ };
2735
+ const setSelection = (next) => {
2736
+ if (selectedRowIds === void 0) setInternalSelection(next);
2737
+ onRowSelectionChange == null ? void 0 : onRowSelectionChange(next);
2738
+ };
2739
+ const setPageIndex = React22.useCallback(
2740
+ (next) => {
2741
+ if (pageIndex === void 0) setInternalPageIndex(next);
2742
+ onPageChange == null ? void 0 : onPageChange(next);
2743
+ },
2744
+ [pageIndex, onPageChange]
2745
+ );
2746
+ const visibleColumns = columns.filter(
2747
+ (column) => resolvedVisibility[column.id] !== false
2748
+ );
2749
+ const filteredData = React22.useMemo(() => {
2750
+ if (manualFiltering) return data;
2751
+ const globalValue = resolvedGlobalFilter.trim();
2752
+ return data.filter((row) => {
2753
+ if (globalValue) {
2754
+ const matchesGlobal = columns.some((column) => {
2755
+ const value = normalizeValue(getColumnValue(column, row));
2756
+ return String(value).includes(globalValue.toLowerCase());
2757
+ });
2758
+ if (!matchesGlobal) return false;
2759
+ }
2760
+ return Object.entries(resolvedFilters).every(([columnId, value]) => {
2761
+ if (!value) return true;
2762
+ const column = columns.find((col) => col.id === columnId);
2763
+ if (!column) return true;
2764
+ const cellValue = normalizeValue(getColumnValue(column, row));
2765
+ return String(cellValue).includes(value.toLowerCase());
2766
+ });
2767
+ });
2768
+ }, [columns, data, manualFiltering, resolvedFilters, resolvedGlobalFilter]);
2769
+ const sortedData = React22.useMemo(() => {
2770
+ if (manualSorting || !resolvedSort) return filteredData;
2771
+ const column = columns.find((col) => col.id === resolvedSort.id);
2772
+ if (!column) return filteredData;
2773
+ const sorted = [...filteredData].sort((a, b) => {
2774
+ const valueA = normalizeValue(getColumnValue(column, a));
2775
+ const valueB = normalizeValue(getColumnValue(column, b));
2776
+ if (typeof valueA === "number" && typeof valueB === "number") {
2777
+ return valueA - valueB;
2778
+ }
2779
+ return String(valueA).localeCompare(String(valueB));
2780
+ });
2781
+ return resolvedSort.desc ? sorted.reverse() : sorted;
2782
+ }, [columns, filteredData, manualSorting, resolvedSort]);
2783
+ const resolvedPageCount = manualPagination ? Math.max(pageCount != null ? pageCount : 1, 1) : Math.max(Math.ceil(sortedData.length / pageSize), 1);
2784
+ React22.useEffect(() => {
2785
+ if (resolvedPageIndex > resolvedPageCount - 1) {
2786
+ setPageIndex(Math.max(resolvedPageCount - 1, 0));
1068
2787
  }
1069
- ) });
1070
- });
1071
- CraftNumberInput.displayName = "CraftNumberInput";
1072
-
1073
- // src/components/craft-currency-input.tsx
1074
- var React13 = __toESM(require("react"), 1);
1075
- var import_jsx_runtime19 = require("react/jsx-runtime");
1076
- var CraftCurrencyInput = React13.forwardRef(({ className, tone, currencySymbol = "$", ...props }, ref) => {
1077
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "relative w-full", "data-nc-theme": tone, children: [
1078
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "pointer-events-none absolute left-4 top-1/2 -translate-y-1/2 text-[rgb(var(--nc-fg-soft))]", children: currencySymbol }),
1079
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1080
- "input",
2788
+ }, [resolvedPageCount, resolvedPageIndex, setPageIndex]);
2789
+ const pagedData = React22.useMemo(() => {
2790
+ if (!enablePagination || manualPagination) return sortedData;
2791
+ const start = resolvedPageIndex * pageSize;
2792
+ return sortedData.slice(start, start + pageSize);
2793
+ }, [enablePagination, manualPagination, pageSize, resolvedPageIndex, sortedData]);
2794
+ const rowIdFor = React22.useCallback(
2795
+ (row, index) => {
2796
+ var _a;
2797
+ return (_a = getRowId == null ? void 0 : getRowId(row, index)) != null ? _a : String(index);
2798
+ },
2799
+ [getRowId]
2800
+ );
2801
+ const pageStartIndex = enablePagination && !manualPagination ? resolvedPageIndex * pageSize : 0;
2802
+ const pageRowIds = pagedData.map(
2803
+ (row, index) => rowIdFor(row, pageStartIndex + index)
2804
+ );
2805
+ const allSelected = pageRowIds.length > 0 && pageRowIds.every((id) => resolvedSelection[id]);
2806
+ const someSelected = pageRowIds.some((id) => resolvedSelection[id]);
2807
+ const headerCheckboxRef = React22.useRef(null);
2808
+ React22.useEffect(() => {
2809
+ if (headerCheckboxRef.current) {
2810
+ headerCheckboxRef.current.indeterminate = someSelected && !allSelected;
2811
+ }
2812
+ }, [someSelected, allSelected]);
2813
+ const toggleSort = (column) => {
2814
+ if (!enableSorting || column.sortable === false) return;
2815
+ const current = resolvedSort;
2816
+ if (!current || current.id !== column.id) {
2817
+ setSort({ id: column.id, desc: false });
2818
+ return;
2819
+ }
2820
+ if (!current.desc) {
2821
+ setSort({ id: column.id, desc: true });
2822
+ return;
2823
+ }
2824
+ setSort(null);
2825
+ };
2826
+ const emptyContent = emptyState != null ? emptyState : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "text-center text-sm text-[rgb(var(--nc-fg-muted))]", children: "No results found." });
2827
+ const resolvedShowGlobalFilter = showGlobalFilter != null ? showGlobalFilter : enableFiltering && !toolbar;
2828
+ const setGlobalFilter = (next) => {
2829
+ if (globalFilter === void 0) setInternalGlobalFilter(next);
2830
+ onGlobalFilterChange == null ? void 0 : onGlobalFilterChange(next);
2831
+ };
2832
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: cn("space-y-4", className), "data-nc-theme": tone, children: [
2833
+ toolbar,
2834
+ resolvedShowGlobalFilter && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center justify-between gap-3 rounded-2xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-2 text-sm text-[rgb(var(--nc-fg))]", children: [
2835
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xs text-[rgb(var(--nc-fg-muted))]", children: "Global filter" }),
2836
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2837
+ "input",
2838
+ {
2839
+ type: "search",
2840
+ value: resolvedGlobalFilter,
2841
+ onChange: (event) => setGlobalFilter(event.target.value),
2842
+ placeholder: "Search all columns...",
2843
+ className: "w-full max-w-xs rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.18)] px-3 py-2 text-xs text-[rgb(var(--nc-fg))]"
2844
+ }
2845
+ )
2846
+ ] }),
2847
+ enableColumnVisibility && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "relative flex justify-end", children: [
2848
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2849
+ "button",
2850
+ {
2851
+ type: "button",
2852
+ className: "rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-2 text-xs text-[rgb(var(--nc-fg))] transition hover:bg-[rgb(var(--nc-surface)/0.2)]",
2853
+ onClick: () => setShowColumns((prev) => !prev),
2854
+ children: "Columns"
2855
+ }
2856
+ ),
2857
+ showColumns && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "absolute right-0 top-10 z-20 w-48 rounded-2xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.2)] p-3 shadow-[0_12px_30px_rgba(0,0,0,0.35)] backdrop-blur-2xl", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "grid gap-2", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2858
+ "label",
2859
+ {
2860
+ className: "flex items-center gap-2 text-xs text-[rgb(var(--nc-fg))]",
2861
+ children: [
2862
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2863
+ "input",
2864
+ {
2865
+ type: "checkbox",
2866
+ className: "h-4 w-4 accent-[rgb(var(--nc-accent-1))]",
2867
+ checked: resolvedVisibility[column.id] !== false,
2868
+ onChange: (event) => setVisibility({
2869
+ ...resolvedVisibility,
2870
+ [column.id]: event.target.checked
2871
+ })
2872
+ }
2873
+ ),
2874
+ column.header
2875
+ ]
2876
+ },
2877
+ column.id
2878
+ )) }) })
2879
+ ] }),
2880
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "overflow-hidden rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] shadow-[0_18px_50px_rgba(0,0,0,0.35)] backdrop-blur-2xl", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("table", { className: "w-full border-collapse text-left text-sm", children: [
2881
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("thead", { className: "bg-[rgb(var(--nc-surface)/0.12)] text-[rgb(var(--nc-fg-muted))]", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("tr", { children: [
2882
+ enableRowSelection && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("th", { className: "w-12 px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2883
+ "input",
2884
+ {
2885
+ ref: headerCheckboxRef,
2886
+ type: "checkbox",
2887
+ className: "h-4 w-4 accent-[rgb(var(--nc-accent-1))]",
2888
+ checked: allSelected,
2889
+ onChange: (event) => {
2890
+ const next = { ...resolvedSelection };
2891
+ pageRowIds.forEach((id) => {
2892
+ next[id] = event.target.checked;
2893
+ });
2894
+ setSelection(next);
2895
+ }
2896
+ }
2897
+ ) }),
2898
+ visibleColumns.map((column) => {
2899
+ var _a;
2900
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2901
+ "th",
2902
+ {
2903
+ className: cn(
2904
+ "px-4 py-3 text-xs font-semibold uppercase tracking-[0.2em]",
2905
+ column.headerClassName
2906
+ ),
2907
+ style: { width: column.width },
2908
+ children: [
2909
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2910
+ "button",
2911
+ {
2912
+ type: "button",
2913
+ className: cn(
2914
+ "flex items-center gap-2",
2915
+ enableSorting && column.sortable !== false ? "cursor-pointer" : "cursor-default"
2916
+ ),
2917
+ onClick: () => toggleSort(column),
2918
+ children: [
2919
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { children: column.header }),
2920
+ (resolvedSort == null ? void 0 : resolvedSort.id) === column.id && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-[rgb(var(--nc-accent-1))]", children: resolvedSort.desc ? "\u2193" : "\u2191" })
2921
+ ]
2922
+ }
2923
+ ),
2924
+ enableFiltering && column.filterable !== false && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2925
+ "input",
2926
+ {
2927
+ type: "text",
2928
+ value: (_a = resolvedFilters[column.id]) != null ? _a : "",
2929
+ onChange: (event) => setFilters({
2930
+ ...resolvedFilters,
2931
+ [column.id]: event.target.value
2932
+ }),
2933
+ placeholder: "Filter",
2934
+ className: "mt-2 w-full rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.18)] px-2 py-1 text-xs text-[rgb(var(--nc-fg))]"
2935
+ }
2936
+ )
2937
+ ]
2938
+ },
2939
+ column.id
2940
+ );
2941
+ })
2942
+ ] }) }),
2943
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("tbody", { className: "text-[rgb(var(--nc-fg))]", children: [
2944
+ loading && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2945
+ "td",
2946
+ {
2947
+ colSpan: visibleColumns.length + (enableRowSelection ? 1 : 0),
2948
+ className: "px-4 py-10 text-center text-sm text-[rgb(var(--nc-fg-muted))]",
2949
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "inline-flex items-center gap-2", children: [
2950
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-[rgb(var(--nc-fg-muted))] border-t-transparent" }),
2951
+ "Loading data..."
2952
+ ] })
2953
+ }
2954
+ ) }),
2955
+ !loading && pagedData.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2956
+ "td",
2957
+ {
2958
+ colSpan: visibleColumns.length + (enableRowSelection ? 1 : 0),
2959
+ className: "px-4 py-10",
2960
+ children: emptyContent
2961
+ }
2962
+ ) }),
2963
+ !loading && pagedData.map((row, rowIndex) => {
2964
+ const rowId = rowIdFor(row, pageStartIndex + rowIndex);
2965
+ const isSelected = resolvedSelection[rowId];
2966
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2967
+ "tr",
2968
+ {
2969
+ className: cn(
2970
+ "border-t border-[rgb(var(--nc-border)/0.15)]",
2971
+ isSelected && "bg-[rgb(var(--nc-accent-1)/0.08)]"
2972
+ ),
2973
+ children: [
2974
+ enableRowSelection && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("td", { className: "px-4 py-4", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2975
+ "input",
2976
+ {
2977
+ type: "checkbox",
2978
+ className: "h-4 w-4 accent-[rgb(var(--nc-accent-1))]",
2979
+ checked: isSelected,
2980
+ onChange: (event) => setSelection({
2981
+ ...resolvedSelection,
2982
+ [rowId]: event.target.checked
2983
+ })
2984
+ }
2985
+ ) }),
2986
+ visibleColumns.map((column) => {
2987
+ var _a;
2988
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2989
+ "td",
2990
+ {
2991
+ className: cn(
2992
+ "px-4 py-4",
2993
+ column.align === "center" && "text-center",
2994
+ column.align === "right" && "text-right",
2995
+ column.cellClassName
2996
+ ),
2997
+ children: column.cell ? column.cell(row) : String((_a = getColumnValue(column, row)) != null ? _a : "")
2998
+ },
2999
+ column.id
3000
+ );
3001
+ })
3002
+ ]
3003
+ },
3004
+ rowId
3005
+ );
3006
+ })
3007
+ ] })
3008
+ ] }) }),
3009
+ enablePagination && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3010
+ CraftPagination,
1081
3011
  {
1082
- ref,
1083
- type: "text",
1084
- inputMode: "decimal",
1085
- className: cn(
1086
- "w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl",
1087
- "shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)]",
1088
- "focus:outline-none focus:ring-4",
1089
- "transition-all duration-300",
1090
- "disabled:opacity-50 disabled:cursor-not-allowed",
1091
- "border-[rgb(var(--nc-border)/0.35)]",
1092
- "focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)]",
1093
- "placeholder:text-[rgb(var(--nc-fg-soft))]",
1094
- "px-5 py-3 pl-9 text-base",
1095
- className
1096
- ),
1097
- ...props
3012
+ pageIndex: resolvedPageIndex,
3013
+ pageCount: resolvedPageCount,
3014
+ onPageChange: setPageIndex,
3015
+ pageSize,
3016
+ onPageSizeChange,
3017
+ tone
1098
3018
  }
1099
3019
  )
1100
3020
  ] });
1101
- });
1102
- CraftCurrencyInput.displayName = "CraftCurrencyInput";
3021
+ }
1103
3022
 
1104
3023
  // src/components/layout/app-shell.tsx
1105
- var import_jsx_runtime20 = require("react/jsx-runtime");
3024
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1106
3025
  function AppShell({ className, sidebar, topNav, children, ...props }) {
1107
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3026
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
1108
3027
  "div",
1109
3028
  {
1110
3029
  className: cn(
@@ -1113,20 +3032,35 @@ function AppShell({ className, sidebar, topNav, children, ...props }) {
1113
3032
  ),
1114
3033
  ...props,
1115
3034
  children: [
1116
- sidebar && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "h-full", children: sidebar }),
1117
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-6", children: [
1118
- topNav,
1119
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("main", { className: "flex-1", children })
3035
+ sidebar && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "h-full lg:sticky lg:top-6 lg:self-start lg:max-h-[calc(100vh-3rem)] lg:overflow-y-auto", children: sidebar }),
3036
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-col gap-6", children: [
3037
+ topNav && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "lg:sticky lg:top-6 lg:z-20", children: topNav }),
3038
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("main", { className: "flex-1", children })
1120
3039
  ] })
1121
3040
  ]
1122
3041
  }
1123
3042
  );
1124
3043
  }
1125
3044
 
3045
+ // src/components/layout/app-template.tsx
3046
+ var React23 = __toESM(require("react"), 1);
3047
+
3048
+ // src/components/layout/breadcrumbs.tsx
3049
+ var import_jsx_runtime40 = require("react/jsx-runtime");
3050
+ function Breadcrumbs({ className, items, ...props }) {
3051
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("nav", { className: cn("flex items-center text-sm text-[rgb(var(--nc-fg-muted))]", className), ...props, children: items.map((item, index) => {
3052
+ const content = item.href ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("a", { href: item.href, className: "transition hover:text-[rgb(var(--nc-fg))]", children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-[rgb(var(--nc-fg))]", children: item.label });
3053
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "flex items-center", children: [
3054
+ content,
3055
+ index < items.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "mx-2 text-[rgb(var(--nc-fg-soft))]", children: "/" })
3056
+ ] }, `${item.label}-${index}`);
3057
+ }) });
3058
+ }
3059
+
1126
3060
  // src/components/layout/sidebar.tsx
1127
- var import_jsx_runtime21 = require("react/jsx-runtime");
3061
+ var import_jsx_runtime41 = require("react/jsx-runtime");
1128
3062
  function Sidebar({ className, title, items, footer, ...props }) {
1129
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
3063
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
1130
3064
  "aside",
1131
3065
  {
1132
3066
  className: cn(
@@ -1135,10 +3069,10 @@ function Sidebar({ className, title, items, footer, ...props }) {
1135
3069
  ),
1136
3070
  ...props,
1137
3071
  children: [
1138
- title && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "text-lg font-semibold", children: title }),
1139
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("nav", { className: "flex flex-col gap-2", children: items.map((item, index) => {
3072
+ title && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "text-lg font-semibold", children: title }),
3073
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("nav", { className: "flex flex-col gap-2", children: items.map((item, index) => {
1140
3074
  var _a;
1141
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
3075
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
1142
3076
  "a",
1143
3077
  {
1144
3078
  href: (_a = item.href) != null ? _a : "#",
@@ -1148,22 +3082,22 @@ function Sidebar({ className, title, items, footer, ...props }) {
1148
3082
  ),
1149
3083
  children: [
1150
3084
  item.icon,
1151
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: item.label })
3085
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: item.label })
1152
3086
  ]
1153
3087
  },
1154
3088
  `${item.label}-${index}`
1155
3089
  );
1156
3090
  }) }),
1157
- footer && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-auto pt-4", children: footer })
3091
+ footer && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "mt-auto pt-4", children: footer })
1158
3092
  ]
1159
3093
  }
1160
3094
  );
1161
3095
  }
1162
3096
 
1163
3097
  // src/components/layout/top-nav.tsx
1164
- var import_jsx_runtime22 = require("react/jsx-runtime");
3098
+ var import_jsx_runtime42 = require("react/jsx-runtime");
1165
3099
  function TopNav({ className, title, actions, breadcrumb, ...props }) {
1166
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
3100
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
1167
3101
  "header",
1168
3102
  {
1169
3103
  className: cn(
@@ -1172,18 +3106,131 @@ function TopNav({ className, title, actions, breadcrumb, ...props }) {
1172
3106
  ),
1173
3107
  ...props,
1174
3108
  children: [
1175
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-1", children: [
3109
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-1", children: [
1176
3110
  breadcrumb,
1177
- title && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "text-xl font-semibold", children: title })
3111
+ title && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "text-xl font-semibold", children: title })
1178
3112
  ] }),
1179
- actions && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
3113
+ actions && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
1180
3114
  ]
1181
3115
  }
1182
3116
  );
1183
3117
  }
1184
3118
 
3119
+ // src/components/layout/app-template.tsx
3120
+ var import_jsx_runtime43 = require("react/jsx-runtime");
3121
+ function AppTemplate({
3122
+ config,
3123
+ headerActions,
3124
+ headerBreadcrumb,
3125
+ sidebarFooter,
3126
+ resolveIcon,
3127
+ icons,
3128
+ activePath,
3129
+ getActivePath,
3130
+ lucideFallback = true,
3131
+ children
3132
+ }) {
3133
+ const sidebarConfig = config.sidebar;
3134
+ const headerConfig = config.header;
3135
+ const resolvedActivePath = activePath != null ? activePath : getActivePath == null ? void 0 : getActivePath();
3136
+ const buildIcon = React23.useCallback(
3137
+ (name) => {
3138
+ if (!name) return void 0;
3139
+ if (resolveIcon) return resolveIcon(name);
3140
+ if (icons == null ? void 0 : icons[name]) return icons[name];
3141
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(CraftIcon, { name, useLucide: lucideFallback });
3142
+ },
3143
+ [icons, lucideFallback, resolveIcon]
3144
+ );
3145
+ const sidebarItems = sidebarConfig ? sidebarConfig.items.map((item) => {
3146
+ var _a;
3147
+ return {
3148
+ label: item.label,
3149
+ href: item.href,
3150
+ active: (_a = item.active) != null ? _a : resolvedActivePath && item.href ? item.href === resolvedActivePath : false,
3151
+ icon: buildIcon(item.icon)
3152
+ };
3153
+ }) : null;
3154
+ const breadcrumbNode = headerBreadcrumb != null ? headerBreadcrumb : (headerConfig == null ? void 0 : headerConfig.breadcrumb) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Breadcrumbs, { items: headerConfig.breadcrumb }) : null;
3155
+ const sidebarFooterNode = sidebarFooter != null ? sidebarFooter : (sidebarConfig == null ? void 0 : sidebarConfig.footerText) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "text-xs text-[rgb(var(--nc-fg-muted))]", children: sidebarConfig.footerText }) : null;
3156
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3157
+ AppShell,
3158
+ {
3159
+ sidebar: sidebarConfig && sidebarItems ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3160
+ Sidebar,
3161
+ {
3162
+ title: sidebarConfig.title,
3163
+ items: sidebarItems,
3164
+ footer: sidebarFooterNode
3165
+ }
3166
+ ) : void 0,
3167
+ topNav: headerConfig ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3168
+ TopNav,
3169
+ {
3170
+ title: headerConfig.title,
3171
+ breadcrumb: breadcrumbNode,
3172
+ actions: headerActions
3173
+ }
3174
+ ) : void 0,
3175
+ children
3176
+ }
3177
+ );
3178
+ }
3179
+
3180
+ // src/components/layout/layout-config.ts
3181
+ var layoutConfigSchema = {
3182
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3183
+ title: "Nextcraft UI Layout Config",
3184
+ type: "object",
3185
+ additionalProperties: false,
3186
+ properties: {
3187
+ sidebar: {
3188
+ type: "object",
3189
+ additionalProperties: false,
3190
+ properties: {
3191
+ title: { type: "string" },
3192
+ footerText: { type: "string" },
3193
+ items: {
3194
+ type: "array",
3195
+ items: {
3196
+ type: "object",
3197
+ additionalProperties: false,
3198
+ properties: {
3199
+ label: { type: "string" },
3200
+ href: { type: "string" },
3201
+ icon: { type: "string" },
3202
+ active: { type: "boolean" }
3203
+ },
3204
+ required: ["label"]
3205
+ }
3206
+ }
3207
+ },
3208
+ required: ["items"]
3209
+ },
3210
+ header: {
3211
+ type: "object",
3212
+ additionalProperties: false,
3213
+ properties: {
3214
+ title: { type: "string" },
3215
+ breadcrumb: {
3216
+ type: "array",
3217
+ items: {
3218
+ type: "object",
3219
+ additionalProperties: false,
3220
+ properties: {
3221
+ label: { type: "string" },
3222
+ href: { type: "string" }
3223
+ },
3224
+ required: ["label"]
3225
+ }
3226
+ }
3227
+ }
3228
+ }
3229
+ }
3230
+ };
3231
+
1185
3232
  // src/components/layout/page-header.tsx
1186
- var import_jsx_runtime23 = require("react/jsx-runtime");
3233
+ var import_jsx_runtime44 = require("react/jsx-runtime");
1187
3234
  function PageHeader({
1188
3235
  className,
1189
3236
  title,
@@ -1191,36 +3238,24 @@ function PageHeader({
1191
3238
  actions,
1192
3239
  ...props
1193
3240
  }) {
1194
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3241
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
1195
3242
  "div",
1196
3243
  {
1197
3244
  className: cn("flex flex-wrap items-start justify-between gap-6", className),
1198
3245
  ...props,
1199
3246
  children: [
1200
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "space-y-2", children: [
1201
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
1202
- description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
3247
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-2", children: [
3248
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
3249
+ description && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
1203
3250
  ] }),
1204
- actions && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
3251
+ actions && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
1205
3252
  ]
1206
3253
  }
1207
3254
  );
1208
3255
  }
1209
3256
 
1210
- // src/components/layout/breadcrumbs.tsx
1211
- var import_jsx_runtime24 = require("react/jsx-runtime");
1212
- function Breadcrumbs({ className, items, ...props }) {
1213
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("nav", { className: cn("flex items-center text-sm text-[rgb(var(--nc-fg-muted))]", className), ...props, children: items.map((item, index) => {
1214
- const content = item.href ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href: item.href, className: "transition hover:text-[rgb(var(--nc-fg))]", children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-[rgb(var(--nc-fg))]", children: item.label });
1215
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "flex items-center", children: [
1216
- content,
1217
- index < items.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "mx-2 text-[rgb(var(--nc-fg-soft))]", children: "/" })
1218
- ] }, `${item.label}-${index}`);
1219
- }) });
1220
- }
1221
-
1222
3257
  // src/components/layout/auth-layout.tsx
1223
- var import_jsx_runtime25 = require("react/jsx-runtime");
3258
+ var import_jsx_runtime45 = require("react/jsx-runtime");
1224
3259
  function AuthLayout({
1225
3260
  className,
1226
3261
  title,
@@ -1230,7 +3265,7 @@ function AuthLayout({
1230
3265
  children,
1231
3266
  ...props
1232
3267
  }) {
1233
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3268
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
1234
3269
  "div",
1235
3270
  {
1236
3271
  className: cn(
@@ -1240,17 +3275,17 @@ function AuthLayout({
1240
3275
  ),
1241
3276
  ...props,
1242
3277
  children: [
1243
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "flex flex-col justify-center px-6 py-16 sm:px-12", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "mx-auto w-full max-w-md space-y-6", children: [
1244
- (title || description) && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "space-y-2", children: [
1245
- title && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
1246
- description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
3278
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "flex flex-col justify-center px-6 py-16 sm:px-12", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "mx-auto w-full max-w-md space-y-6", children: [
3279
+ (title || description) && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "space-y-2", children: [
3280
+ title && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
3281
+ description && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
1247
3282
  ] }),
1248
3283
  children,
1249
- footer && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: footer })
3284
+ footer && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: footer })
1250
3285
  ] }) }),
1251
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "hidden items-center justify-center border-l border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-12 text-[rgb(var(--nc-fg))] lg:flex", children: graphic != null ? graphic : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "max-w-sm space-y-4 text-center", children: [
1252
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { className: "text-2xl font-semibold", children: "Crafted experiences" }),
1253
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Build authentication flows that feel premium and cohesive." })
3286
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "hidden items-center justify-center border-l border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-12 text-[rgb(var(--nc-fg))] lg:flex", children: graphic != null ? graphic : /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "max-w-sm space-y-4 text-center", children: [
3287
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h2", { className: "text-2xl font-semibold", children: "Crafted experiences" }),
3288
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Build authentication flows that feel premium and cohesive." })
1254
3289
  ] }) })
1255
3290
  ]
1256
3291
  }
@@ -1258,25 +3293,25 @@ function AuthLayout({
1258
3293
  }
1259
3294
 
1260
3295
  // src/components/layout/container.tsx
1261
- var import_jsx_runtime26 = require("react/jsx-runtime");
1262
- var sizeClasses2 = {
3296
+ var import_jsx_runtime46 = require("react/jsx-runtime");
3297
+ var sizeClasses3 = {
1263
3298
  sm: "max-w-3xl",
1264
3299
  md: "max-w-5xl",
1265
3300
  lg: "max-w-6xl",
1266
3301
  xl: "max-w-7xl"
1267
3302
  };
1268
3303
  function Container({ className, size = "lg", ...props }) {
1269
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3304
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
1270
3305
  "div",
1271
3306
  {
1272
- className: cn("mx-auto w-full px-4 sm:px-6 lg:px-8", sizeClasses2[size], className),
3307
+ className: cn("mx-auto w-full px-4 sm:px-6 lg:px-8", sizeClasses3[size], className),
1273
3308
  ...props
1274
3309
  }
1275
3310
  );
1276
3311
  }
1277
3312
 
1278
3313
  // src/components/layout/grid.tsx
1279
- var import_jsx_runtime27 = require("react/jsx-runtime");
3314
+ var import_jsx_runtime47 = require("react/jsx-runtime");
1280
3315
  var colClasses = {
1281
3316
  1: "grid-cols-1",
1282
3317
  2: "grid-cols-1 md:grid-cols-2",
@@ -1292,12 +3327,12 @@ var gapClasses = {
1292
3327
  xl: "gap-10"
1293
3328
  };
1294
3329
  function Grid({ className, columns = 3, gap = "md", ...props }) {
1295
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: cn("grid", colClasses[columns], gapClasses[gap], className), ...props });
3330
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: cn("grid", colClasses[columns], gapClasses[gap], className), ...props });
1296
3331
  }
1297
3332
 
1298
3333
  // src/theme/theme-context.tsx
1299
- var React14 = __toESM(require("react"), 1);
1300
- var import_jsx_runtime28 = require("react/jsx-runtime");
3334
+ var React24 = __toESM(require("react"), 1);
3335
+ var import_jsx_runtime48 = require("react/jsx-runtime");
1301
3336
  var THEME_NAMES = [
1302
3337
  "aurora",
1303
3338
  "ember",
@@ -1305,7 +3340,7 @@ var THEME_NAMES = [
1305
3340
  "midnight",
1306
3341
  "cosmic"
1307
3342
  ];
1308
- var ThemeContext = React14.createContext(null);
3343
+ var ThemeContext = React24.createContext(null);
1309
3344
  var DEFAULT_THEME_KEY = "nextcraft-theme";
1310
3345
  var DEFAULT_MODE_KEY = "nextcraft-mode";
1311
3346
  function ThemeProvider({
@@ -1315,9 +3350,9 @@ function ThemeProvider({
1315
3350
  storageKeyTheme = DEFAULT_THEME_KEY,
1316
3351
  storageKeyMode = DEFAULT_MODE_KEY
1317
3352
  }) {
1318
- const [theme, setTheme] = React14.useState(defaultTheme);
1319
- const [mode, setMode] = React14.useState(defaultMode);
1320
- React14.useEffect(() => {
3353
+ const [theme, setTheme] = React24.useState(defaultTheme);
3354
+ const [mode, setMode] = React24.useState(defaultMode);
3355
+ React24.useEffect(() => {
1321
3356
  if (typeof window === "undefined") return;
1322
3357
  try {
1323
3358
  const storedTheme = window.localStorage.getItem(storageKeyTheme);
@@ -1327,7 +3362,7 @@ function ThemeProvider({
1327
3362
  } catch {
1328
3363
  }
1329
3364
  }, [storageKeyTheme, storageKeyMode]);
1330
- React14.useEffect(() => {
3365
+ React24.useEffect(() => {
1331
3366
  if (typeof window === "undefined") return;
1332
3367
  try {
1333
3368
  window.localStorage.setItem(storageKeyTheme, theme);
@@ -1335,7 +3370,7 @@ function ThemeProvider({
1335
3370
  } catch {
1336
3371
  }
1337
3372
  }, [theme, mode, storageKeyTheme, storageKeyMode]);
1338
- React14.useEffect(() => {
3373
+ React24.useEffect(() => {
1339
3374
  if (typeof document === "undefined") return;
1340
3375
  const root = document.documentElement;
1341
3376
  root.dataset.ncTheme = theme;
@@ -1355,14 +3390,14 @@ function ThemeProvider({
1355
3390
  mediaQuery.addListener(applySystem);
1356
3391
  return () => mediaQuery.removeListener(applySystem);
1357
3392
  }, [theme, mode]);
1358
- const value = React14.useMemo(
3393
+ const value = React24.useMemo(
1359
3394
  () => ({ theme, mode, setTheme, setMode }),
1360
3395
  [theme, mode]
1361
3396
  );
1362
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ThemeContext.Provider, { value, children });
3397
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ThemeContext.Provider, { value, children });
1363
3398
  }
1364
3399
  function useTheme() {
1365
- const context = React14.useContext(ThemeContext);
3400
+ const context = React24.useContext(ThemeContext);
1366
3401
  if (!context) {
1367
3402
  throw new Error("useTheme must be used within ThemeProvider");
1368
3403
  }
@@ -1370,11 +3405,11 @@ function useTheme() {
1370
3405
  }
1371
3406
 
1372
3407
  // src/components/theme-switcher.tsx
1373
- var import_jsx_runtime29 = require("react/jsx-runtime");
3408
+ var import_jsx_runtime49 = require("react/jsx-runtime");
1374
3409
  var MODE_OPTIONS = ["system", "light", "dark"];
1375
3410
  function ThemeSwitcher({ className, showLabels = true, ...props }) {
1376
3411
  const { theme, mode, setTheme, setMode } = useTheme();
1377
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
3412
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
1378
3413
  "div",
1379
3414
  {
1380
3415
  className: cn(
@@ -1383,27 +3418,27 @@ function ThemeSwitcher({ className, showLabels = true, ...props }) {
1383
3418
  ),
1384
3419
  ...props,
1385
3420
  children: [
1386
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2", children: [
1387
- showLabels && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Theme" }),
1388
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3421
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "flex items-center gap-2", children: [
3422
+ showLabels && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Theme" }),
3423
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
1389
3424
  "select",
1390
3425
  {
1391
3426
  className: "rounded-lg border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-1 text-[rgb(var(--nc-fg))] outline-none focus:ring-2 focus:ring-[rgb(var(--nc-accent-1)/0.5)]",
1392
3427
  value: theme,
1393
3428
  onChange: (event) => setTheme(event.target.value),
1394
- children: THEME_NAMES.map((name) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: name, className: "text-slate-900", children: name }, name))
3429
+ children: THEME_NAMES.map((name) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("option", { value: name, className: "text-slate-900", children: name }, name))
1395
3430
  }
1396
3431
  )
1397
3432
  ] }),
1398
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2", children: [
1399
- showLabels && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Mode" }),
1400
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3433
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "flex items-center gap-2", children: [
3434
+ showLabels && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Mode" }),
3435
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
1401
3436
  "select",
1402
3437
  {
1403
3438
  className: "rounded-lg border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-1 text-[rgb(var(--nc-fg))] outline-none focus:ring-2 focus:ring-[rgb(var(--nc-accent-1)/0.5)]",
1404
3439
  value: mode,
1405
3440
  onChange: (event) => setMode(event.target.value),
1406
- children: MODE_OPTIONS.map((value) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value, className: "text-slate-900", children: value }, value))
3441
+ children: MODE_OPTIONS.map((value) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("option", { value, className: "text-slate-900", children: value }, value))
1407
3442
  }
1408
3443
  )
1409
3444
  ] })
@@ -1414,23 +3449,44 @@ function ThemeSwitcher({ className, showLabels = true, ...props }) {
1414
3449
  // Annotate the CommonJS export names for ESM import in node:
1415
3450
  0 && (module.exports = {
1416
3451
  AppShell,
3452
+ AppTemplate,
1417
3453
  AuthLayout,
1418
3454
  Breadcrumbs,
1419
3455
  Container,
3456
+ CraftAlert,
1420
3457
  CraftBadge,
1421
3458
  CraftButton,
1422
3459
  CraftCard,
1423
3460
  CraftCheckbox,
3461
+ CraftCommandPalette,
3462
+ CraftConfirmDialog,
3463
+ CraftCreateEditDrawer,
1424
3464
  CraftCurrencyInput,
3465
+ CraftDataTable,
1425
3466
  CraftDatePicker,
1426
3467
  CraftDrawer,
3468
+ CraftDropdownMenu,
1427
3469
  CraftEmptyState,
3470
+ CraftErrorState,
3471
+ CraftFilterBar,
3472
+ CraftForm,
3473
+ CraftFormBuilder,
3474
+ CraftFormField,
3475
+ CraftIcon,
3476
+ CraftIconProvider,
1428
3477
  CraftInput,
3478
+ CraftLink,
3479
+ CraftLoadingState,
1429
3480
  CraftModal,
1430
3481
  CraftNumberInput,
3482
+ CraftPagination,
3483
+ CraftPopover,
1431
3484
  CraftSelect,
1432
3485
  CraftSkeleton,
3486
+ CraftStatCard,
3487
+ CraftSubmitButton,
1433
3488
  CraftSwitch,
3489
+ CraftTableToolbar,
1434
3490
  CraftTabs,
1435
3491
  CraftTextarea,
1436
3492
  CraftToastHost,
@@ -1442,6 +3498,7 @@ function ThemeSwitcher({ className, showLabels = true, ...props }) {
1442
3498
  ThemeProvider,
1443
3499
  ThemeSwitcher,
1444
3500
  TopNav,
3501
+ layoutConfigSchema,
1445
3502
  useCraftToast,
1446
3503
  useTheme
1447
3504
  });