@memelabui/ui 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -101,11 +101,11 @@ function useDisclosure(defaultOpen = false) {
101
101
  }
102
102
  function useMediaQuery(query) {
103
103
  const [matches, setMatches] = React.useState(() => {
104
- if (typeof window === "undefined") return false;
104
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
105
105
  return window.matchMedia(query).matches;
106
106
  });
107
107
  React.useEffect(() => {
108
- if (typeof window === "undefined") return;
108
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
109
109
  const mediaQueryList = window.matchMedia(query);
110
110
  setMatches(mediaQueryList.matches);
111
111
  const handler = (event) => {
@@ -460,6 +460,765 @@ var SearchInput = React.forwardRef(function SearchInput2({ label, onClear, class
460
460
  wrapper
461
461
  ] });
462
462
  });
463
+ var sizeClass4 = {
464
+ left: { sm: "w-64", md: "w-80", lg: "w-96", full: "w-screen" },
465
+ right: { sm: "w-64", md: "w-80", lg: "w-96", full: "w-screen" },
466
+ bottom: { sm: "h-1/4", md: "h-1/3", lg: "h-1/2", full: "h-screen" }
467
+ };
468
+ var positionClass = {
469
+ left: "inset-y-0 left-0",
470
+ right: "inset-y-0 right-0",
471
+ bottom: "inset-x-0 bottom-0"
472
+ };
473
+ var slideIn = {
474
+ left: "translate-x-0",
475
+ right: "translate-x-0",
476
+ bottom: "translate-y-0"
477
+ };
478
+ var slideOut = {
479
+ left: "-translate-x-full",
480
+ right: "translate-x-full",
481
+ bottom: "translate-y-full"
482
+ };
483
+ function Drawer({
484
+ isOpen,
485
+ onClose,
486
+ children,
487
+ side = "right",
488
+ size = "md",
489
+ ariaLabel,
490
+ closeOnBackdrop = true,
491
+ closeOnEsc = true,
492
+ className
493
+ }) {
494
+ const panelRef = React.useRef(null);
495
+ const lastActiveRef = React.useRef(null);
496
+ React.useEffect(() => {
497
+ if (!isOpen) return;
498
+ lastActiveRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
499
+ const raf = requestAnimationFrame(() => {
500
+ const el = panelRef.current;
501
+ if (!el) return;
502
+ const focusables = getFocusableElements(el);
503
+ focusSafely(focusables[0] ?? el);
504
+ });
505
+ return () => {
506
+ cancelAnimationFrame(raf);
507
+ const lastActive = lastActiveRef.current;
508
+ lastActiveRef.current = null;
509
+ if (lastActive?.isConnected) focusSafely(lastActive);
510
+ };
511
+ }, [isOpen]);
512
+ useScrollLock(isOpen);
513
+ if (!isOpen) return null;
514
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50", role: "presentation", children: [
515
+ /* @__PURE__ */ jsxRuntime.jsx(
516
+ "div",
517
+ {
518
+ className: "absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity duration-200",
519
+ "aria-hidden": "true",
520
+ onClick: closeOnBackdrop ? onClose : void 0
521
+ }
522
+ ),
523
+ /* @__PURE__ */ jsxRuntime.jsx(
524
+ "div",
525
+ {
526
+ ref: panelRef,
527
+ role: "dialog",
528
+ "aria-modal": "true",
529
+ "aria-label": ariaLabel,
530
+ tabIndex: -1,
531
+ className: cn(
532
+ "fixed flex flex-col bg-surface-50 shadow-2xl ring-1 ring-white/10 transition-transform duration-300 ease-out focus:outline-none",
533
+ positionClass[side],
534
+ sizeClass4[side][size],
535
+ isOpen ? slideIn[side] : slideOut[side],
536
+ className
537
+ ),
538
+ onKeyDownCapture: (e) => {
539
+ if (closeOnEsc && e.key === "Escape") {
540
+ e.preventDefault();
541
+ e.stopPropagation();
542
+ onClose();
543
+ return;
544
+ }
545
+ if (e.key !== "Tab") return;
546
+ const el = panelRef.current;
547
+ if (!el) return;
548
+ const focusables = getFocusableElements(el);
549
+ if (focusables.length === 0) {
550
+ e.preventDefault();
551
+ focusSafely(el);
552
+ return;
553
+ }
554
+ const active = document.activeElement;
555
+ const first = focusables[0];
556
+ const last = focusables[focusables.length - 1];
557
+ if (e.shiftKey) {
558
+ if (active === first) {
559
+ e.preventDefault();
560
+ focusSafely(last);
561
+ }
562
+ } else {
563
+ if (active === last) {
564
+ e.preventDefault();
565
+ focusSafely(first);
566
+ }
567
+ }
568
+ },
569
+ children
570
+ }
571
+ )
572
+ ] });
573
+ }
574
+ function Popover({
575
+ content,
576
+ children,
577
+ placement = "bottom",
578
+ closeOnClickOutside = true,
579
+ closeOnEsc = true,
580
+ open: controlledOpen,
581
+ onOpenChange,
582
+ offset = 8,
583
+ className
584
+ }) {
585
+ const popoverId = React.useId();
586
+ const anchorRef = React.useRef(null);
587
+ const popoverRef = React.useRef(null);
588
+ const [internalOpen, setInternalOpen] = React.useState(false);
589
+ const [pos, setPos] = React.useState(null);
590
+ const isControlled = controlledOpen !== void 0;
591
+ const isOpen = isControlled ? controlledOpen : internalOpen;
592
+ const setOpen = React.useCallback(
593
+ (value) => {
594
+ if (!isControlled) setInternalOpen(value);
595
+ onOpenChange?.(value);
596
+ },
597
+ [isControlled, onOpenChange]
598
+ );
599
+ const toggle = React.useCallback(() => setOpen(!isOpen), [isOpen, setOpen]);
600
+ const close = React.useCallback(() => setOpen(false), [setOpen]);
601
+ const updatePosition = React.useCallback(() => {
602
+ const el = anchorRef.current;
603
+ if (!el) return;
604
+ const r = el.getBoundingClientRect();
605
+ let left;
606
+ let top;
607
+ let effPlacement = placement;
608
+ if (placement === "bottom" || placement === "top") {
609
+ left = r.left + r.width / 2;
610
+ if (placement === "bottom") {
611
+ top = r.bottom + offset;
612
+ if (top + 200 > window.innerHeight && r.top - offset > 200) {
613
+ effPlacement = "top";
614
+ top = r.top - offset;
615
+ }
616
+ } else {
617
+ top = r.top - offset;
618
+ if (top < 8) {
619
+ effPlacement = "bottom";
620
+ top = r.bottom + offset;
621
+ }
622
+ }
623
+ } else {
624
+ top = r.top + r.height / 2;
625
+ if (placement === "right") {
626
+ left = r.right + offset;
627
+ } else {
628
+ left = r.left - offset;
629
+ }
630
+ }
631
+ setPos({ left: Math.round(left), top: Math.round(top), placement: effPlacement });
632
+ }, [placement, offset]);
633
+ React.useEffect(() => {
634
+ if (!isOpen) return;
635
+ updatePosition();
636
+ window.addEventListener("scroll", updatePosition, true);
637
+ window.addEventListener("resize", updatePosition);
638
+ return () => {
639
+ window.removeEventListener("scroll", updatePosition, true);
640
+ window.removeEventListener("resize", updatePosition);
641
+ };
642
+ }, [isOpen, updatePosition]);
643
+ React.useEffect(() => {
644
+ if (!isOpen || !closeOnClickOutside) return;
645
+ const handleClick = (e) => {
646
+ const target = e.target;
647
+ if (anchorRef.current?.contains(target) || popoverRef.current?.contains(target)) {
648
+ return;
649
+ }
650
+ close();
651
+ };
652
+ document.addEventListener("mousedown", handleClick);
653
+ return () => document.removeEventListener("mousedown", handleClick);
654
+ }, [isOpen, closeOnClickOutside, close]);
655
+ React.useEffect(() => {
656
+ if (!isOpen || !closeOnEsc) return;
657
+ const handleKey = (e) => {
658
+ if (e.key === "Escape") {
659
+ e.preventDefault();
660
+ close();
661
+ anchorRef.current?.focus();
662
+ }
663
+ };
664
+ document.addEventListener("keydown", handleKey);
665
+ return () => document.removeEventListener("keydown", handleKey);
666
+ }, [isOpen, closeOnEsc, close]);
667
+ if (!React.isValidElement(children)) return children;
668
+ const child = React.cloneElement(children, {
669
+ ref: (node) => {
670
+ anchorRef.current = node;
671
+ const childProps = children.props;
672
+ const prevRef = childProps.ref;
673
+ if (typeof prevRef === "function") prevRef(node);
674
+ else if (prevRef && typeof prevRef === "object") prevRef.current = node;
675
+ },
676
+ onClick: (e) => {
677
+ const childProps = children.props;
678
+ if (typeof childProps.onClick === "function") childProps.onClick(e);
679
+ toggle();
680
+ },
681
+ "aria-expanded": isOpen,
682
+ "aria-haspopup": "dialog",
683
+ "aria-controls": isOpen ? popoverId : void 0
684
+ });
685
+ const getTransform = () => {
686
+ if (!pos) return "translate(-9999px, -9999px)";
687
+ switch (pos.placement) {
688
+ case "top":
689
+ return "translate(-50%, -100%)";
690
+ case "bottom":
691
+ return "translate(-50%, 0%)";
692
+ case "left":
693
+ return "translate(-100%, -50%)";
694
+ case "right":
695
+ return "translate(0%, -50%)";
696
+ }
697
+ };
698
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
699
+ child,
700
+ isOpen && typeof document !== "undefined" ? reactDom.createPortal(
701
+ /* @__PURE__ */ jsxRuntime.jsx(
702
+ "div",
703
+ {
704
+ ref: popoverRef,
705
+ id: popoverId,
706
+ role: "dialog",
707
+ className: cn(
708
+ "fixed z-[9999] rounded-xl shadow-xl ring-1 ring-white/10 bg-surface-50 backdrop-blur-md p-4",
709
+ className
710
+ ),
711
+ style: {
712
+ left: pos?.left ?? 0,
713
+ top: pos?.top ?? 0,
714
+ transform: getTransform()
715
+ },
716
+ children: content
717
+ }
718
+ ),
719
+ document.body
720
+ ) : null
721
+ ] });
722
+ }
723
+ var DAY_NAMES = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
724
+ var DAY_IN_MS = 24 * 60 * 60 * 1e3;
725
+ function startOfDay(date) {
726
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
727
+ }
728
+ function startOfMonth(date) {
729
+ return new Date(date.getFullYear(), date.getMonth(), 1);
730
+ }
731
+ function addDays(date, amount) {
732
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount);
733
+ }
734
+ function addMonths(date, amount) {
735
+ return new Date(date.getFullYear(), date.getMonth() + amount, 1);
736
+ }
737
+ function getCalendarStart(date) {
738
+ const monthStart = startOfMonth(date);
739
+ const day = monthStart.getDay();
740
+ const diff = day === 0 ? 6 : day - 1;
741
+ return addDays(monthStart, -diff);
742
+ }
743
+ function isSameDay(a, b) {
744
+ if (!a || !b) return false;
745
+ return startOfDay(a).getTime() === startOfDay(b).getTime();
746
+ }
747
+ function isBetween(day, from, to) {
748
+ if (!from || !to) return false;
749
+ const current = startOfDay(day).getTime();
750
+ return current > startOfDay(from).getTime() && current < startOfDay(to).getTime();
751
+ }
752
+ function diffInDays(from, to) {
753
+ return Math.round((startOfDay(to).getTime() - startOfDay(from).getTime()) / DAY_IN_MS);
754
+ }
755
+ function pad(value) {
756
+ return String(value).padStart(2, "0");
757
+ }
758
+ function formatDate(date, pattern) {
759
+ return pattern.replace("dd", pad(date.getDate())).replace("MM", pad(date.getMonth() + 1)).replace("yyyy", String(date.getFullYear()));
760
+ }
761
+ function formatMonthLabel(date) {
762
+ return new Intl.DateTimeFormat(void 0, { month: "long", year: "numeric" }).format(date);
763
+ }
764
+ function formatFullDate(date) {
765
+ return new Intl.DateTimeFormat(void 0, {
766
+ year: "numeric",
767
+ month: "long",
768
+ day: "numeric"
769
+ }).format(date);
770
+ }
771
+ function parseDateInput(value) {
772
+ const trimmed = value.trim();
773
+ if (!trimmed) return null;
774
+ if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
775
+ const [year2, month2, day2] = trimmed.split("-").map(Number);
776
+ const parsed2 = new Date(year2, month2 - 1, day2);
777
+ if (parsed2.getFullYear() === year2 && parsed2.getMonth() === month2 - 1 && parsed2.getDate() === day2) {
778
+ return startOfDay(parsed2);
779
+ }
780
+ return null;
781
+ }
782
+ const match = trimmed.match(/^(\d{1,2})[./-](\d{1,2})[./-](\d{4})$/);
783
+ if (!match) return null;
784
+ const day = Number(match[1]);
785
+ const month = Number(match[2]);
786
+ const year = Number(match[3]);
787
+ const parsed = new Date(year, month - 1, day);
788
+ if (parsed.getFullYear() !== year || parsed.getMonth() !== month - 1 || parsed.getDate() !== day) {
789
+ return null;
790
+ }
791
+ return startOfDay(parsed);
792
+ }
793
+ function getPlaceholder(placeholder, key, fallback) {
794
+ if (typeof placeholder === "string") {
795
+ return key === "trigger" ? placeholder : fallback;
796
+ }
797
+ return placeholder?.[key] ?? fallback;
798
+ }
799
+ function buildCalendarDays(month) {
800
+ const start = getCalendarStart(month);
801
+ return Array.from({ length: 42 }, (_, index) => addDays(start, index));
802
+ }
803
+ function getRangeSummary(range, formatPattern) {
804
+ if (range.from && range.to) {
805
+ return `${formatDate(range.from, formatPattern)} - ${formatDate(range.to, formatPattern)}`;
806
+ }
807
+ if (range.from) {
808
+ return `${formatDate(range.from, formatPattern)} - ...`;
809
+ }
810
+ return "No date range selected";
811
+ }
812
+ function normalizeRange(range) {
813
+ return {
814
+ from: range.from ? startOfDay(range.from) : null,
815
+ to: range.to ? startOfDay(range.to) : null
816
+ };
817
+ }
818
+ function clampRange(range, min, max, maxRangeDays) {
819
+ let nextFrom = range.from ? startOfDay(range.from) : null;
820
+ let nextTo = range.to ? startOfDay(range.to) : null;
821
+ if (min) {
822
+ const minDay = startOfDay(min);
823
+ if (nextFrom && nextFrom < minDay) nextFrom = minDay;
824
+ if (nextTo && nextTo < minDay) nextTo = minDay;
825
+ }
826
+ if (max) {
827
+ const maxDay = startOfDay(max);
828
+ if (nextFrom && nextFrom > maxDay) nextFrom = maxDay;
829
+ if (nextTo && nextTo > maxDay) nextTo = maxDay;
830
+ }
831
+ if (nextFrom && nextTo && nextFrom > nextTo) {
832
+ const swap = nextFrom;
833
+ nextFrom = nextTo;
834
+ nextTo = swap;
835
+ }
836
+ if (nextFrom && nextTo && maxRangeDays && diffInDays(nextFrom, nextTo) + 1 > maxRangeDays) {
837
+ nextTo = addDays(nextFrom, maxRangeDays - 1);
838
+ }
839
+ return { from: nextFrom, to: nextTo };
840
+ }
841
+ function isDateDisabled(day, range, min, max, maxRangeDays) {
842
+ const normalized = startOfDay(day);
843
+ const minDay = min ? startOfDay(min) : null;
844
+ const maxDay = max ? startOfDay(max) : null;
845
+ if (minDay && normalized < minDay) return true;
846
+ if (maxDay && normalized > maxDay) return true;
847
+ if (range.from && !range.to && maxRangeDays) {
848
+ return Math.abs(diffInDays(range.from, normalized)) + 1 > maxRangeDays;
849
+ }
850
+ return false;
851
+ }
852
+ function CalendarIcon() {
853
+ return /* @__PURE__ */ jsxRuntime.jsxs(
854
+ "svg",
855
+ {
856
+ "aria-hidden": "true",
857
+ className: "h-4 w-4",
858
+ viewBox: "0 0 20 20",
859
+ fill: "none",
860
+ xmlns: "http://www.w3.org/2000/svg",
861
+ children: [
862
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "14", height: "13", rx: "2.5", stroke: "currentColor", strokeWidth: "1.5" }),
863
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6.5 2.75V5.5M13.5 2.75V5.5M3 8h14", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
864
+ ]
865
+ }
866
+ );
867
+ }
868
+ function ChevronIcon({ className }) {
869
+ return /* @__PURE__ */ jsxRuntime.jsx(
870
+ "svg",
871
+ {
872
+ "aria-hidden": "true",
873
+ className: cn("h-4 w-4", className),
874
+ viewBox: "0 0 20 20",
875
+ fill: "none",
876
+ xmlns: "http://www.w3.org/2000/svg",
877
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 8l4 4 4-4", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" })
878
+ }
879
+ );
880
+ }
881
+ function CalendarMonth({
882
+ month,
883
+ viewMonth,
884
+ range,
885
+ formatPattern,
886
+ min,
887
+ max,
888
+ maxRangeDays,
889
+ onPrevMonth,
890
+ onNextMonth,
891
+ onSelectDay
892
+ }) {
893
+ const days = React.useMemo(() => buildCalendarDays(month), [month]);
894
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-white/10 bg-white/[0.03] p-3", children: [
895
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 flex items-center justify-between gap-2", children: [
896
+ /* @__PURE__ */ jsxRuntime.jsx(
897
+ "button",
898
+ {
899
+ type: "button",
900
+ onClick: onPrevMonth,
901
+ disabled: !onPrevMonth,
902
+ "aria-label": "Previous month",
903
+ className: cn(
904
+ "inline-flex h-8 w-8 items-center justify-center rounded-lg text-white/70 transition-colors",
905
+ onPrevMonth ? "hover:bg-white/10 hover:text-white" : "pointer-events-none opacity-0"
906
+ ),
907
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: "h-4 w-4", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5l-5 5 5 5", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) })
908
+ }
909
+ ),
910
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium capitalize text-white", children: formatMonthLabel(month) }),
911
+ /* @__PURE__ */ jsxRuntime.jsx(
912
+ "button",
913
+ {
914
+ type: "button",
915
+ onClick: onNextMonth,
916
+ disabled: !onNextMonth,
917
+ "aria-label": "Next month",
918
+ className: cn(
919
+ "inline-flex h-8 w-8 items-center justify-center rounded-lg text-white/70 transition-colors",
920
+ onNextMonth ? "hover:bg-white/10 hover:text-white" : "pointer-events-none opacity-0"
921
+ ),
922
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: "h-4 w-4", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 5l5 5-5 5", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) })
923
+ }
924
+ )
925
+ ] }),
926
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 grid grid-cols-7 gap-1 text-center text-[11px] font-medium uppercase tracking-[0.14em] text-white/35", children: DAY_NAMES.map((day) => /* @__PURE__ */ jsxRuntime.jsx("span", { children: day }, day)) }),
927
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 gap-1", children: days.map((day) => {
928
+ const inMonth = day.getMonth() === month.getMonth();
929
+ const disabled = isDateDisabled(day, range, min, max, maxRangeDays);
930
+ const selectedStart = isSameDay(day, range.from);
931
+ const selectedEnd = isSameDay(day, range.to);
932
+ const inRange = isBetween(day, range.from, range.to);
933
+ const isToday = isSameDay(day, /* @__PURE__ */ new Date());
934
+ const roundedClass = selectedStart && selectedEnd ? "rounded-xl" : selectedStart ? "rounded-l-xl rounded-r-md" : selectedEnd ? "rounded-r-xl rounded-l-md" : inRange ? "rounded-md" : "rounded-xl";
935
+ return /* @__PURE__ */ jsxRuntime.jsxs(
936
+ "button",
937
+ {
938
+ type: "button",
939
+ disabled,
940
+ onClick: () => onSelectDay(day),
941
+ "aria-label": formatFullDate(day),
942
+ "aria-pressed": selectedStart || selectedEnd || inRange,
943
+ className: cn(
944
+ "relative h-9 w-full text-sm tabular-nums transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40",
945
+ roundedClass,
946
+ !inMonth && "text-white/25",
947
+ inMonth && !selectedStart && !selectedEnd && !inRange && "text-white/75",
948
+ (selectedStart || selectedEnd) && "bg-primary text-white shadow-glow",
949
+ inRange && !selectedStart && !selectedEnd && "bg-primary/15 text-white",
950
+ !selectedStart && !selectedEnd && !inRange && !disabled && "hover:bg-white/10 hover:text-white",
951
+ disabled && "cursor-not-allowed opacity-35"
952
+ ),
953
+ children: [
954
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatDate(day, "dd") }),
955
+ isToday && !selectedStart && !selectedEnd && !inRange ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-x-2 bottom-1 h-0.5 rounded-full bg-primary/70" }) : null,
956
+ isSameDay(day, viewMonth) ? null : null
957
+ ]
958
+ },
959
+ day.toISOString()
960
+ );
961
+ }) }),
962
+ range.from || range.to ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-xs text-white/45", children: getRangeSummary(range, formatPattern) }) : null
963
+ ] });
964
+ }
965
+ function DateRangePicker({
966
+ value,
967
+ onChange,
968
+ presets,
969
+ format = "dd.MM.yyyy",
970
+ placeholder,
971
+ min,
972
+ max,
973
+ maxRangeDays,
974
+ label,
975
+ helperText,
976
+ clearable = true,
977
+ disabled,
978
+ hasError,
979
+ error,
980
+ closeOnSelect = false,
981
+ compact = false,
982
+ className
983
+ }) {
984
+ const isMobile = useMediaQuery("(max-width: 767px)");
985
+ const [open, setOpen] = React.useState(false);
986
+ const normalizedValue = React.useMemo(() => normalizeRange(value), [value]);
987
+ const [viewMonth, setViewMonth] = React.useState(() => startOfMonth(normalizedValue.from ?? normalizedValue.to ?? /* @__PURE__ */ new Date()));
988
+ const [fromInput, setFromInput] = React.useState("");
989
+ const [toInput, setToInput] = React.useState("");
990
+ const showError = hasError || Boolean(error);
991
+ const hasValue = normalizedValue.from !== null || normalizedValue.to !== null;
992
+ const triggerPlaceholder = getPlaceholder(placeholder, "trigger", compact ? "Any date" : "Select date range");
993
+ const fromPlaceholder = getPlaceholder(placeholder, "from", "dd.mm.yyyy");
994
+ const toPlaceholder = getPlaceholder(placeholder, "to", "dd.mm.yyyy");
995
+ const monthsToRender = isMobile ? [viewMonth] : [viewMonth, addMonths(viewMonth, 1)];
996
+ React.useEffect(() => {
997
+ setFromInput(normalizedValue.from ? formatDate(normalizedValue.from, format) : "");
998
+ setToInput(normalizedValue.to ? formatDate(normalizedValue.to, format) : "");
999
+ }, [normalizedValue.from, normalizedValue.to, format]);
1000
+ React.useEffect(() => {
1001
+ if (!open) {
1002
+ setViewMonth(startOfMonth(normalizedValue.from ?? normalizedValue.to ?? /* @__PURE__ */ new Date()));
1003
+ }
1004
+ }, [normalizedValue.from, normalizedValue.to, open]);
1005
+ const selectedText = React.useMemo(() => {
1006
+ if (normalizedValue.from && normalizedValue.to) {
1007
+ return `${formatDate(normalizedValue.from, format)} - ${formatDate(normalizedValue.to, format)}`;
1008
+ }
1009
+ if (normalizedValue.from) {
1010
+ return `${formatDate(normalizedValue.from, format)} - ...`;
1011
+ }
1012
+ return triggerPlaceholder;
1013
+ }, [format, normalizedValue.from, normalizedValue.to, triggerPlaceholder]);
1014
+ const handleRangeChange = (nextRange) => {
1015
+ onChange(clampRange(nextRange, min, max, maxRangeDays));
1016
+ };
1017
+ const handleSelectDay = (day) => {
1018
+ if (isDateDisabled(day, normalizedValue, min, max, maxRangeDays)) {
1019
+ return;
1020
+ }
1021
+ const normalizedDay = startOfDay(day);
1022
+ if (!normalizedValue.from || normalizedValue.to) {
1023
+ handleRangeChange({ from: normalizedDay, to: null });
1024
+ return;
1025
+ }
1026
+ const nextRange = normalizedDay < normalizedValue.from ? { from: normalizedDay, to: normalizedValue.from } : { from: normalizedValue.from, to: normalizedDay };
1027
+ handleRangeChange(nextRange);
1028
+ if (closeOnSelect) {
1029
+ setOpen(false);
1030
+ }
1031
+ };
1032
+ const commitInput = (kind, rawValue) => {
1033
+ const parsed = parseDateInput(rawValue);
1034
+ if (!rawValue.trim()) {
1035
+ handleRangeChange({
1036
+ from: kind === "from" ? null : normalizedValue.from,
1037
+ to: kind === "to" ? null : normalizedValue.to
1038
+ });
1039
+ return;
1040
+ }
1041
+ if (!parsed || isDateDisabled(parsed, normalizedValue, min, max, maxRangeDays)) {
1042
+ return;
1043
+ }
1044
+ if (kind === "from") {
1045
+ handleRangeChange({ from: parsed, to: normalizedValue.to });
1046
+ setViewMonth(startOfMonth(parsed));
1047
+ return;
1048
+ }
1049
+ handleRangeChange({ from: normalizedValue.from, to: parsed });
1050
+ setViewMonth(startOfMonth(parsed));
1051
+ };
1052
+ const handleClear = () => {
1053
+ handleRangeChange({ from: null, to: null });
1054
+ setOpen(false);
1055
+ };
1056
+ const panel = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-4 p-4", isMobile ? "h-full overflow-y-auto" : "w-[min(42rem,calc(100vw-1.5rem))] max-w-[calc(100vw-1.5rem)]"), children: [
1057
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
1058
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1059
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-white", children: "Date range" }),
1060
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-white/50", children: "Pick a start and end date or use a preset." })
1061
+ ] }),
1062
+ !isMobile ? /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "ghost", onClick: () => setOpen(false), children: "Done" }) : null
1063
+ ] }),
1064
+ presets && presets.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: presets.map((preset) => {
1065
+ const presetRange = clampRange(preset.range, min, max, maxRangeDays);
1066
+ const active = isSameDay(presetRange.from, normalizedValue.from) && isSameDay(presetRange.to, normalizedValue.to);
1067
+ return /* @__PURE__ */ jsxRuntime.jsx(
1068
+ "button",
1069
+ {
1070
+ type: "button",
1071
+ onClick: () => {
1072
+ handleRangeChange(presetRange);
1073
+ if (closeOnSelect) {
1074
+ setOpen(false);
1075
+ }
1076
+ },
1077
+ className: cn(
1078
+ "rounded-xl border px-3 py-1.5 text-xs font-medium transition-colors",
1079
+ active ? "border-primary/60 bg-primary/15 text-white" : "border-white/10 bg-white/[0.03] text-white/70 hover:bg-white/10 hover:text-white"
1080
+ ),
1081
+ children: preset.label
1082
+ },
1083
+ preset.label
1084
+ );
1085
+ }) }) : null,
1086
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
1087
+ /* @__PURE__ */ jsxRuntime.jsx(
1088
+ Input,
1089
+ {
1090
+ label: "From",
1091
+ value: fromInput,
1092
+ placeholder: fromPlaceholder,
1093
+ onChange: (event) => setFromInput(event.target.value),
1094
+ onBlur: (event) => commitInput("from", event.target.value),
1095
+ onKeyDown: (event) => {
1096
+ if (event.key === "Enter") {
1097
+ event.preventDefault();
1098
+ commitInput("from", fromInput);
1099
+ }
1100
+ }
1101
+ }
1102
+ ),
1103
+ /* @__PURE__ */ jsxRuntime.jsx(
1104
+ Input,
1105
+ {
1106
+ label: "To",
1107
+ value: toInput,
1108
+ placeholder: toPlaceholder,
1109
+ onChange: (event) => setToInput(event.target.value),
1110
+ onBlur: (event) => commitInput("to", event.target.value),
1111
+ onKeyDown: (event) => {
1112
+ if (event.key === "Enter") {
1113
+ event.preventDefault();
1114
+ commitInput("to", toInput);
1115
+ }
1116
+ }
1117
+ }
1118
+ )
1119
+ ] }),
1120
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("grid gap-4", isMobile ? "grid-cols-1" : "md:grid-cols-2"), children: monthsToRender.map((month, index) => /* @__PURE__ */ jsxRuntime.jsx(
1121
+ CalendarMonth,
1122
+ {
1123
+ month,
1124
+ viewMonth,
1125
+ range: normalizedValue,
1126
+ formatPattern: format,
1127
+ min,
1128
+ max,
1129
+ maxRangeDays,
1130
+ onPrevMonth: index === 0 ? () => setViewMonth((prev) => addMonths(prev, -1)) : void 0,
1131
+ onNextMonth: index === monthsToRender.length - 1 ? () => setViewMonth((prev) => addMonths(prev, 1)) : void 0,
1132
+ onSelectDay: handleSelectDay
1133
+ },
1134
+ month.toISOString()
1135
+ )) }),
1136
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-white/10 pt-3", children: [
1137
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-white/45", children: getRangeSummary(normalizedValue, format) }),
1138
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1139
+ clearable ? /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "ghost", onClick: handleClear, children: "Clear" }) : null,
1140
+ isMobile ? /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "secondary", onClick: () => setOpen(false), children: "Done" }) : null
1141
+ ] })
1142
+ ] })
1143
+ ] });
1144
+ const triggerButton = /* @__PURE__ */ jsxRuntime.jsxs(
1145
+ "button",
1146
+ {
1147
+ type: "button",
1148
+ disabled,
1149
+ onClick: () => {
1150
+ if (isMobile) {
1151
+ setOpen(true);
1152
+ }
1153
+ },
1154
+ "aria-label": `Date range: ${selectedText}`,
1155
+ className: cn(
1156
+ "flex w-full items-center justify-between gap-3 rounded-xl bg-white/10 text-left text-white shadow-sm outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-primary/40",
1157
+ compact ? "min-h-10 px-3 py-2 text-sm" : "min-h-11 px-3 py-2.5 text-sm",
1158
+ hasValue && clearable && "pr-16",
1159
+ showError && "ring-2 ring-rose-500/40 focus-visible:ring-rose-500/40",
1160
+ disabled && "cursor-not-allowed opacity-60",
1161
+ className
1162
+ ),
1163
+ children: [
1164
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
1165
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(hasValue ? "text-primary" : "text-white/40"), children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, {}) }),
1166
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("truncate", hasValue ? "text-white" : "text-white/40"), children: selectedText })
1167
+ ] }),
1168
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2 text-white/45", children: [
1169
+ normalizedValue.from && normalizedValue.to ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "hidden rounded-full bg-white/10 px-2 py-0.5 text-[11px] text-white/60 sm:inline-flex", children: [
1170
+ diffInDays(normalizedValue.from, normalizedValue.to) + 1,
1171
+ "d"
1172
+ ] }) : null,
1173
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon, { className: cn(open && "rotate-180 transition-transform") })
1174
+ ] })
1175
+ ]
1176
+ }
1177
+ );
1178
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1179
+ label ? /* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-1.5 block text-sm text-white/70", children: label }) : null,
1180
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1181
+ isMobile ? triggerButton : /* @__PURE__ */ jsxRuntime.jsx(
1182
+ Popover,
1183
+ {
1184
+ open,
1185
+ onOpenChange: setOpen,
1186
+ placement: "bottom",
1187
+ className: "overflow-hidden p-0",
1188
+ content: panel,
1189
+ children: triggerButton
1190
+ }
1191
+ ),
1192
+ clearable && hasValue ? /* @__PURE__ */ jsxRuntime.jsx(
1193
+ "button",
1194
+ {
1195
+ type: "button",
1196
+ onClick: (event) => {
1197
+ event.stopPropagation();
1198
+ handleClear();
1199
+ },
1200
+ "aria-label": "Clear date range",
1201
+ className: "absolute right-10 top-1/2 -translate-y-1/2 rounded-md p-1 text-white/35 transition-colors hover:bg-white/10 hover:text-white",
1202
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: "h-3.5 w-3.5", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 4l8 8M12 4l-8 8", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) })
1203
+ }
1204
+ ) : null
1205
+ ] }),
1206
+ error ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-rose-400", children: error }) : null,
1207
+ helperText && !error ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-white/40", children: helperText }) : null,
1208
+ isMobile ? /* @__PURE__ */ jsxRuntime.jsx(
1209
+ Drawer,
1210
+ {
1211
+ isOpen: open,
1212
+ onClose: () => setOpen(false),
1213
+ side: "bottom",
1214
+ size: "full",
1215
+ ariaLabel: "Date range picker",
1216
+ className: "rounded-t-3xl",
1217
+ children: panel
1218
+ }
1219
+ ) : null
1220
+ ] });
1221
+ }
463
1222
  var selectBase = "w-full rounded-xl px-3 py-2.5 text-sm bg-white/10 text-white shadow-sm outline-none focus-visible:ring-2 focus-visible:ring-primary/40 transition-shadow";
464
1223
  var Select = React.forwardRef(function Select2({ hasError, label, error, helperText, className, id: externalId, children, ...props }, ref) {
465
1224
  const generatedId = React.useId();
@@ -513,128 +1272,131 @@ var Textarea = React.forwardRef(function Textarea2({ hasError, label, error, hel
513
1272
  helperText && !error && /* @__PURE__ */ jsxRuntime.jsx("p", { id: helperId, className: "text-white/40 text-xs mt-1", children: helperText })
514
1273
  ] });
515
1274
  });
516
- function TagInput({
517
- value,
518
- onChange,
519
- placeholder,
520
- disabled = false,
521
- label,
522
- error,
523
- maxTags,
524
- className,
525
- id: externalId
526
- }) {
527
- const generatedId = React.useId();
528
- const inputId = externalId ?? generatedId;
529
- const errorId = error ? `${inputId}-error` : void 0;
530
- const inputRef = React.useRef(null);
531
- const atMax = maxTags !== void 0 && value.length >= maxTags;
532
- function addTag(raw) {
533
- const tag = raw.trim();
534
- if (!tag || value.includes(tag) || atMax) return;
535
- onChange([...value, tag]);
536
- }
537
- function removeTag(index) {
538
- onChange(value.filter((_, i) => i !== index));
539
- }
540
- function handleKeyDown(e) {
541
- const input = inputRef.current;
542
- if (!input) return;
543
- if (e.key === "Enter" || e.key === "," || e.key === "Tab") {
544
- if (input.value) {
545
- e.preventDefault();
546
- addTag(input.value);
547
- input.value = "";
548
- }
549
- return;
1275
+ var TagInput = React.forwardRef(
1276
+ function TagInput2({
1277
+ value,
1278
+ onChange,
1279
+ placeholder,
1280
+ disabled = false,
1281
+ label,
1282
+ error,
1283
+ maxTags,
1284
+ className,
1285
+ id: externalId
1286
+ }, ref) {
1287
+ const generatedId = React.useId();
1288
+ const inputId = externalId ?? generatedId;
1289
+ const errorId = error ? `${inputId}-error` : void 0;
1290
+ const internalRef = React.useRef(null);
1291
+ const inputRef = ref ?? internalRef;
1292
+ const atMax = maxTags !== void 0 && value.length >= maxTags;
1293
+ function addTag(raw) {
1294
+ const tag = raw.trim();
1295
+ if (!tag || value.includes(tag) || atMax) return;
1296
+ onChange([...value, tag]);
550
1297
  }
551
- if (e.key === "Backspace" && !input.value && value.length > 0) {
552
- removeTag(value.length - 1);
1298
+ function removeTag(index) {
1299
+ onChange(value.filter((_, i) => i !== index));
553
1300
  }
554
- }
555
- function handlePaste(e) {
556
- const pasted = e.clipboardData.getData("text");
557
- if (!pasted.includes(",")) return;
558
- e.preventDefault();
559
- const parts = pasted.split(",");
560
- const next = [...value];
561
- for (const part of parts) {
562
- const tag = part.trim();
563
- if (tag && !next.includes(tag)) {
564
- if (maxTags !== void 0 && next.length >= maxTags) break;
565
- next.push(tag);
1301
+ function handleKeyDown(e) {
1302
+ const input = inputRef.current;
1303
+ if (!input) return;
1304
+ if (e.key === "Enter" || e.key === "," || e.key === "Tab") {
1305
+ if (input.value) {
1306
+ e.preventDefault();
1307
+ addTag(input.value);
1308
+ input.value = "";
1309
+ }
1310
+ return;
1311
+ }
1312
+ if (e.key === "Backspace" && !input.value && value.length > 0) {
1313
+ removeTag(value.length - 1);
566
1314
  }
567
1315
  }
568
- onChange(next);
569
- if (inputRef.current) inputRef.current.value = "";
570
- }
571
- const wrapper = /* @__PURE__ */ jsxRuntime.jsxs(
572
- "div",
573
- {
574
- className: cn(
575
- "flex flex-wrap items-center gap-1.5 min-h-[42px] w-full rounded-xl px-3 py-2 bg-white/10 ring-1 ring-white/10 transition-shadow focus-within:ring-2 focus-within:ring-primary/40",
576
- error && "ring-2 ring-rose-500/40 focus-within:ring-rose-500/40",
577
- disabled && "opacity-50 cursor-not-allowed",
578
- className
579
- ),
580
- onClick: () => inputRef.current?.focus(),
581
- children: [
582
- value.map((tag, i) => /* @__PURE__ */ jsxRuntime.jsxs(
583
- "span",
584
- {
585
- className: "inline-flex items-center gap-1 bg-white/10 text-white/90 rounded-full text-xs px-2.5 py-1 ring-1 ring-white/10",
586
- children: [
587
- tag,
588
- !disabled && /* @__PURE__ */ jsxRuntime.jsx(
589
- "button",
590
- {
591
- type: "button",
592
- "aria-label": `Remove ${tag}`,
593
- onClick: (e) => {
594
- e.stopPropagation();
595
- removeTag(i);
596
- },
597
- className: "text-white/50 hover:text-white/90 transition-colors leading-none",
598
- children: "\u2715"
599
- }
600
- )
601
- ]
602
- },
603
- `${tag}-${i}`
604
- )),
605
- /* @__PURE__ */ jsxRuntime.jsx(
606
- "input",
607
- {
608
- ref: inputRef,
609
- id: inputId,
610
- type: "text",
611
- disabled: disabled || atMax,
612
- placeholder: value.length === 0 ? placeholder : void 0,
613
- "aria-invalid": !!error || void 0,
614
- "aria-describedby": errorId,
615
- onKeyDown: handleKeyDown,
616
- onPaste: handlePaste,
617
- onBlur: (e) => {
618
- if (e.target.value) {
619
- addTag(e.target.value);
620
- e.target.value = "";
621
- }
622
- },
623
- className: "flex-1 min-w-[120px] bg-transparent text-sm text-white outline-none placeholder-white/30 disabled:cursor-not-allowed"
624
- }
625
- )
626
- ]
1316
+ function handlePaste(e) {
1317
+ const pasted = e.clipboardData.getData("text");
1318
+ if (!pasted.includes(",")) return;
1319
+ e.preventDefault();
1320
+ const parts = pasted.split(",");
1321
+ const next = [...value];
1322
+ for (const part of parts) {
1323
+ const tag = part.trim();
1324
+ if (tag && !next.includes(tag)) {
1325
+ if (maxTags !== void 0 && next.length >= maxTags) break;
1326
+ next.push(tag);
1327
+ }
1328
+ }
1329
+ onChange(next);
1330
+ if (inputRef.current) inputRef.current.value = "";
627
1331
  }
628
- );
629
- if (!label && !error) return wrapper;
630
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
631
- label && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: inputId, className: "block text-sm text-white/70 mb-1.5", children: label }),
632
- wrapper,
633
- error && /* @__PURE__ */ jsxRuntime.jsx("p", { id: errorId, className: "text-rose-400 text-xs mt-1", children: error })
634
- ] });
635
- }
1332
+ const wrapper = /* @__PURE__ */ jsxRuntime.jsxs(
1333
+ "div",
1334
+ {
1335
+ className: cn(
1336
+ "flex flex-wrap items-center gap-1.5 min-h-[42px] w-full rounded-xl px-3 py-2 bg-white/10 ring-1 ring-white/10 transition-shadow focus-within:ring-2 focus-within:ring-primary/40",
1337
+ error && "ring-2 ring-rose-500/40 focus-within:ring-rose-500/40",
1338
+ disabled && "opacity-50 cursor-not-allowed",
1339
+ className
1340
+ ),
1341
+ onClick: () => inputRef.current?.focus(),
1342
+ children: [
1343
+ value.map((tag, i) => /* @__PURE__ */ jsxRuntime.jsxs(
1344
+ "span",
1345
+ {
1346
+ className: "inline-flex items-center gap-1 bg-white/10 text-white/90 rounded-full text-xs px-2.5 py-1 ring-1 ring-white/10",
1347
+ children: [
1348
+ tag,
1349
+ !disabled && /* @__PURE__ */ jsxRuntime.jsx(
1350
+ "button",
1351
+ {
1352
+ type: "button",
1353
+ "aria-label": `Remove ${tag}`,
1354
+ onClick: (e) => {
1355
+ e.stopPropagation();
1356
+ removeTag(i);
1357
+ },
1358
+ className: "text-white/50 hover:text-white/90 transition-colors leading-none",
1359
+ children: "\u2715"
1360
+ }
1361
+ )
1362
+ ]
1363
+ },
1364
+ `${tag}-${i}`
1365
+ )),
1366
+ /* @__PURE__ */ jsxRuntime.jsx(
1367
+ "input",
1368
+ {
1369
+ ref: inputRef,
1370
+ id: inputId,
1371
+ type: "text",
1372
+ disabled: disabled || atMax,
1373
+ placeholder: value.length === 0 ? placeholder : void 0,
1374
+ "aria-invalid": !!error || void 0,
1375
+ "aria-describedby": errorId,
1376
+ onKeyDown: handleKeyDown,
1377
+ onPaste: handlePaste,
1378
+ onBlur: (e) => {
1379
+ if (e.target.value) {
1380
+ addTag(e.target.value);
1381
+ e.target.value = "";
1382
+ }
1383
+ },
1384
+ className: "flex-1 min-w-[120px] bg-transparent text-sm text-white outline-none placeholder-white/30 disabled:cursor-not-allowed"
1385
+ }
1386
+ )
1387
+ ]
1388
+ }
1389
+ );
1390
+ if (!label && !error) return wrapper;
1391
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1392
+ label && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: inputId, className: "block text-sm text-white/70 mb-1.5", children: label }),
1393
+ wrapper,
1394
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { id: errorId, className: "text-rose-400 text-xs mt-1", children: error })
1395
+ ] });
1396
+ }
1397
+ );
636
1398
  var base3 = "inline-flex items-center justify-center rounded-full font-semibold ring-1 ring-white/10";
637
- var sizeClass4 = {
1399
+ var sizeClass5 = {
638
1400
  sm: "text-xs px-2.5 py-1",
639
1401
  md: "text-sm px-3 py-1.5"
640
1402
  };
@@ -649,7 +1411,7 @@ var variantClass3 = {
649
1411
  accent: "bg-accent/15 text-accent-light ring-accent/20"
650
1412
  };
651
1413
  var Badge = React.forwardRef(function Badge2({ children, variant = "neutral", size = "sm", className, ...props }, ref) {
652
- return /* @__PURE__ */ jsxRuntime.jsx("span", { ref, ...props, className: cn(base3, sizeClass4[size], variantClass3[variant], className), children });
1414
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ref, ...props, className: cn(base3, sizeClass5[size], variantClass3[variant], className), children });
653
1415
  });
654
1416
  var Pill = Badge;
655
1417
  var trackSize = {
@@ -1099,7 +1861,7 @@ function RadioItem({ value, disabled: itemDisabled, children, className }) {
1099
1861
  }
1100
1862
  );
1101
1863
  }
1102
- var sizeClass5 = {
1864
+ var sizeClass6 = {
1103
1865
  sm: "h-3 w-3 border",
1104
1866
  md: "h-4 w-4 border-2",
1105
1867
  lg: "h-6 w-6 border-2"
@@ -1108,7 +1870,7 @@ function Spinner({ className, size = "md", label }) {
1108
1870
  return /* @__PURE__ */ jsxRuntime.jsx(
1109
1871
  "span",
1110
1872
  {
1111
- className: cn("inline-block rounded-full border-white/15 border-t-primary animate-spin", sizeClass5[size], className),
1873
+ className: cn("inline-block rounded-full border-white/15 border-t-primary animate-spin", sizeClass6[size], className),
1112
1874
  role: label ? "status" : void 0,
1113
1875
  "aria-hidden": label ? void 0 : "true",
1114
1876
  "aria-label": label || void 0
@@ -2028,93 +2790,203 @@ function Divider({ orientation = "horizontal", label, className }) {
2028
2790
  }
2029
2791
  );
2030
2792
  }
2031
- var Table = React.forwardRef(({ children, className }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl ring-1 ring-white/10 overflow-hidden bg-white/5", children: /* @__PURE__ */ jsxRuntime.jsx("table", { ref, className: cn("w-full text-sm text-white", className), children }) }));
2032
- Table.displayName = "Table";
2033
- var TableHeader = React.forwardRef(
2034
- ({ children, className }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: cn("bg-white/5 border-b border-white/10", className), children })
2035
- );
2036
- TableHeader.displayName = "TableHeader";
2037
- var TableBody = React.forwardRef(
2038
- ({ children, className }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: cn("divide-y divide-white/[0.06]", className), children })
2039
- );
2040
- TableBody.displayName = "TableBody";
2041
- var TableRow = React.forwardRef(
2042
- ({ children, className, hoverable }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2043
- "tr",
2044
- {
2045
- ref,
2046
- className: cn(hoverable && "hover:bg-white/[0.03] transition-colors", className),
2047
- children
2048
- }
2049
- )
2050
- );
2051
- TableRow.displayName = "TableRow";
2052
- var TableHead = React.forwardRef(
2053
- ({ children, className }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2054
- "th",
2793
+ var Table = React.forwardRef(function Table2({ children, className, ...props }, ref) {
2794
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl ring-1 ring-white/10 overflow-hidden bg-white/5", children: /* @__PURE__ */ jsxRuntime.jsx("table", { ref, className: cn("w-full text-sm text-white", className), ...props, children }) });
2795
+ });
2796
+ var TableHeader = React.forwardRef(function TableHeader2({ children, className, ...props }, ref) {
2797
+ return /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: cn("bg-white/5 border-b border-white/10", className), ...props, children });
2798
+ });
2799
+ var TableBody = React.forwardRef(function TableBody2({ children, className, ...props }, ref) {
2800
+ return /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: cn("divide-y divide-white/[0.06]", className), ...props, children });
2801
+ });
2802
+ var TableRow = React.forwardRef(function TableRow2({ children, className, hoverable, ...props }, ref) {
2803
+ return /* @__PURE__ */ jsxRuntime.jsx(
2804
+ "tr",
2805
+ {
2806
+ ref,
2807
+ className: cn(hoverable && "hover:bg-white/[0.03] transition-colors", className),
2808
+ ...props,
2809
+ children
2810
+ }
2811
+ );
2812
+ });
2813
+ var TableHead = React.forwardRef(function TableHead2({ children, className, ...props }, ref) {
2814
+ return /* @__PURE__ */ jsxRuntime.jsx(
2815
+ "th",
2816
+ {
2817
+ ref,
2818
+ className: cn(
2819
+ "px-4 py-3 text-left text-xs font-semibold text-white/50 uppercase tracking-wider",
2820
+ className
2821
+ ),
2822
+ ...props,
2823
+ children
2824
+ }
2825
+ );
2826
+ });
2827
+ var alignClass = {
2828
+ left: "text-left",
2829
+ center: "text-center",
2830
+ right: "text-right"
2831
+ };
2832
+ var TableCell = React.forwardRef(function TableCell2({ children, className, align = "left", ...props }, ref) {
2833
+ return /* @__PURE__ */ jsxRuntime.jsx("td", { ref, className: cn("px-4 py-3 text-white/80", alignClass[align], className), ...props, children });
2834
+ });
2835
+ var variantBorderColor = {
2836
+ info: "border-blue-500",
2837
+ success: "border-emerald-500",
2838
+ warning: "border-amber-500",
2839
+ error: "border-rose-500"
2840
+ };
2841
+ var variantIconColor = {
2842
+ info: "text-blue-400",
2843
+ success: "text-emerald-400",
2844
+ warning: "text-amber-400",
2845
+ error: "text-rose-400"
2846
+ };
2847
+ function InfoIcon() {
2848
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2849
+ "svg",
2850
+ {
2851
+ "aria-hidden": "true",
2852
+ width: "18",
2853
+ height: "18",
2854
+ viewBox: "0 0 18 18",
2855
+ fill: "none",
2856
+ xmlns: "http://www.w3.org/2000/svg",
2857
+ children: [
2858
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "9", r: "7.5", stroke: "currentColor", strokeWidth: "1.5" }),
2859
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 8v5", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" }),
2860
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "5.5", r: "0.875", fill: "currentColor" })
2861
+ ]
2862
+ }
2863
+ );
2864
+ }
2865
+ function SuccessIcon() {
2866
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2867
+ "svg",
2868
+ {
2869
+ "aria-hidden": "true",
2870
+ width: "18",
2871
+ height: "18",
2872
+ viewBox: "0 0 18 18",
2873
+ fill: "none",
2874
+ xmlns: "http://www.w3.org/2000/svg",
2875
+ children: [
2876
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "9", r: "7.5", stroke: "currentColor", strokeWidth: "1.5" }),
2877
+ /* @__PURE__ */ jsxRuntime.jsx(
2878
+ "path",
2879
+ {
2880
+ d: "M5.5 9.5l2.5 2.5 4.5-5",
2881
+ stroke: "currentColor",
2882
+ strokeWidth: "1.75",
2883
+ strokeLinecap: "round",
2884
+ strokeLinejoin: "round"
2885
+ }
2886
+ )
2887
+ ]
2888
+ }
2889
+ );
2890
+ }
2891
+ function WarningIcon() {
2892
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2893
+ "svg",
2894
+ {
2895
+ "aria-hidden": "true",
2896
+ width: "18",
2897
+ height: "18",
2898
+ viewBox: "0 0 18 18",
2899
+ fill: "none",
2900
+ xmlns: "http://www.w3.org/2000/svg",
2901
+ children: [
2902
+ /* @__PURE__ */ jsxRuntime.jsx(
2903
+ "path",
2904
+ {
2905
+ d: "M7.634 2.896a1.6 1.6 0 0 1 2.732 0l5.866 10.167A1.6 1.6 0 0 1 14.866 15.5H3.134a1.6 1.6 0 0 1-1.366-2.437L7.634 2.896Z",
2906
+ stroke: "currentColor",
2907
+ strokeWidth: "1.5",
2908
+ strokeLinejoin: "round"
2909
+ }
2910
+ ),
2911
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 7v4", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" }),
2912
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "12.5", r: "0.875", fill: "currentColor" })
2913
+ ]
2914
+ }
2915
+ );
2916
+ }
2917
+ function ErrorIcon() {
2918
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2919
+ "svg",
2055
2920
  {
2056
- ref,
2057
- className: cn(
2058
- "px-4 py-3 text-left text-xs font-semibold text-white/50 uppercase tracking-wider",
2059
- className
2060
- ),
2061
- children
2921
+ "aria-hidden": "true",
2922
+ width: "18",
2923
+ height: "18",
2924
+ viewBox: "0 0 18 18",
2925
+ fill: "none",
2926
+ xmlns: "http://www.w3.org/2000/svg",
2927
+ children: [
2928
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "9", r: "7.5", stroke: "currentColor", strokeWidth: "1.5" }),
2929
+ /* @__PURE__ */ jsxRuntime.jsx(
2930
+ "path",
2931
+ {
2932
+ d: "M6.5 6.5l5 5M11.5 6.5l-5 5",
2933
+ stroke: "currentColor",
2934
+ strokeWidth: "1.75",
2935
+ strokeLinecap: "round"
2936
+ }
2937
+ )
2938
+ ]
2062
2939
  }
2063
- )
2064
- );
2065
- TableHead.displayName = "TableHead";
2066
- var alignClass = {
2067
- left: "text-left",
2068
- center: "text-center",
2069
- right: "text-right"
2070
- };
2071
- var TableCell = React.forwardRef(
2072
- ({ children, className, align = "left" }, ref) => /* @__PURE__ */ jsxRuntime.jsx("td", { ref, className: cn("px-4 py-3 text-white/80", alignClass[align], className), children })
2073
- );
2074
- TableCell.displayName = "TableCell";
2075
- function TrendIndicator({ trend }) {
2076
- if (trend.value > 0) {
2077
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-emerald-400", children: [
2078
- /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: "w-3 h-3 shrink-0", fill: "none", viewBox: "0 0 12 12", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 9V3M3 6l3-3 3 3" }) }),
2079
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2080
- "+",
2081
- trend.value,
2082
- trend.label ? ` ${trend.label}` : ""
2083
- ] })
2084
- ] });
2085
- }
2086
- if (trend.value < 0) {
2087
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-rose-400", children: [
2088
- /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: "w-3 h-3 shrink-0", fill: "none", viewBox: "0 0 12 12", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 3v6M3 6l3 3 3-3" }) }),
2089
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2090
- trend.value,
2091
- trend.label ? ` ${trend.label}` : ""
2092
- ] })
2093
- ] });
2094
- }
2095
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-white/40", children: [
2096
- /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: "w-3 h-3 shrink-0", fill: "none", viewBox: "0 0 12 12", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M2 6h8" }) }),
2097
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2098
- trend.value,
2099
- trend.label ? ` ${trend.label}` : ""
2100
- ] })
2101
- ] });
2940
+ );
2102
2941
  }
2103
- function StatCard({ value, label, icon, trend, className }) {
2942
+ var variantIcon = {
2943
+ info: InfoIcon,
2944
+ success: SuccessIcon,
2945
+ warning: WarningIcon,
2946
+ error: ErrorIcon
2947
+ };
2948
+ function Alert({ variant = "info", title, children, onDismiss, className }) {
2949
+ const Icon = variantIcon[variant];
2104
2950
  return /* @__PURE__ */ jsxRuntime.jsxs(
2105
2951
  "div",
2106
2952
  {
2953
+ role: "alert",
2107
2954
  className: cn(
2108
- "glass rounded-xl p-4 flex items-start gap-3",
2955
+ "flex items-start gap-3 rounded-xl bg-white/5 ring-1 ring-white/10",
2956
+ "border-l-4 pl-4 pr-3 py-3",
2957
+ variantBorderColor[variant],
2109
2958
  className
2110
2959
  ),
2111
2960
  children: [
2112
- icon != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-lg bg-white/10 flex items-center justify-center text-primary shrink-0", children: icon }),
2113
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [
2114
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl font-bold text-white tabular-nums leading-none", children: value }),
2115
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-white/50 truncate", children: label }),
2116
- trend != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(TrendIndicator, { trend }) })
2117
- ] })
2961
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("mt-0.5 shrink-0", variantIconColor[variant]), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {}) }),
2962
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
2963
+ title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-white leading-snug mb-0.5", children: title }),
2964
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-white/70 leading-relaxed", children })
2965
+ ] }),
2966
+ onDismiss && /* @__PURE__ */ jsxRuntime.jsx(
2967
+ "button",
2968
+ {
2969
+ type: "button",
2970
+ "aria-label": "Dismiss",
2971
+ onClick: onDismiss,
2972
+ className: cn(
2973
+ "shrink-0 flex items-center justify-center h-6 w-6 rounded-lg mt-0.5",
2974
+ "text-white/40 transition-colors hover:bg-white/10 hover:text-white/80",
2975
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40"
2976
+ ),
2977
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2978
+ "svg",
2979
+ {
2980
+ "aria-hidden": "true",
2981
+ width: "10",
2982
+ height: "10",
2983
+ viewBox: "0 0 10 10",
2984
+ fill: "none",
2985
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 1l8 8M9 1L1 9", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
2986
+ }
2987
+ )
2988
+ }
2989
+ )
2118
2990
  ]
2119
2991
  }
2120
2992
  );
@@ -2250,6 +3122,567 @@ function Pagination({
2250
3122
  }
2251
3123
  );
2252
3124
  }
3125
+ function useControllableState(controlledValue, defaultValue, onChange) {
3126
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
3127
+ const value = controlledValue ?? internalValue;
3128
+ const setValue = (nextValue) => {
3129
+ const resolvedValue = typeof nextValue === "function" ? nextValue(value) : nextValue;
3130
+ if (controlledValue === void 0) {
3131
+ setInternalValue(resolvedValue);
3132
+ }
3133
+ onChange?.(resolvedValue);
3134
+ };
3135
+ return [value, setValue];
3136
+ }
3137
+ function startOfDay2(date) {
3138
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
3139
+ }
3140
+ function endOfDay(date) {
3141
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);
3142
+ }
3143
+ function isDateRangeValue(value) {
3144
+ return typeof value === "object" && value !== null && "from" in value && "to" in value;
3145
+ }
3146
+ function hasActiveDateRange(range) {
3147
+ return range.from !== null || range.to !== null;
3148
+ }
3149
+ function isFilterValueActive(value) {
3150
+ if (value == null) return false;
3151
+ if (typeof value === "string") return value.trim() !== "";
3152
+ if (Array.isArray(value)) return value.length > 0;
3153
+ if (isDateRangeValue(value)) return hasActiveDateRange(value);
3154
+ return true;
3155
+ }
3156
+ function getColumnValue(column, row) {
3157
+ if (column.accessorFn) {
3158
+ return column.accessorFn(row);
3159
+ }
3160
+ if (column.accessorKey) {
3161
+ return row[column.accessorKey];
3162
+ }
3163
+ return void 0;
3164
+ }
3165
+ function coerceDate(value) {
3166
+ if (value instanceof Date && !Number.isNaN(value.getTime())) {
3167
+ return value;
3168
+ }
3169
+ if (typeof value === "string" || typeof value === "number") {
3170
+ const parsed = new Date(value);
3171
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
3172
+ }
3173
+ return null;
3174
+ }
3175
+ function compareValues(left, right) {
3176
+ if (left == null && right == null) return 0;
3177
+ if (left == null) return 1;
3178
+ if (right == null) return -1;
3179
+ if (left instanceof Date || right instanceof Date) {
3180
+ const leftDate = coerceDate(left);
3181
+ const rightDate = coerceDate(right);
3182
+ if (!leftDate && !rightDate) return 0;
3183
+ if (!leftDate) return 1;
3184
+ if (!rightDate) return -1;
3185
+ return leftDate.getTime() - rightDate.getTime();
3186
+ }
3187
+ if (typeof left === "number" && typeof right === "number") {
3188
+ return left - right;
3189
+ }
3190
+ return String(left).localeCompare(String(right), void 0, {
3191
+ numeric: true,
3192
+ sensitivity: "base"
3193
+ });
3194
+ }
3195
+ function matchColumnFilter(column, row, filterValue) {
3196
+ if (!isFilterValueActive(filterValue)) {
3197
+ return true;
3198
+ }
3199
+ const rawValue = getColumnValue(column, row);
3200
+ if (column.filterFn) {
3201
+ return column.filterFn(rawValue, row, filterValue);
3202
+ }
3203
+ if (typeof column.filter === "function") {
3204
+ return true;
3205
+ }
3206
+ switch (column.filter) {
3207
+ case "select":
3208
+ case "boolean":
3209
+ return String(rawValue ?? "") === String(filterValue);
3210
+ case "date-range": {
3211
+ if (!isDateRangeValue(filterValue)) return true;
3212
+ const dateValue = coerceDate(rawValue);
3213
+ if (!dateValue) return false;
3214
+ if (filterValue.from && dateValue < startOfDay2(filterValue.from)) return false;
3215
+ if (filterValue.to && dateValue > endOfDay(filterValue.to)) return false;
3216
+ return true;
3217
+ }
3218
+ case "text":
3219
+ default:
3220
+ return String(rawValue ?? "").toLowerCase().includes(String(filterValue).trim().toLowerCase());
3221
+ }
3222
+ }
3223
+ function defaultResultsLabel(meta) {
3224
+ return `Showing ${meta.from} - ${meta.to} of ${meta.total}`;
3225
+ }
3226
+ function SortIndicator({ active, desc }) {
3227
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("inline-flex flex-col text-[10px] leading-none", active ? "text-white" : "text-white/25"), children: [
3228
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: cn("h-2.5 w-2.5", active && !desc && "text-primary"), viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4.5 9.5 8 6l3.5 3.5", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) }),
3229
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: cn("h-2.5 w-2.5 -mt-0.5", active && desc && "text-primary"), viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4.5 6.5 8 10l3.5-3.5", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) })
3230
+ ] });
3231
+ }
3232
+ function DataTable({
3233
+ data,
3234
+ columns,
3235
+ caption,
3236
+ searchValue,
3237
+ defaultSearchValue = "",
3238
+ onSearchValueChange,
3239
+ searchPlaceholder = "Search records...",
3240
+ enableSearch,
3241
+ sortBy,
3242
+ defaultSortBy = null,
3243
+ onSortChange,
3244
+ filters,
3245
+ defaultFilters = {},
3246
+ onFiltersChange,
3247
+ showFilters,
3248
+ defaultShowFilters = false,
3249
+ onShowFiltersChange,
3250
+ page,
3251
+ defaultPage = 1,
3252
+ onPageChange,
3253
+ pageSize,
3254
+ defaultPageSize = 25,
3255
+ onPageSizeChange,
3256
+ pageSizeOptions = [25, 50, 100],
3257
+ totalItems,
3258
+ loading,
3259
+ loadingRows = 5,
3260
+ error,
3261
+ onRetry,
3262
+ emptyState,
3263
+ emptyTitle = "Nothing to show yet",
3264
+ emptyDescription = "No rows matched the current filters.",
3265
+ filterToggleLabel = "Filters",
3266
+ clearFiltersLabel = "Clear",
3267
+ pageSizeLabel = "Rows",
3268
+ resultsLabel = defaultResultsLabel,
3269
+ toolbarActions,
3270
+ stickyHeader,
3271
+ dense,
3272
+ className,
3273
+ manualSorting,
3274
+ manualFiltering,
3275
+ manualPagination,
3276
+ onRowClick,
3277
+ rowHref,
3278
+ getRowId,
3279
+ getRowClassName
3280
+ }) {
3281
+ const visibleColumns = React.useMemo(() => columns.filter((column) => !column.hidden), [columns]);
3282
+ const [currentSearch, setCurrentSearch] = useControllableState(searchValue, defaultSearchValue, onSearchValueChange);
3283
+ const [currentSort, setCurrentSort] = useControllableState(sortBy, defaultSortBy, onSortChange);
3284
+ const [currentFilters, setCurrentFilters] = useControllableState(filters, defaultFilters, onFiltersChange);
3285
+ const [filtersVisible, setFiltersVisible] = useControllableState(showFilters, defaultShowFilters, onShowFiltersChange);
3286
+ const [currentPage, setCurrentPage] = useControllableState(page, defaultPage, onPageChange);
3287
+ const [currentPageSize, setCurrentPageSize] = useControllableState(pageSize, defaultPageSize, onPageSizeChange);
3288
+ const hasSearchControl = enableSearch || searchValue !== void 0 || defaultSearchValue !== "";
3289
+ const searchTerm = currentSearch.trim().toLowerCase();
3290
+ const searchableColumns = React.useMemo(
3291
+ () => visibleColumns.filter((column) => column.searchable !== false),
3292
+ [visibleColumns]
3293
+ );
3294
+ const filteredRows = React.useMemo(() => {
3295
+ if (manualFiltering) {
3296
+ return data;
3297
+ }
3298
+ return data.filter((row) => {
3299
+ const matchesSearch = !searchTerm || searchableColumns.some((column) => {
3300
+ const value = getColumnValue(column, row);
3301
+ return String(value ?? "").toLowerCase().includes(searchTerm);
3302
+ });
3303
+ if (!matchesSearch) {
3304
+ return false;
3305
+ }
3306
+ return visibleColumns.every((column) => matchColumnFilter(column, row, currentFilters[column.id]));
3307
+ });
3308
+ }, [currentFilters, data, manualFiltering, searchTerm, searchableColumns, visibleColumns]);
3309
+ const sortedRows = React.useMemo(() => {
3310
+ if (manualSorting || currentSort == null) {
3311
+ return filteredRows;
3312
+ }
3313
+ const sortColumn = visibleColumns.find((column) => column.id === currentSort.id);
3314
+ if (!sortColumn) {
3315
+ return filteredRows;
3316
+ }
3317
+ return [...filteredRows].sort((left, right) => {
3318
+ const result = compareValues(getColumnValue(sortColumn, left), getColumnValue(sortColumn, right));
3319
+ return currentSort.desc ? -result : result;
3320
+ });
3321
+ }, [currentSort, filteredRows, manualSorting, visibleColumns]);
3322
+ const derivedTotalItems = manualPagination ? totalItems ?? data.length : sortedRows.length;
3323
+ const totalPages = Math.max(1, Math.ceil(derivedTotalItems / currentPageSize));
3324
+ React.useEffect(() => {
3325
+ if (currentPage > totalPages) {
3326
+ setCurrentPage(totalPages);
3327
+ }
3328
+ }, [currentPage, setCurrentPage, totalPages]);
3329
+ const pagedRows = React.useMemo(() => {
3330
+ if (manualPagination) {
3331
+ return data;
3332
+ }
3333
+ const startIndex = (currentPage - 1) * currentPageSize;
3334
+ return sortedRows.slice(startIndex, startIndex + currentPageSize);
3335
+ }, [currentPage, currentPageSize, data, manualPagination, sortedRows]);
3336
+ const activeFilterCount = React.useMemo(
3337
+ () => Object.values(currentFilters).filter(isFilterValueActive).length + (searchTerm ? 1 : 0),
3338
+ [currentFilters, searchTerm]
3339
+ );
3340
+ const from = derivedTotalItems === 0 ? 0 : (currentPage - 1) * currentPageSize + 1;
3341
+ const to = derivedTotalItems === 0 ? 0 : manualPagination ? Math.min(from + pagedRows.length - 1, derivedTotalItems) : Math.min(currentPage * currentPageSize, derivedTotalItems);
3342
+ const handleSortToggle = (column) => {
3343
+ if (!column.sortable) return;
3344
+ setCurrentPage(1);
3345
+ setCurrentSort((previousSort) => {
3346
+ if (!previousSort || previousSort.id !== column.id) {
3347
+ return { id: column.id, desc: Boolean(column.sortDescFirst) };
3348
+ }
3349
+ if (previousSort.desc === Boolean(column.sortDescFirst)) {
3350
+ return { id: column.id, desc: !previousSort.desc };
3351
+ }
3352
+ return null;
3353
+ });
3354
+ };
3355
+ const handleFilterChange = (columnId, value) => {
3356
+ setCurrentPage(1);
3357
+ setCurrentFilters((previousFilters) => ({
3358
+ ...previousFilters,
3359
+ [columnId]: value
3360
+ }));
3361
+ };
3362
+ const handleClear = () => {
3363
+ setCurrentSearch("");
3364
+ setCurrentPage(1);
3365
+ setCurrentFilters({});
3366
+ };
3367
+ const handlePageSizeChange = (value) => {
3368
+ setCurrentPage(1);
3369
+ setCurrentPageSize(value);
3370
+ };
3371
+ const handleRowActivate = (row) => {
3372
+ onRowClick?.(row);
3373
+ const href = rowHref?.(row);
3374
+ if (href && typeof window !== "undefined") {
3375
+ window.location.assign(href);
3376
+ }
3377
+ };
3378
+ const renderFilterControl = (column) => {
3379
+ const filterValue = currentFilters[column.id];
3380
+ if (typeof column.filter === "function") {
3381
+ return column.filter({
3382
+ column,
3383
+ value: filterValue,
3384
+ onChange: (value) => handleFilterChange(column.id, value),
3385
+ data
3386
+ });
3387
+ }
3388
+ switch (column.filter) {
3389
+ case "select":
3390
+ case "boolean":
3391
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3392
+ "select",
3393
+ {
3394
+ "aria-label": `Filter ${typeof column.header === "string" ? column.header : column.id}`,
3395
+ value: typeof filterValue === "string" ? filterValue : "",
3396
+ onChange: (event) => handleFilterChange(column.id, event.target.value),
3397
+ className: "w-full rounded-lg border border-white/10 bg-white/5 px-2.5 py-2 text-sm text-white outline-none focus-visible:ring-2 focus-visible:ring-primary/40",
3398
+ children: [
3399
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "All" }),
3400
+ column.filterOptions?.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option.value, children: option.label }, option.value))
3401
+ ]
3402
+ }
3403
+ );
3404
+ case "date-range":
3405
+ return /* @__PURE__ */ jsxRuntime.jsx(
3406
+ DateRangePicker,
3407
+ {
3408
+ compact: true,
3409
+ value: isDateRangeValue(filterValue) ? filterValue : { from: null, to: null },
3410
+ onChange: (range) => handleFilterChange(column.id, range),
3411
+ placeholder: { trigger: "Any date" }
3412
+ }
3413
+ );
3414
+ case "text":
3415
+ default:
3416
+ return /* @__PURE__ */ jsxRuntime.jsx(
3417
+ "input",
3418
+ {
3419
+ "aria-label": `Filter ${typeof column.header === "string" ? column.header : column.id}`,
3420
+ type: "text",
3421
+ value: typeof filterValue === "string" ? filterValue : "",
3422
+ onChange: (event) => handleFilterChange(column.id, event.target.value),
3423
+ className: "w-full rounded-lg border border-white/10 bg-white/5 px-2.5 py-2 text-sm text-white outline-none placeholder:text-white/25 focus-visible:ring-2 focus-visible:ring-primary/40",
3424
+ placeholder: "Filter..."
3425
+ }
3426
+ );
3427
+ }
3428
+ };
3429
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-4", className), children: [
3430
+ hasSearchControl || toolbarActions || visibleColumns.some((column) => column.filter) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between", children: [
3431
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
3432
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm text-white/60", children: [
3433
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: pageSizeLabel }),
3434
+ /* @__PURE__ */ jsxRuntime.jsx(
3435
+ "select",
3436
+ {
3437
+ "aria-label": "Rows per page",
3438
+ value: currentPageSize,
3439
+ onChange: (event) => handlePageSizeChange(Number(event.target.value)),
3440
+ className: "rounded-lg border border-white/10 bg-white/5 px-2.5 py-2 text-sm text-white outline-none focus-visible:ring-2 focus-visible:ring-primary/40",
3441
+ children: pageSizeOptions.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option, children: option }, option))
3442
+ }
3443
+ )
3444
+ ] }),
3445
+ visibleColumns.some((column) => column.filter) ? /* @__PURE__ */ jsxRuntime.jsxs(
3446
+ Button,
3447
+ {
3448
+ size: "sm",
3449
+ variant: filtersVisible ? "secondary" : "ghost",
3450
+ onClick: () => setFiltersVisible((previousValue) => !previousValue),
3451
+ children: [
3452
+ filterToggleLabel,
3453
+ activeFilterCount > 0 ? ` (${activeFilterCount})` : ""
3454
+ ]
3455
+ }
3456
+ ) : null,
3457
+ activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "ghost", onClick: handleClear, children: clearFiltersLabel }) : null
3458
+ ] }),
3459
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-end", children: [
3460
+ hasSearchControl ? /* @__PURE__ */ jsxRuntime.jsx(
3461
+ SearchInput,
3462
+ {
3463
+ value: currentSearch,
3464
+ onChange: (event) => {
3465
+ setCurrentPage(1);
3466
+ setCurrentSearch(event.target.value);
3467
+ },
3468
+ onClear: () => {
3469
+ setCurrentPage(1);
3470
+ setCurrentSearch("");
3471
+ },
3472
+ placeholder: searchPlaceholder,
3473
+ className: "min-w-[16rem]"
3474
+ }
3475
+ ) : null,
3476
+ toolbarActions
3477
+ ] })
3478
+ ] }) : null,
3479
+ error ? /* @__PURE__ */ jsxRuntime.jsx(Alert, { variant: "error", title: "Unable to load table data", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
3480
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: error }),
3481
+ onRetry ? /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "secondary", onClick: onRetry, children: "Retry" }) : null
3482
+ ] }) }) : null,
3483
+ /* @__PURE__ */ jsxRuntime.jsxs(Table, { className: "min-w-full", children: [
3484
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
3485
+ /* @__PURE__ */ jsxRuntime.jsxs(TableHeader, { children: [
3486
+ /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: visibleColumns.map((column) => {
3487
+ const sorted = currentSort?.id === column.id ? currentSort : null;
3488
+ const ariaSort = column.sortable ? sorted ? sorted.desc ? "descending" : "ascending" : "none" : void 0;
3489
+ return /* @__PURE__ */ jsxRuntime.jsx(
3490
+ TableHead,
3491
+ {
3492
+ className: cn(
3493
+ stickyHeader && "sticky top-0 z-10 bg-[#121420] backdrop-blur-sm",
3494
+ column.headerClassName
3495
+ ),
3496
+ style: { width: column.width, minWidth: column.minWidth },
3497
+ "aria-sort": ariaSort,
3498
+ children: column.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
3499
+ "button",
3500
+ {
3501
+ type: "button",
3502
+ onClick: () => handleSortToggle(column),
3503
+ className: "flex w-full items-center gap-2 text-left transition-colors hover:text-white",
3504
+ children: [
3505
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: typeof column.header === "function" ? column.header({ column, sort: sorted }) : column.header }),
3506
+ /* @__PURE__ */ jsxRuntime.jsx(SortIndicator, { active: sorted !== null, desc: sorted?.desc })
3507
+ ]
3508
+ }
3509
+ ) : typeof column.header === "function" ? column.header({ column, sort: sorted }) : column.header
3510
+ },
3511
+ column.id
3512
+ );
3513
+ }) }),
3514
+ filtersVisible ? /* @__PURE__ */ jsxRuntime.jsx(TableRow, { className: "bg-white/[0.025]", children: visibleColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(
3515
+ TableHead,
3516
+ {
3517
+ className: "normal-case text-white/70 tracking-normal",
3518
+ style: { width: column.width, minWidth: column.minWidth },
3519
+ children: column.filter ? renderFilterControl(column) : null
3520
+ },
3521
+ `${column.id}-filter`
3522
+ )) }) : null
3523
+ ] }),
3524
+ /* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: loading ? Array.from({ length: loadingRows }).map((_, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: visibleColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: dense ? "py-2" : void 0, align: column.align, children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: cn(column.align === "right" ? "ml-auto" : "", "h-5 w-full max-w-[12rem]") }) }, `${column.id}-${rowIndex}`)) }, `loading-${rowIndex}`)) : pagedRows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx(TableCell, { colSpan: visibleColumns.length, className: "py-10", align: "center", children: emptyState ?? /* @__PURE__ */ jsxRuntime.jsx(
3525
+ EmptyState,
3526
+ {
3527
+ title: emptyTitle,
3528
+ description: emptyDescription
3529
+ }
3530
+ ) }) }) : pagedRows.map((row, rowIndex) => {
3531
+ const key = getRowId?.(row, rowIndex) ?? String(rowIndex);
3532
+ const href = rowHref?.(row);
3533
+ const interactive = Boolean(onRowClick || href);
3534
+ return /* @__PURE__ */ jsxRuntime.jsx(
3535
+ TableRow,
3536
+ {
3537
+ hoverable: interactive,
3538
+ className: cn(
3539
+ dense && "[&>td]:py-2",
3540
+ interactive && "cursor-pointer",
3541
+ getRowClassName?.(row, rowIndex)
3542
+ ),
3543
+ ...interactive ? {
3544
+ tabIndex: 0,
3545
+ onClick: () => handleRowActivate(row),
3546
+ onKeyDown: (event) => {
3547
+ if (event.key === "Enter" || event.key === " ") {
3548
+ event.preventDefault();
3549
+ handleRowActivate(row);
3550
+ }
3551
+ }
3552
+ } : {},
3553
+ children: visibleColumns.map((column) => {
3554
+ const value = getColumnValue(column, row);
3555
+ return /* @__PURE__ */ jsxRuntime.jsx(
3556
+ TableCell,
3557
+ {
3558
+ align: column.align,
3559
+ className: column.className,
3560
+ children: column.cell ? column.cell({ row, value, rowIndex, column }) : value == null ? "\u2014" : String(value)
3561
+ },
3562
+ column.id
3563
+ );
3564
+ })
3565
+ },
3566
+ key
3567
+ );
3568
+ }) })
3569
+ ] }),
3570
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 border-t border-white/10 pt-3 sm:flex-row sm:items-center sm:justify-between", children: [
3571
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-white/50", children: resultsLabel({ from, to, total: derivedTotalItems }) }),
3572
+ /* @__PURE__ */ jsxRuntime.jsx(Pagination, { page: currentPage, totalPages, onPageChange: (nextPage) => setCurrentPage(nextPage) })
3573
+ ] })
3574
+ ] });
3575
+ }
3576
+ var sizeStyles = {
3577
+ sm: "p-3 gap-3",
3578
+ md: "p-4 gap-3",
3579
+ lg: "p-5 gap-4"
3580
+ };
3581
+ var valueStyles = {
3582
+ sm: "text-xl",
3583
+ md: "text-2xl",
3584
+ lg: "text-3xl"
3585
+ };
3586
+ var labelStyles = {
3587
+ sm: "text-[11px] uppercase tracking-[0.16em]",
3588
+ md: "text-sm",
3589
+ lg: "text-sm uppercase tracking-[0.18em]"
3590
+ };
3591
+ var iconStyles = {
3592
+ sm: "h-9 w-9 rounded-xl text-sm",
3593
+ md: "h-10 w-10 rounded-xl text-base",
3594
+ lg: "h-11 w-11 rounded-2xl text-base"
3595
+ };
3596
+ function getSignedValue(value) {
3597
+ if (value > 0) return `+${value}`;
3598
+ return `${value}`;
3599
+ }
3600
+ function getValueColorClass(valueColor, value) {
3601
+ if (valueColor === "default") return "text-white";
3602
+ if (valueColor === "success") return "text-emerald-400";
3603
+ if (valueColor === "danger") return "text-rose-400";
3604
+ if (valueColor === "warning") return "text-amber-400";
3605
+ const raw = typeof value === "number" ? value : Number(String(value).replace(/[%,$\s]/g, ""));
3606
+ if (!Number.isNaN(raw)) {
3607
+ if (raw > 0) return "text-emerald-400";
3608
+ if (raw < 0) return "text-rose-400";
3609
+ }
3610
+ const trimmed = String(value).trim();
3611
+ if (trimmed.startsWith("+")) return "text-emerald-400";
3612
+ if (trimmed.startsWith("-")) return "text-rose-400";
3613
+ return "text-white";
3614
+ }
3615
+ function TrendIndicator({ trend }) {
3616
+ const tone = trend.value > 0 ? "text-emerald-400" : trend.value < 0 ? "text-rose-400" : "text-white/40";
3617
+ const icon = trend.value > 0 ? /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 9V3M3 6l3-3 3 3" }) : trend.value < 0 ? /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 3v6M3 6l3 3 3-3" }) : /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M2 6h8" });
3618
+ const text = trend.format ? trend.format({ value: trend.value, percentValue: trend.percentValue }) : `${getSignedValue(trend.value)}${trend.percentValue != null ? ` (${getSignedValue(trend.percentValue)}%)` : ""}${trend.label ? ` ${trend.label}` : ""}`;
3619
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("inline-flex items-center gap-1 text-xs", tone), children: [
3620
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: "h-3 w-3 shrink-0", fill: "none", viewBox: "0 0 12 12", stroke: "currentColor", strokeWidth: 2, children: icon }),
3621
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: text })
3622
+ ] });
3623
+ }
3624
+ function MetricContent({ value, label, trend, size, valueColor }) {
3625
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-1", children: [
3626
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("block font-bold leading-none tabular-nums", valueStyles[size], getValueColorClass(valueColor, value)), children: value }),
3627
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("block truncate text-white/55", labelStyles[size]), children: label }),
3628
+ trend ? /* @__PURE__ */ jsxRuntime.jsx(TrendIndicator, { trend }) : null
3629
+ ] });
3630
+ }
3631
+ function ChevronIcon2() {
3632
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", className: "h-4 w-4", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 5l5 5-5 5", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) });
3633
+ }
3634
+ function StatCard({
3635
+ value,
3636
+ label,
3637
+ icon,
3638
+ trend,
3639
+ size = "md",
3640
+ valueColor = "default",
3641
+ href,
3642
+ onClick,
3643
+ loading,
3644
+ secondaryMetric,
3645
+ className
3646
+ }) {
3647
+ const clickable = Boolean(href || onClick);
3648
+ const rootClassName = cn(
3649
+ "glass rounded-xl transition-[transform,background-color,box-shadow,ring-color]",
3650
+ sizeStyles[size],
3651
+ clickable && "group hover:bg-white/[0.08] hover:-translate-y-0.5 hover:shadow-lg hover:shadow-black/20",
3652
+ className
3653
+ );
3654
+ const content = loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-start gap-3", children: [
3655
+ icon ? /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: cn(iconStyles[size]) }) : null,
3656
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [
3657
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: cn("h-7 max-w-[8rem]", size === "lg" && "h-8 max-w-[10rem]") }),
3658
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-4 max-w-[11rem]" }),
3659
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-3 max-w-[9rem]" })
3660
+ ] })
3661
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3662
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0 bg-white/10 flex items-center justify-center text-primary", iconStyles[size]), children: icon }) : null,
3663
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
3664
+ /* @__PURE__ */ jsxRuntime.jsx(MetricContent, { value, label, trend, size, valueColor }),
3665
+ secondaryMetric ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 border-t border-white/10 pt-4", children: /* @__PURE__ */ jsxRuntime.jsx(
3666
+ MetricContent,
3667
+ {
3668
+ value: secondaryMetric.value,
3669
+ label: secondaryMetric.label,
3670
+ trend: secondaryMetric.trend,
3671
+ size: size === "lg" ? "md" : size,
3672
+ valueColor: "default"
3673
+ }
3674
+ ) }) : null
3675
+ ] }),
3676
+ clickable ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 shrink-0 text-white/35 transition-colors group-hover:text-white/70", children: /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon2, {}) }) : null
3677
+ ] });
3678
+ if (href) {
3679
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href, className: cn("flex items-start", rootClassName), children: content });
3680
+ }
3681
+ if (onClick) {
3682
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick, className: cn("flex w-full items-start text-left", rootClassName), children: content });
3683
+ }
3684
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-start", rootClassName), children: content });
3685
+ }
2253
3686
  function Stepper({ steps, activeStep, className }) {
2254
3687
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-start w-full", className), children: steps.map((step, index) => {
2255
3688
  const isCompleted = index < activeStep;
@@ -2582,8 +4015,221 @@ function DotIndicator({
2582
4015
  );
2583
4016
  })
2584
4017
  }
2585
- ),
2586
- showLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-xs font-medium tabular-nums", urgency.label), children: label })
4018
+ ),
4019
+ showLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-xs font-medium tabular-nums", urgency.label), children: label })
4020
+ ] });
4021
+ }
4022
+ var toneClass = {
4023
+ default: "text-white/55 bg-white/[0.04] ring-white/10",
4024
+ primary: "text-primary bg-primary/10 ring-primary/20",
4025
+ success: "text-emerald-400 bg-emerald-500/10 ring-emerald-500/20",
4026
+ warning: "text-amber-400 bg-amber-500/10 ring-amber-500/20",
4027
+ danger: "text-rose-400 bg-rose-500/10 ring-rose-500/20",
4028
+ accent: "text-accent-light bg-accent/10 ring-accent/20"
4029
+ };
4030
+ var variantStyles = {
4031
+ default: {
4032
+ gap: "gap-4",
4033
+ icon: "h-10 w-10 text-sm",
4034
+ textGap: "gap-2"
4035
+ },
4036
+ compact: {
4037
+ gap: "gap-3",
4038
+ icon: "h-8 w-8 text-xs",
4039
+ textGap: "gap-1.5"
4040
+ }
4041
+ };
4042
+ function toDate(value) {
4043
+ if (!value) return null;
4044
+ if (value instanceof Date) {
4045
+ return Number.isNaN(value.getTime()) ? null : value;
4046
+ }
4047
+ const parsed = new Date(value);
4048
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
4049
+ }
4050
+ function formatTimestamp(value) {
4051
+ return new Intl.DateTimeFormat(void 0, {
4052
+ year: "numeric",
4053
+ month: "2-digit",
4054
+ day: "2-digit",
4055
+ hour: "2-digit",
4056
+ minute: "2-digit",
4057
+ second: "2-digit"
4058
+ }).format(value);
4059
+ }
4060
+ function formatGroupHeader(value, groupBy) {
4061
+ if (groupBy === "day") {
4062
+ return new Intl.DateTimeFormat(void 0, {
4063
+ year: "numeric",
4064
+ month: "long",
4065
+ day: "numeric"
4066
+ }).format(value);
4067
+ }
4068
+ if (groupBy === "month") {
4069
+ return new Intl.DateTimeFormat(void 0, {
4070
+ year: "numeric",
4071
+ month: "long"
4072
+ }).format(value);
4073
+ }
4074
+ return new Intl.DateTimeFormat(void 0, {
4075
+ year: "numeric"
4076
+ }).format(value);
4077
+ }
4078
+ function getGroupKey(value, groupBy) {
4079
+ const year = value.getFullYear();
4080
+ const month = String(value.getMonth() + 1).padStart(2, "0");
4081
+ const day = String(value.getDate()).padStart(2, "0");
4082
+ if (groupBy === "year") return `${year}`;
4083
+ if (groupBy === "month") return `${year}-${month}`;
4084
+ return `${year}-${month}-${day}`;
4085
+ }
4086
+ function DefaultIcon() {
4087
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-2.5 w-2.5 rounded-full bg-current", "aria-hidden": "true" });
4088
+ }
4089
+ function getToneStyle(iconColor) {
4090
+ if (!iconColor || iconColor in toneClass) {
4091
+ const tone = iconColor ?? "default";
4092
+ return { className: toneClass[tone] };
4093
+ }
4094
+ return {
4095
+ className: "bg-white/[0.04] ring-white/10",
4096
+ style: { color: iconColor }
4097
+ };
4098
+ }
4099
+ function getLineClass(lineStyle) {
4100
+ if (lineStyle === "dashed") {
4101
+ return "border-l border-dashed border-white/10";
4102
+ }
4103
+ if (lineStyle === "solid") {
4104
+ return "border-l border-white/10";
4105
+ }
4106
+ return "border-l border-transparent";
4107
+ }
4108
+ function LoadingTimeline({ variant }) {
4109
+ const styles = variantStyles[variant];
4110
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: Array.from({ length: 4 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-start", styles.gap), children: [
4111
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex w-10 shrink-0 justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { circle: true, className: styles.icon }) }),
4112
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [
4113
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-4 max-w-[12rem]" }),
4114
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-5 max-w-[14rem]" }),
4115
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-4 max-w-[18rem]" })
4116
+ ] })
4117
+ ] }, index)) });
4118
+ }
4119
+ function Timeline({
4120
+ events,
4121
+ timestampFormatter = formatTimestamp,
4122
+ timestampPosition = "above",
4123
+ groupBy = "none",
4124
+ groupHeaderFormatter = formatGroupHeader,
4125
+ variant = "default",
4126
+ lineStyle = "solid",
4127
+ order = "asc",
4128
+ maxVisible,
4129
+ onLoadMore,
4130
+ hasMore,
4131
+ loading,
4132
+ emptyState,
4133
+ className
4134
+ }) {
4135
+ const styles = variantStyles[variant];
4136
+ const orderedEvents = React.useMemo(() => {
4137
+ const nextEvents = [...events].map((event, index) => ({
4138
+ event,
4139
+ index,
4140
+ timestamp: toDate(event.timestamp)
4141
+ }));
4142
+ nextEvents.sort((left, right) => {
4143
+ const leftTime = left.timestamp?.getTime();
4144
+ const rightTime = right.timestamp?.getTime();
4145
+ if (leftTime == null && rightTime == null) return left.index - right.index;
4146
+ if (leftTime == null) return 1;
4147
+ if (rightTime == null) return -1;
4148
+ return order === "asc" ? leftTime - rightTime : rightTime - leftTime;
4149
+ });
4150
+ return nextEvents.map((entry) => entry.event);
4151
+ }, [events, order]);
4152
+ const visibleEvents = maxVisible ? orderedEvents.slice(0, maxVisible) : orderedEvents;
4153
+ const groupedEvents = React.useMemo(() => {
4154
+ if (groupBy === "none") {
4155
+ return [{ key: "all", date: null, items: visibleEvents }];
4156
+ }
4157
+ const groups = /* @__PURE__ */ new Map();
4158
+ visibleEvents.forEach((event) => {
4159
+ const timestamp = toDate(event.timestamp);
4160
+ const key = timestamp ? getGroupKey(timestamp, groupBy) : "ungrouped";
4161
+ const existing = groups.get(key);
4162
+ if (existing) {
4163
+ existing.items.push(event);
4164
+ return;
4165
+ }
4166
+ groups.set(key, {
4167
+ key,
4168
+ date: timestamp,
4169
+ items: [event]
4170
+ });
4171
+ });
4172
+ return Array.from(groups.values());
4173
+ }, [groupBy, visibleEvents]);
4174
+ const showLoadMore = Boolean(onLoadMore) && (hasMore ?? orderedEvents.length > visibleEvents.length);
4175
+ if (loading) {
4176
+ return /* @__PURE__ */ jsxRuntime.jsx(LoadingTimeline, { variant });
4177
+ }
4178
+ if (visibleEvents.length === 0) {
4179
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: emptyState ?? /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: "No events yet", description: "Timeline entries will appear here once activity starts." }) });
4180
+ }
4181
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-6", className), children: [
4182
+ groupedEvents.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
4183
+ groupBy !== "none" && group.date ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.18em] text-white/35", children: groupHeaderFormatter(group.date, groupBy) }) : null,
4184
+ /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "space-y-4", children: group.items.map((event, index) => {
4185
+ const timestamp = toDate(event.timestamp);
4186
+ const tone = getToneStyle(event.iconColor);
4187
+ const isLast = index === group.items.length - 1;
4188
+ const timestampNode = timestamp ? /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: timestamp.toISOString(), className: "text-xs text-white/45", children: timestampFormatter(timestamp) }) : null;
4189
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: cn(timestampPosition === "side" ? "grid gap-3 md:grid-cols-[11rem_1fr]" : ""), children: [
4190
+ timestampPosition === "side" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1 text-xs text-white/45", children: timestampNode }) : null,
4191
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-start", styles.gap), "aria-label": timestamp ? `${timestampFormatter(timestamp)} ${String(event.title)}` : void 0, children: [
4192
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex w-10 shrink-0 justify-center", children: [
4193
+ lineStyle !== "none" && !isLast ? /* @__PURE__ */ jsxRuntime.jsx(
4194
+ "span",
4195
+ {
4196
+ "aria-hidden": "true",
4197
+ className: cn("absolute left-1/2 top-10 bottom-[-1rem] -translate-x-1/2", getLineClass(lineStyle))
4198
+ }
4199
+ ) : null,
4200
+ /* @__PURE__ */ jsxRuntime.jsx(
4201
+ "span",
4202
+ {
4203
+ className: cn(
4204
+ "relative z-[1] inline-flex shrink-0 items-center justify-center rounded-full ring-1",
4205
+ styles.icon,
4206
+ tone.className
4207
+ ),
4208
+ style: tone.style,
4209
+ "aria-hidden": "true",
4210
+ children: event.icon ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultIcon, {})
4211
+ }
4212
+ )
4213
+ ] }),
4214
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("min-w-0 flex-1", styles.textGap, timestampPosition === "inline" ? "space-y-1.5" : "space-y-2"), children: [
4215
+ timestampPosition === "above" ? timestampNode : null,
4216
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(timestampPosition === "inline" ? "flex flex-wrap items-start justify-between gap-2" : "space-y-2"), children: [
4217
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-2", children: [
4218
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium leading-relaxed text-white", children: event.title }),
4219
+ event.description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm leading-relaxed text-white/60", children: event.description }) : null
4220
+ ] }),
4221
+ timestampPosition === "inline" ? timestampNode : null
4222
+ ] }),
4223
+ event.metadata && Object.keys(event.metadata).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid gap-2 rounded-xl border border-white/10 bg-white/[0.03] p-3 sm:grid-cols-2", children: Object.entries(event.metadata).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-1", children: [
4224
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-[11px] uppercase tracking-[0.14em] text-white/35", children: key }),
4225
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "text-sm text-white/70", children: value })
4226
+ ] }, key)) }) : null
4227
+ ] })
4228
+ ] })
4229
+ ] }, event.id);
4230
+ }) })
4231
+ ] }, group.key)),
4232
+ showLoadMore ? /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "secondary", size: "sm", onClick: onLoadMore, children: "Load more" }) }) : null
2587
4233
  ] });
2588
4234
  }
2589
4235
  function ActiveFilterPills({
@@ -2758,7 +4404,7 @@ function Sidebar({ children, collapsed = false, onToggle, className }) {
2758
4404
  }
2759
4405
  );
2760
4406
  }
2761
- var maxWidthClass2 = {
4407
+ var widthClass = {
2762
4408
  sm: "max-w-2xl",
2763
4409
  md: "max-w-4xl",
2764
4410
  lg: "max-w-5xl",
@@ -2766,309 +4412,247 @@ var maxWidthClass2 = {
2766
4412
  "2xl": "max-w-[92rem]",
2767
4413
  full: "max-w-full"
2768
4414
  };
2769
- function DashboardLayout({ children, navbar, sidebar, className, mainClassName, maxWidth = "lg" }) {
2770
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("min-h-screen bg-surface relative overflow-hidden", className), children: [
2771
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "aria-hidden": "true", className: "pointer-events-none fixed inset-0", children: [
2772
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "orb orb-purple w-[400px] h-[400px] -top-[150px] -left-[150px] opacity-15" }),
2773
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "orb orb-blue w-[300px] h-[300px] top-[60%] -right-[100px] opacity-10" })
2774
- ] }),
2775
- navbar,
2776
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex", navbar && "pt-16"), children: [
2777
- sidebar,
2778
- /* @__PURE__ */ jsxRuntime.jsx("main", { className: cn("flex-1 min-w-0 py-8 px-6", mainClassName), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mx-auto", maxWidthClass2[maxWidth]), children }) })
2779
- ] })
2780
- ] });
2781
- }
2782
- var variantBorderColor = {
2783
- info: "border-blue-500",
2784
- success: "border-emerald-500",
2785
- warning: "border-amber-500",
2786
- error: "border-rose-500"
2787
- };
2788
- var variantIconColor = {
2789
- info: "text-blue-400",
2790
- success: "text-emerald-400",
2791
- warning: "text-amber-400",
2792
- error: "text-rose-400"
2793
- };
2794
- function InfoIcon() {
2795
- return /* @__PURE__ */ jsxRuntime.jsxs(
2796
- "svg",
2797
- {
2798
- "aria-hidden": "true",
2799
- width: "18",
2800
- height: "18",
2801
- viewBox: "0 0 18 18",
2802
- fill: "none",
2803
- xmlns: "http://www.w3.org/2000/svg",
2804
- children: [
2805
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "9", r: "7.5", stroke: "currentColor", strokeWidth: "1.5" }),
2806
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 8v5", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" }),
2807
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "5.5", r: "0.875", fill: "currentColor" })
2808
- ]
2809
- }
2810
- );
4415
+ function getItemKey(item, index) {
4416
+ if (item.key) return item.key;
4417
+ if (item.href) return item.href;
4418
+ return `dashboard-nav-item-${index}`;
2811
4419
  }
2812
- function SuccessIcon() {
2813
- return /* @__PURE__ */ jsxRuntime.jsxs(
2814
- "svg",
2815
- {
2816
- "aria-hidden": "true",
2817
- width: "18",
2818
- height: "18",
2819
- viewBox: "0 0 18 18",
2820
- fill: "none",
2821
- xmlns: "http://www.w3.org/2000/svg",
2822
- children: [
2823
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "9", r: "7.5", stroke: "currentColor", strokeWidth: "1.5" }),
2824
- /* @__PURE__ */ jsxRuntime.jsx(
2825
- "path",
2826
- {
2827
- d: "M5.5 9.5l2.5 2.5 4.5-5",
2828
- stroke: "currentColor",
2829
- strokeWidth: "1.75",
2830
- strokeLinecap: "round",
2831
- strokeLinejoin: "round"
2832
- }
2833
- )
2834
- ]
2835
- }
4420
+ function getDesktopNavItemClass(item) {
4421
+ return cn(
4422
+ "flex items-center gap-3 rounded-lg px-4 py-2.5 text-sm transition-all duration-200",
4423
+ item.active ? "bg-accent/20 text-accent" : "text-white/60 hover:bg-white/5 hover:text-white",
4424
+ item.disabled && "pointer-events-none opacity-50"
2836
4425
  );
2837
4426
  }
2838
- function WarningIcon() {
2839
- return /* @__PURE__ */ jsxRuntime.jsxs(
2840
- "svg",
2841
- {
2842
- "aria-hidden": "true",
2843
- width: "18",
2844
- height: "18",
2845
- viewBox: "0 0 18 18",
2846
- fill: "none",
2847
- xmlns: "http://www.w3.org/2000/svg",
2848
- children: [
2849
- /* @__PURE__ */ jsxRuntime.jsx(
2850
- "path",
2851
- {
2852
- d: "M7.634 2.896a1.6 1.6 0 0 1 2.732 0l5.866 10.167A1.6 1.6 0 0 1 14.866 15.5H3.134a1.6 1.6 0 0 1-1.366-2.437L7.634 2.896Z",
2853
- stroke: "currentColor",
2854
- strokeWidth: "1.5",
2855
- strokeLinejoin: "round"
2856
- }
2857
- ),
2858
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 7v4", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" }),
2859
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "12.5", r: "0.875", fill: "currentColor" })
2860
- ]
2861
- }
4427
+ function getMobileNavItemClass(item) {
4428
+ return cn(
4429
+ "flex flex-col items-center px-3 py-2 text-xs transition-colors",
4430
+ item.active ? "text-accent" : "text-white/50",
4431
+ item.disabled && "pointer-events-none opacity-50"
2862
4432
  );
2863
4433
  }
2864
- function ErrorIcon() {
2865
- return /* @__PURE__ */ jsxRuntime.jsxs(
2866
- "svg",
4434
+ function renderDefaultNavItem(item, context) {
4435
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4436
+ item.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: context.type === "mobile" ? "text-lg" : void 0, children: item.icon }) : null,
4437
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("min-w-0 truncate", context.type === "desktop" && item.badge && "flex-1"), children: item.label }),
4438
+ context.type === "desktop" && item.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: item.badge }) : null
4439
+ ] });
4440
+ if (item.href) {
4441
+ return /* @__PURE__ */ jsxRuntime.jsx(
4442
+ "a",
4443
+ {
4444
+ href: item.href,
4445
+ target: item.target,
4446
+ rel: item.rel,
4447
+ "aria-current": item.active ? "page" : void 0,
4448
+ className: context.className,
4449
+ children: content
4450
+ }
4451
+ );
4452
+ }
4453
+ return /* @__PURE__ */ jsxRuntime.jsx(
4454
+ "button",
2867
4455
  {
2868
- "aria-hidden": "true",
2869
- width: "18",
2870
- height: "18",
2871
- viewBox: "0 0 18 18",
2872
- fill: "none",
2873
- xmlns: "http://www.w3.org/2000/svg",
2874
- children: [
2875
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "9", r: "7.5", stroke: "currentColor", strokeWidth: "1.5" }),
2876
- /* @__PURE__ */ jsxRuntime.jsx(
2877
- "path",
2878
- {
2879
- d: "M6.5 6.5l5 5M11.5 6.5l-5 5",
2880
- stroke: "currentColor",
2881
- strokeWidth: "1.75",
2882
- strokeLinecap: "round"
2883
- }
2884
- )
2885
- ]
4456
+ type: "button",
4457
+ onClick: item.onClick,
4458
+ disabled: item.disabled,
4459
+ "aria-current": item.active ? "page" : void 0,
4460
+ className: context.className,
4461
+ children: content
2886
4462
  }
2887
4463
  );
2888
4464
  }
2889
- var variantIcon = {
2890
- info: InfoIcon,
2891
- success: SuccessIcon,
2892
- warning: WarningIcon,
2893
- error: ErrorIcon
2894
- };
2895
- function Alert({ variant = "info", title, children, onDismiss, className }) {
2896
- const Icon = variantIcon[variant];
2897
- return /* @__PURE__ */ jsxRuntime.jsxs(
4465
+ function DashboardLayout({
4466
+ children,
4467
+ navbar,
4468
+ sidebar,
4469
+ brand,
4470
+ user,
4471
+ headerActions,
4472
+ navItems,
4473
+ renderNavItem,
4474
+ navigationLabel = "Main navigation",
4475
+ mobileNavigationLabel = "Mobile navigation",
4476
+ shellClassName,
4477
+ shellWidth = "xl",
4478
+ className,
4479
+ mainClassName,
4480
+ maxWidth = "lg"
4481
+ }) {
4482
+ const hasGeneratedHeader = !navbar && Boolean(brand || user || headerActions);
4483
+ const hasGeneratedNavigation = !sidebar && Boolean(navItems?.length);
4484
+ const hasGeneratedShell = hasGeneratedHeader || hasGeneratedNavigation;
4485
+ const renderNav = renderNavItem ?? renderDefaultNavItem;
4486
+ const generatedHeader = hasGeneratedHeader ? /* @__PURE__ */ jsxRuntime.jsx("header", { className: "sticky top-0 z-40 glass border-b border-white/10", children: /* @__PURE__ */ jsxRuntime.jsxs(
2898
4487
  "div",
2899
4488
  {
2900
- role: "alert",
2901
4489
  className: cn(
2902
- "flex items-start gap-3 rounded-xl bg-white/5 ring-1 ring-white/10",
2903
- "border-l-4 pl-4 pr-3 py-3",
2904
- variantBorderColor[variant],
2905
- className
4490
+ "mx-auto flex h-16 items-center justify-between gap-4 px-4 sm:px-6 lg:px-8",
4491
+ widthClass[shellWidth]
2906
4492
  ),
2907
4493
  children: [
2908
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("mt-0.5 shrink-0", variantIconColor[variant]), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {}) }),
2909
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
2910
- title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-white leading-snug mb-0.5", children: title }),
2911
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-white/70 leading-relaxed", children })
2912
- ] }),
2913
- onDismiss && /* @__PURE__ */ jsxRuntime.jsx(
2914
- "button",
2915
- {
2916
- type: "button",
2917
- "aria-label": "Dismiss",
2918
- onClick: onDismiss,
2919
- className: cn(
2920
- "shrink-0 flex items-center justify-center h-6 w-6 rounded-lg mt-0.5",
2921
- "text-white/40 transition-colors hover:bg-white/10 hover:text-white/80",
2922
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40"
2923
- ),
2924
- children: /* @__PURE__ */ jsxRuntime.jsx(
2925
- "svg",
2926
- {
2927
- "aria-hidden": "true",
2928
- width: "10",
2929
- height: "10",
2930
- viewBox: "0 0 10 10",
2931
- fill: "none",
2932
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 1l8 8M9 1L1 9", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
2933
- }
2934
- )
2935
- }
2936
- )
2937
- ]
2938
- }
2939
- );
2940
- }
2941
- function CopyIcon() {
2942
- return /* @__PURE__ */ jsxRuntime.jsxs(
2943
- "svg",
2944
- {
2945
- "aria-hidden": "true",
2946
- width: "16",
2947
- height: "16",
2948
- viewBox: "0 0 16 16",
2949
- fill: "none",
2950
- xmlns: "http://www.w3.org/2000/svg",
2951
- children: [
2952
- /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "5", y: "5", width: "9", height: "9", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
2953
- /* @__PURE__ */ jsxRuntime.jsx(
2954
- "path",
2955
- {
2956
- d: "M3.5 11H3a1.5 1.5 0 0 1-1.5-1.5V3A1.5 1.5 0 0 1 3 1.5h6.5A1.5 1.5 0 0 1 11 3v.5",
2957
- stroke: "currentColor",
2958
- strokeWidth: "1.5",
2959
- strokeLinecap: "round"
2960
- }
2961
- )
4494
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex items-center gap-3", children: brand }),
4495
+ (user || headerActions) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
4496
+ user,
4497
+ headerActions
4498
+ ] })
2962
4499
  ]
2963
4500
  }
2964
- );
2965
- }
2966
- function CheckIcon() {
2967
- return /* @__PURE__ */ jsxRuntime.jsx(
2968
- "svg",
4501
+ ) }) : null;
4502
+ const generatedSidebar = hasGeneratedNavigation ? /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "hidden w-56 shrink-0 md:block", "aria-label": navigationLabel, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "glass sticky top-24 rounded-xl p-3", children: navItems.map((item, index) => {
4503
+ const navContext = {
4504
+ type: "desktop",
4505
+ className: getDesktopNavItemClass(item)
4506
+ };
4507
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderNav(item, navContext) }, getItemKey(item, index));
4508
+ }) }) }) : null;
4509
+ const generatedMobileNavigation = hasGeneratedNavigation ? /* @__PURE__ */ jsxRuntime.jsx(
4510
+ "nav",
2969
4511
  {
2970
- "aria-hidden": "true",
2971
- width: "16",
2972
- height: "16",
2973
- viewBox: "0 0 16 16",
2974
- fill: "none",
2975
- xmlns: "http://www.w3.org/2000/svg",
2976
- children: /* @__PURE__ */ jsxRuntime.jsx(
2977
- "path",
2978
- {
2979
- d: "M3 8.5l3.5 3.5 6.5-7",
2980
- stroke: "currentColor",
2981
- strokeWidth: "1.75",
2982
- strokeLinecap: "round",
2983
- strokeLinejoin: "round"
2984
- }
2985
- )
4512
+ className: "glass pb-safe fixed bottom-0 left-0 right-0 z-40 border-t border-white/10 px-2 py-1 md:hidden",
4513
+ "aria-label": mobileNavigationLabel,
4514
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-around", children: navItems.map((item, index) => {
4515
+ const navContext = {
4516
+ type: "mobile",
4517
+ className: getMobileNavItemClass(item)
4518
+ };
4519
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderNav(item, navContext) }, getItemKey(item, index));
4520
+ }) })
2986
4521
  }
2987
- );
2988
- }
2989
- function EyeIcon() {
2990
- return /* @__PURE__ */ jsxRuntime.jsxs(
2991
- "svg",
2992
- {
2993
- "aria-hidden": "true",
2994
- width: "16",
2995
- height: "16",
2996
- viewBox: "0 0 16 16",
2997
- fill: "none",
2998
- xmlns: "http://www.w3.org/2000/svg",
2999
- children: [
3000
- /* @__PURE__ */ jsxRuntime.jsx(
3001
- "path",
3002
- {
3003
- d: "M1.5 8S3.5 3.5 8 3.5 14.5 8 14.5 8 12.5 12.5 8 12.5 1.5 8 1.5 8Z",
3004
- stroke: "currentColor",
3005
- strokeWidth: "1.5",
3006
- strokeLinejoin: "round"
3007
- }
3008
- ),
3009
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8", cy: "8", r: "2", stroke: "currentColor", strokeWidth: "1.5" })
3010
- ]
4522
+ ) : null;
4523
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("min-h-screen bg-surface relative overflow-hidden", className), children: [
4524
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "aria-hidden": "true", className: "pointer-events-none fixed inset-0", children: [
4525
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "orb orb-purple w-[400px] h-[400px] -top-[150px] -left-[150px] opacity-15" }),
4526
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "orb orb-blue w-[300px] h-[300px] top-[60%] -right-[100px] opacity-10" })
4527
+ ] }),
4528
+ generatedHeader ?? navbar,
4529
+ hasGeneratedShell ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4530
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("mx-auto flex gap-6 px-4 py-6 sm:px-6 lg:px-8", widthClass[shellWidth], shellClassName), children: [
4531
+ generatedSidebar ?? sidebar,
4532
+ /* @__PURE__ */ jsxRuntime.jsx("main", { className: cn("flex-1 min-w-0", hasGeneratedNavigation && "pb-20 md:pb-0", mainClassName), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mx-auto", widthClass[maxWidth]), children }) })
4533
+ ] }),
4534
+ generatedMobileNavigation
4535
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex", navbar && "pt-16", shellClassName), children: [
4536
+ sidebar,
4537
+ /* @__PURE__ */ jsxRuntime.jsx("main", { className: cn("flex-1 min-w-0 py-8 px-6", mainClassName), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mx-auto", widthClass[maxWidth]), children }) })
4538
+ ] })
4539
+ ] });
4540
+ }
4541
+ function CopyIcon() {
4542
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": "true", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
4543
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "5", y: "5", width: "9", height: "9", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
4544
+ /* @__PURE__ */ jsxRuntime.jsx(
4545
+ "path",
4546
+ {
4547
+ d: "M3.5 11H3a1.5 1.5 0 0 1-1.5-1.5V3A1.5 1.5 0 0 1 3 1.5h6.5A1.5 1.5 0 0 1 11 3v.5",
4548
+ stroke: "currentColor",
4549
+ strokeWidth: "1.5",
4550
+ strokeLinecap: "round"
4551
+ }
4552
+ )
4553
+ ] });
4554
+ }
4555
+ function CheckIcon() {
4556
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx(
4557
+ "path",
4558
+ {
4559
+ d: "M3 8.5l3.5 3.5 6.5-7",
4560
+ stroke: "currentColor",
4561
+ strokeWidth: "1.75",
4562
+ strokeLinecap: "round",
4563
+ strokeLinejoin: "round"
3011
4564
  }
3012
- );
4565
+ ) });
4566
+ }
4567
+ function EyeIcon() {
4568
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": "true", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
4569
+ /* @__PURE__ */ jsxRuntime.jsx(
4570
+ "path",
4571
+ {
4572
+ d: "M1.5 8S3.5 3.5 8 3.5 14.5 8 14.5 8 12.5 12.5 8 12.5 1.5 8 1.5 8Z",
4573
+ stroke: "currentColor",
4574
+ strokeWidth: "1.5",
4575
+ strokeLinejoin: "round"
4576
+ }
4577
+ ),
4578
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8", cy: "8", r: "2", stroke: "currentColor", strokeWidth: "1.5" })
4579
+ ] });
3013
4580
  }
3014
4581
  function EyeOffIcon() {
3015
- return /* @__PURE__ */ jsxRuntime.jsx(
3016
- "svg",
4582
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": "true", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx(
4583
+ "path",
3017
4584
  {
3018
- "aria-hidden": "true",
3019
- width: "16",
3020
- height: "16",
3021
- viewBox: "0 0 16 16",
3022
- fill: "none",
3023
- xmlns: "http://www.w3.org/2000/svg",
3024
- children: /* @__PURE__ */ jsxRuntime.jsx(
3025
- "path",
3026
- {
3027
- d: "M2 2l12 12M6.5 6.6A2 2 0 0 0 9.4 9.5M4.3 4.4C2.9 5.4 1.5 8 1.5 8S3.5 12.5 8 12.5c1.4 0 2.6-.4 3.7-1.1M6.7 3.6C7.1 3.5 7.5 3.5 8 3.5c4.5 0 6.5 4.5 6.5 4.5s-.5 1.2-1.5 2.3",
3028
- stroke: "currentColor",
3029
- strokeWidth: "1.5",
3030
- strokeLinecap: "round",
3031
- strokeLinejoin: "round"
3032
- }
3033
- )
4585
+ d: "M2 2l12 12M6.5 6.6A2 2 0 0 0 9.4 9.5M4.3 4.4C2.9 5.4 1.5 8 1.5 8S3.5 12.5 8 12.5c1.4 0 2.6-.4 3.7-1.1M6.7 3.6C7.1 3.5 7.5 3.5 8 3.5c4.5 0 6.5 4.5 6.5 4.5s-.5 1.2-1.5 2.3",
4586
+ stroke: "currentColor",
4587
+ strokeWidth: "1.5",
4588
+ strokeLinecap: "round",
4589
+ strokeLinejoin: "round"
3034
4590
  }
3035
- );
4591
+ ) });
3036
4592
  }
3037
4593
  var iconButtonBase = cn(
3038
4594
  "flex items-center justify-center h-7 w-7 rounded-lg shrink-0",
3039
4595
  "text-white/40 transition-colors hover:bg-white/10 hover:text-white/80",
3040
4596
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40"
3041
4597
  );
3042
- function CopyField({ value, label, masked = false, className, id: externalId }) {
4598
+ function defaultMaskFormatter(rawValue) {
4599
+ return "\u2022".repeat(Math.min(rawValue.length, 24));
4600
+ }
4601
+ function CopyField({
4602
+ value,
4603
+ label,
4604
+ description,
4605
+ masked = false,
4606
+ emptyText = "\u2014",
4607
+ rightActions,
4608
+ copyOnClick = false,
4609
+ maskFormatter = defaultMaskFormatter,
4610
+ className,
4611
+ id: externalId
4612
+ }) {
3043
4613
  const generatedId = React.useId();
3044
4614
  const fieldId = externalId || generatedId;
4615
+ const labelId = label ? `${fieldId}-label` : void 0;
3045
4616
  const { copy, copied } = useClipboard();
3046
4617
  const [revealed, setRevealed] = React.useState(false);
3047
- const displayValue = masked && !revealed ? "\u2022".repeat(Math.min(value.length, 24)) : value;
4618
+ const hasValue = value.trim().length > 0;
4619
+ const displayValue = !hasValue ? emptyText : masked && !revealed ? maskFormatter(value) : value;
4620
+ const handleCopy = () => {
4621
+ if (!hasValue) return;
4622
+ void copy(value);
4623
+ };
3048
4624
  const field = /* @__PURE__ */ jsxRuntime.jsxs(
3049
4625
  "div",
3050
4626
  {
3051
4627
  className: cn(
3052
4628
  "flex items-center gap-1 w-full rounded-xl px-3 py-2.5",
3053
4629
  "bg-white/10 ring-1 ring-white/10",
4630
+ copyOnClick && hasValue && "cursor-pointer hover:bg-white/15 focus-within:ring-primary/30",
4631
+ copyOnClick && !hasValue && "cursor-not-allowed opacity-70",
3054
4632
  className
3055
4633
  ),
4634
+ "aria-labelledby": labelId,
4635
+ role: copyOnClick && hasValue ? "button" : void 0,
4636
+ tabIndex: copyOnClick && hasValue ? 0 : void 0,
4637
+ onClick: copyOnClick ? handleCopy : void 0,
4638
+ onKeyDown: copyOnClick && hasValue ? (event) => {
4639
+ if (event.key === "Enter" || event.key === " ") {
4640
+ event.preventDefault();
4641
+ handleCopy();
4642
+ }
4643
+ } : void 0,
3056
4644
  children: [
3057
- /* @__PURE__ */ jsxRuntime.jsx(
3058
- "span",
3059
- {
3060
- id: fieldId,
3061
- className: "flex-1 min-w-0 truncate text-sm text-white select-all font-mono",
3062
- "aria-label": label,
3063
- children: displayValue
3064
- }
3065
- ),
3066
- masked && /* @__PURE__ */ jsxRuntime.jsx(
4645
+ /* @__PURE__ */ jsxRuntime.jsx("span", { id: fieldId, className: "flex-1 min-w-0 truncate text-sm text-white select-all font-mono", children: displayValue }),
4646
+ rightActions,
4647
+ masked && hasValue && /* @__PURE__ */ jsxRuntime.jsx(
3067
4648
  "button",
3068
4649
  {
3069
4650
  type: "button",
3070
4651
  "aria-label": revealed ? "Hide value" : "Reveal value",
3071
- onClick: () => setRevealed((v) => !v),
4652
+ onClick: (event) => {
4653
+ event.stopPropagation();
4654
+ setRevealed((currentValue) => !currentValue);
4655
+ },
3072
4656
  className: iconButtonBase,
3073
4657
  children: revealed ? /* @__PURE__ */ jsxRuntime.jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(EyeIcon, {})
3074
4658
  }
@@ -3078,7 +4662,11 @@ function CopyField({ value, label, masked = false, className, id: externalId })
3078
4662
  {
3079
4663
  type: "button",
3080
4664
  "aria-label": copied ? "Copied!" : "Copy to clipboard",
3081
- onClick: () => copy(value),
4665
+ onClick: (event) => {
4666
+ event.stopPropagation();
4667
+ handleCopy();
4668
+ },
4669
+ disabled: !hasValue,
3082
4670
  className: cn(iconButtonBase, copied && "text-emerald-400 hover:text-emerald-400"),
3083
4671
  children: copied ? /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(CopyIcon, {})
3084
4672
  }
@@ -3088,8 +4676,9 @@ function CopyField({ value, label, masked = false, className, id: externalId })
3088
4676
  );
3089
4677
  if (!label) return field;
3090
4678
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3091
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: fieldId, className: "block text-sm text-white/70 mb-1.5", children: label }),
3092
- field
4679
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: labelId, className: "block text-sm text-white/70 mb-1.5", children: label }),
4680
+ field,
4681
+ description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1.5 text-xs text-white/50", children: description }) : null
3093
4682
  ] });
3094
4683
  }
3095
4684
  var ProgressButton = React.forwardRef(
@@ -3156,7 +4745,7 @@ var variantIconColor2 = {
3156
4745
  warning: "text-amber-400",
3157
4746
  info: "text-primary"
3158
4747
  };
3159
- var positionClass = {
4748
+ var positionClass2 = {
3160
4749
  "top-right": "top-4 right-4 items-end",
3161
4750
  "top-center": "top-4 left-1/2 -translate-x-1/2 items-center",
3162
4751
  "bottom-right": "bottom-4 right-4 items-end",
@@ -3303,7 +4892,7 @@ function ToastProvider({ children, position = "top-right", maxToasts = 5 }) {
3303
4892
  "div",
3304
4893
  {
3305
4894
  "aria-label": "Notifications",
3306
- className: cn("fixed z-[9999] flex flex-col gap-3 pointer-events-none", positionClass[position]),
4895
+ className: cn("fixed z-[9999] flex flex-col gap-3 pointer-events-none", positionClass2[position]),
3307
4896
  children: toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsxRuntime.jsx(ToastCard, { toast: t, onDismiss: dismiss }) }, t.id))
3308
4897
  }
3309
4898
  ),
@@ -3433,7 +5022,7 @@ function MutationOverlay({
3433
5022
  }
3434
5023
  );
3435
5024
  }
3436
- var sizeClass6 = {
5025
+ var sizeClass7 = {
3437
5026
  sm: "w-8 h-8",
3438
5027
  md: "w-10 h-10",
3439
5028
  lg: "w-12 h-12"
@@ -3451,503 +5040,345 @@ var badgeSizeClass = {
3451
5040
  var DefaultBellIcon = ({ className }) => /* @__PURE__ */ jsxRuntime.jsxs(
3452
5041
  "svg",
3453
5042
  {
3454
- xmlns: "http://www.w3.org/2000/svg",
3455
- viewBox: "0 0 24 24",
3456
- fill: "none",
3457
- stroke: "currentColor",
3458
- strokeWidth: 2,
3459
- strokeLinecap: "round",
3460
- strokeLinejoin: "round",
3461
- className,
3462
- "aria-hidden": "true",
3463
- children: [
3464
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }),
3465
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })
3466
- ]
3467
- }
3468
- );
3469
- var NotificationBell = React.forwardRef(
3470
- function NotificationBell2({ icon, count, maxCount = 99, size = "md", ping, className, disabled, ...props }, ref) {
3471
- const displayCount = count && count > maxCount ? `${maxCount}+` : count;
3472
- const hasCount = count !== void 0 && count > 0;
3473
- return /* @__PURE__ */ jsxRuntime.jsxs(
3474
- "button",
3475
- {
3476
- ref,
3477
- type: "button",
3478
- ...props,
3479
- disabled,
3480
- "aria-label": props["aria-label"] || `Notifications${hasCount ? ` (${count})` : ""}`,
3481
- className: cn(
3482
- "relative inline-flex items-center justify-center rounded-xl text-white/70 transition-colors hover:text-white hover:bg-white/10 focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent disabled:opacity-60 disabled:pointer-events-none",
3483
- sizeClass6[size],
3484
- className
3485
- ),
3486
- children: [
3487
- icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: icon }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultBellIcon, { className: iconSizeClass[size] }),
3488
- hasCount && /* @__PURE__ */ jsxRuntime.jsxs(
3489
- "span",
3490
- {
3491
- className: cn(
3492
- "absolute top-0 right-0 flex items-center justify-center rounded-full bg-rose-500 text-white font-semibold leading-none",
3493
- badgeSizeClass[size]
3494
- ),
3495
- children: [
3496
- ping && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 rounded-full bg-rose-500 animate-ping opacity-75" }),
3497
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative", children: displayCount })
3498
- ]
3499
- }
3500
- )
3501
- ]
3502
- }
3503
- );
3504
- }
3505
- );
3506
- var sizeClass7 = {
3507
- xs: "text-sm font-semibold",
3508
- sm: "text-base font-semibold",
3509
- md: "text-lg font-bold",
3510
- lg: "text-xl font-bold",
3511
- xl: "text-2xl font-bold tracking-tight",
3512
- "2xl": "text-3xl font-bold tracking-tight sm:text-4xl"
3513
- };
3514
- var levelToSize = {
3515
- 1: "2xl",
3516
- 2: "xl",
3517
- 3: "lg",
3518
- 4: "md",
3519
- 5: "sm",
3520
- 6: "xs"
3521
- };
3522
- var colorClass = {
3523
- default: "text-white",
3524
- muted: "text-white/70",
3525
- gradient: "text-gradient"
3526
- };
3527
- var Heading = React.forwardRef(function Heading2({ level = 2, size, color = "default", className, ...props }, ref) {
3528
- const Tag = `h${level}`;
3529
- const effectiveSize = size ?? levelToSize[level];
3530
- return /* @__PURE__ */ jsxRuntime.jsx(
3531
- Tag,
3532
- {
3533
- ref,
3534
- ...props,
3535
- className: cn(sizeClass7[effectiveSize], colorClass[color], className)
3536
- }
3537
- );
3538
- });
3539
- var sizeMap2 = {
3540
- xs: "text-xs",
3541
- sm: "text-sm",
3542
- md: "text-base",
3543
- lg: "text-lg"
3544
- };
3545
- var colorMap = {
3546
- default: "text-white/90",
3547
- muted: "text-white/70",
3548
- dimmed: "text-white/50",
3549
- primary: "text-primary-light",
3550
- success: "text-emerald-400",
3551
- warning: "text-amber-400",
3552
- danger: "text-rose-400"
3553
- };
3554
- var weightMap = {
3555
- normal: "font-normal",
3556
- medium: "font-medium",
3557
- semibold: "font-semibold",
3558
- bold: "font-bold"
3559
- };
3560
- var Text = React.forwardRef(function Text2({ size = "md", color = "default", weight = "normal", inline = false, truncate = false, className, ...props }, ref) {
3561
- const Tag = inline ? "span" : "p";
3562
- return /* @__PURE__ */ jsxRuntime.jsx(
3563
- Tag,
3564
- {
3565
- ref,
3566
- ...props,
3567
- className: cn(
3568
- sizeMap2[size],
3569
- colorMap[color],
3570
- weightMap[weight],
3571
- truncate && "truncate",
3572
- className
3573
- )
3574
- }
3575
- );
3576
- });
3577
- var gapClass = {
3578
- 0: "gap-0",
3579
- 1: "gap-1",
3580
- 2: "gap-2",
3581
- 3: "gap-3",
3582
- 4: "gap-4",
3583
- 5: "gap-5",
3584
- 6: "gap-6",
3585
- 8: "gap-8",
3586
- 10: "gap-10",
3587
- 12: "gap-12"
3588
- };
3589
- var alignClass2 = {
3590
- start: "items-start",
3591
- center: "items-center",
3592
- end: "items-end",
3593
- stretch: "items-stretch",
3594
- baseline: "items-baseline"
3595
- };
3596
- var justifyClass = {
3597
- start: "justify-start",
3598
- center: "justify-center",
3599
- end: "justify-end",
3600
- between: "justify-between",
3601
- around: "justify-around",
3602
- evenly: "justify-evenly"
3603
- };
3604
- var Stack = React.forwardRef(function Stack2({ children, direction = "vertical", gap = 4, align = "stretch", justify = "start", wrap = false, className, ...props }, ref) {
3605
- return /* @__PURE__ */ jsxRuntime.jsx(
3606
- "div",
3607
- {
3608
- ref,
3609
- ...props,
3610
- className: cn(
3611
- "flex",
3612
- direction === "vertical" ? "flex-col" : "flex-row",
3613
- gapClass[gap],
3614
- alignClass2[align],
3615
- justifyClass[justify],
3616
- wrap && "flex-wrap",
3617
- className
3618
- ),
3619
- children
3620
- }
3621
- );
3622
- });
3623
- var ScrollArea = React.forwardRef(function ScrollArea2({ children, maxHeight, hideScrollbar = false, orientation = "vertical", className, style, ...props }, ref) {
3624
- const overflowClass = {
3625
- vertical: "overflow-y-auto overflow-x-hidden",
3626
- horizontal: "overflow-x-auto overflow-y-hidden",
3627
- both: "overflow-auto"
3628
- }[orientation];
3629
- return /* @__PURE__ */ jsxRuntime.jsx(
3630
- "div",
3631
- {
3632
- ref,
3633
- ...props,
3634
- tabIndex: 0,
3635
- className: cn(
3636
- overflowClass,
3637
- // Custom dark scrollbar styling
3638
- "[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5",
3639
- "[&::-webkit-scrollbar-track]:bg-transparent",
3640
- "[&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-white/15 hover:[&::-webkit-scrollbar-thumb]:bg-white/25",
3641
- hideScrollbar && "no-scrollbar",
3642
- "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/30 focus-visible:ring-inset",
3643
- className
3644
- ),
3645
- style: {
3646
- maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight,
3647
- ...style
3648
- },
3649
- children
3650
- }
3651
- );
3652
- });
3653
- var defaultSeparator = /* @__PURE__ */ jsxRuntime.jsx(
3654
- "svg",
3655
- {
3656
- className: "w-3.5 h-3.5 text-white/30 flex-shrink-0",
3657
- viewBox: "0 0 16 16",
5043
+ xmlns: "http://www.w3.org/2000/svg",
5044
+ viewBox: "0 0 24 24",
3658
5045
  fill: "none",
3659
5046
  stroke: "currentColor",
3660
- strokeWidth: "2",
5047
+ strokeWidth: 2,
3661
5048
  strokeLinecap: "round",
5049
+ strokeLinejoin: "round",
5050
+ className,
3662
5051
  "aria-hidden": "true",
3663
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 4l4 4-4 4" })
5052
+ children: [
5053
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }),
5054
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })
5055
+ ]
3664
5056
  }
3665
5057
  );
3666
- function Breadcrumbs({ items, separator = defaultSeparator, className }) {
3667
- if (items.length === 0) return null;
3668
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: cn("flex items-center", className), children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex items-center gap-1.5 text-sm", children: items.map((item, index) => {
3669
- const isLast = index === items.length - 1;
3670
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center gap-1.5", children: [
3671
- index > 0 && separator,
3672
- isLast ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white font-medium", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsxRuntime.jsx(
3673
- "a",
3674
- {
3675
- href: item.href,
3676
- onClick: item.onClick,
3677
- className: "text-white/50 hover:text-white/80 transition-colors",
3678
- children: item.label
3679
- }
3680
- ) : item.onClick ? /* @__PURE__ */ jsxRuntime.jsx(
3681
- "button",
3682
- {
3683
- type: "button",
3684
- onClick: item.onClick,
3685
- className: "text-white/50 hover:text-white/80 transition-colors",
3686
- children: item.label
3687
- }
3688
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white/50", children: item.label })
3689
- ] }, index);
3690
- }) }) });
3691
- }
3692
- function Popover({
3693
- content,
3694
- children,
3695
- placement = "bottom",
3696
- closeOnClickOutside = true,
3697
- closeOnEsc = true,
3698
- open: controlledOpen,
3699
- onOpenChange,
3700
- offset = 8,
3701
- className
3702
- }) {
3703
- const popoverId = React.useId();
3704
- const anchorRef = React.useRef(null);
3705
- const popoverRef = React.useRef(null);
3706
- const [internalOpen, setInternalOpen] = React.useState(false);
3707
- const [pos, setPos] = React.useState(null);
3708
- const isControlled = controlledOpen !== void 0;
3709
- const isOpen = isControlled ? controlledOpen : internalOpen;
3710
- const setOpen = React.useCallback(
3711
- (value) => {
3712
- if (!isControlled) setInternalOpen(value);
3713
- onOpenChange?.(value);
3714
- },
3715
- [isControlled, onOpenChange]
3716
- );
3717
- const toggle = React.useCallback(() => setOpen(!isOpen), [isOpen, setOpen]);
3718
- const close = React.useCallback(() => setOpen(false), [setOpen]);
3719
- const updatePosition = React.useCallback(() => {
3720
- const el = anchorRef.current;
3721
- if (!el) return;
3722
- const r = el.getBoundingClientRect();
3723
- let left;
3724
- let top;
3725
- let effPlacement = placement;
3726
- if (placement === "bottom" || placement === "top") {
3727
- left = r.left + r.width / 2;
3728
- if (placement === "bottom") {
3729
- top = r.bottom + offset;
3730
- if (top + 200 > window.innerHeight && r.top - offset > 200) {
3731
- effPlacement = "top";
3732
- top = r.top - offset;
3733
- }
3734
- } else {
3735
- top = r.top - offset;
3736
- if (top < 8) {
3737
- effPlacement = "bottom";
3738
- top = r.bottom + offset;
3739
- }
3740
- }
3741
- } else {
3742
- top = r.top + r.height / 2;
3743
- if (placement === "right") {
3744
- left = r.right + offset;
3745
- } else {
3746
- left = r.left - offset;
3747
- }
3748
- }
3749
- setPos({ left: Math.round(left), top: Math.round(top), placement: effPlacement });
3750
- }, [placement, offset]);
3751
- React.useEffect(() => {
3752
- if (!isOpen) return;
3753
- updatePosition();
3754
- window.addEventListener("scroll", updatePosition, true);
3755
- window.addEventListener("resize", updatePosition);
3756
- return () => {
3757
- window.removeEventListener("scroll", updatePosition, true);
3758
- window.removeEventListener("resize", updatePosition);
3759
- };
3760
- }, [isOpen, updatePosition]);
3761
- React.useEffect(() => {
3762
- if (!isOpen || !closeOnClickOutside) return;
3763
- const handleClick = (e) => {
3764
- const target = e.target;
3765
- if (anchorRef.current?.contains(target) || popoverRef.current?.contains(target)) {
3766
- return;
3767
- }
3768
- close();
3769
- };
3770
- document.addEventListener("mousedown", handleClick);
3771
- return () => document.removeEventListener("mousedown", handleClick);
3772
- }, [isOpen, closeOnClickOutside, close]);
3773
- React.useEffect(() => {
3774
- if (!isOpen || !closeOnEsc) return;
3775
- const handleKey = (e) => {
3776
- if (e.key === "Escape") {
3777
- e.preventDefault();
3778
- close();
3779
- anchorRef.current?.focus();
5058
+ var NotificationBell = React.forwardRef(
5059
+ function NotificationBell2({ icon, count, maxCount = 99, size = "md", ping, className, disabled, ...props }, ref) {
5060
+ const displayCount = count && count > maxCount ? `${maxCount}+` : count;
5061
+ const hasCount = count !== void 0 && count > 0;
5062
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5063
+ "button",
5064
+ {
5065
+ ref,
5066
+ type: "button",
5067
+ ...props,
5068
+ disabled,
5069
+ "aria-label": props["aria-label"] || `Notifications${hasCount ? ` (${count})` : ""}`,
5070
+ className: cn(
5071
+ "relative inline-flex items-center justify-center rounded-xl text-white/70 transition-colors hover:text-white hover:bg-white/10 focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent disabled:opacity-60 disabled:pointer-events-none",
5072
+ sizeClass7[size],
5073
+ className
5074
+ ),
5075
+ children: [
5076
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: icon }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultBellIcon, { className: iconSizeClass[size] }),
5077
+ hasCount && /* @__PURE__ */ jsxRuntime.jsxs(
5078
+ "span",
5079
+ {
5080
+ className: cn(
5081
+ "absolute top-0 right-0 flex items-center justify-center rounded-full bg-rose-500 text-white font-semibold leading-none",
5082
+ badgeSizeClass[size]
5083
+ ),
5084
+ children: [
5085
+ ping && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 rounded-full bg-rose-500 animate-ping opacity-75" }),
5086
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative", children: displayCount })
5087
+ ]
5088
+ }
5089
+ )
5090
+ ]
3780
5091
  }
3781
- };
3782
- document.addEventListener("keydown", handleKey);
3783
- return () => document.removeEventListener("keydown", handleKey);
3784
- }, [isOpen, closeOnEsc, close]);
3785
- if (!React.isValidElement(children)) return children;
3786
- const child = React.cloneElement(children, {
3787
- ref: (node) => {
3788
- anchorRef.current = node;
3789
- const childProps = children.props;
3790
- const prevRef = childProps.ref;
3791
- if (typeof prevRef === "function") prevRef(node);
3792
- else if (prevRef && typeof prevRef === "object") prevRef.current = node;
3793
- },
3794
- onClick: (e) => {
3795
- const childProps = children.props;
3796
- if (typeof childProps.onClick === "function") childProps.onClick(e);
3797
- toggle();
3798
- },
3799
- "aria-expanded": isOpen,
3800
- "aria-haspopup": "dialog",
3801
- "aria-controls": isOpen ? popoverId : void 0
3802
- });
3803
- const getTransform = () => {
3804
- if (!pos) return "translate(-9999px, -9999px)";
3805
- switch (pos.placement) {
3806
- case "top":
3807
- return "translate(-50%, -100%)";
3808
- case "bottom":
3809
- return "translate(-50%, 0%)";
3810
- case "left":
3811
- return "translate(-100%, -50%)";
3812
- case "right":
3813
- return "translate(0%, -50%)";
3814
- }
3815
- };
3816
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3817
- child,
3818
- isOpen && typeof document !== "undefined" ? reactDom.createPortal(
3819
- /* @__PURE__ */ jsxRuntime.jsx(
3820
- "div",
3821
- {
3822
- ref: popoverRef,
3823
- id: popoverId,
3824
- role: "dialog",
3825
- className: cn(
3826
- "fixed z-[9999] rounded-xl shadow-xl ring-1 ring-white/10 bg-surface-50 backdrop-blur-md p-4",
3827
- className
3828
- ),
3829
- style: {
3830
- left: pos?.left ?? 0,
3831
- top: pos?.top ?? 0,
3832
- transform: getTransform()
3833
- },
3834
- children: content
3835
- }
3836
- ),
3837
- document.body
3838
- ) : null
3839
- ] });
3840
- }
5092
+ );
5093
+ }
5094
+ );
3841
5095
  var sizeClass8 = {
3842
- left: { sm: "w-64", md: "w-80", lg: "w-96", full: "w-screen" },
3843
- right: { sm: "w-64", md: "w-80", lg: "w-96", full: "w-screen" },
3844
- bottom: { sm: "h-1/4", md: "h-1/3", lg: "h-1/2", full: "h-screen" }
5096
+ xs: "text-sm font-semibold",
5097
+ sm: "text-base font-semibold",
5098
+ md: "text-lg font-bold",
5099
+ lg: "text-xl font-bold",
5100
+ xl: "text-2xl font-bold tracking-tight",
5101
+ "2xl": "text-3xl font-bold tracking-tight sm:text-4xl"
5102
+ };
5103
+ var levelToSize = {
5104
+ 1: "2xl",
5105
+ 2: "xl",
5106
+ 3: "lg",
5107
+ 4: "md",
5108
+ 5: "sm",
5109
+ 6: "xs"
5110
+ };
5111
+ var colorClass = {
5112
+ default: "text-white",
5113
+ muted: "text-white/70",
5114
+ gradient: "text-gradient"
5115
+ };
5116
+ var Heading = React.forwardRef(function Heading2({ level = 2, size, color = "default", className, ...props }, ref) {
5117
+ const Tag = `h${level}`;
5118
+ const effectiveSize = size ?? levelToSize[level];
5119
+ return /* @__PURE__ */ jsxRuntime.jsx(
5120
+ Tag,
5121
+ {
5122
+ ref,
5123
+ ...props,
5124
+ className: cn(sizeClass8[effectiveSize], colorClass[color], className)
5125
+ }
5126
+ );
5127
+ });
5128
+ var sizeMap2 = {
5129
+ xs: "text-xs",
5130
+ sm: "text-sm",
5131
+ md: "text-base",
5132
+ lg: "text-lg"
5133
+ };
5134
+ var colorMap = {
5135
+ default: "text-white/90",
5136
+ muted: "text-white/70",
5137
+ dimmed: "text-white/50",
5138
+ primary: "text-primary-light",
5139
+ success: "text-emerald-400",
5140
+ warning: "text-amber-400",
5141
+ danger: "text-rose-400"
3845
5142
  };
3846
- var positionClass2 = {
3847
- left: "inset-y-0 left-0",
3848
- right: "inset-y-0 right-0",
3849
- bottom: "inset-x-0 bottom-0"
5143
+ var weightMap = {
5144
+ normal: "font-normal",
5145
+ medium: "font-medium",
5146
+ semibold: "font-semibold",
5147
+ bold: "font-bold"
3850
5148
  };
3851
- var slideIn = {
3852
- left: "translate-x-0",
3853
- right: "translate-x-0",
3854
- bottom: "translate-y-0"
5149
+ var Text = React.forwardRef(function Text2({ size = "md", color = "default", weight = "normal", inline = false, truncate = false, className, ...props }, ref) {
5150
+ const Tag = inline ? "span" : "p";
5151
+ return /* @__PURE__ */ jsxRuntime.jsx(
5152
+ Tag,
5153
+ {
5154
+ ref,
5155
+ ...props,
5156
+ className: cn(
5157
+ sizeMap2[size],
5158
+ colorMap[color],
5159
+ weightMap[weight],
5160
+ truncate && "truncate",
5161
+ className
5162
+ )
5163
+ }
5164
+ );
5165
+ });
5166
+ var gapClass = {
5167
+ 0: "gap-0",
5168
+ 1: "gap-1",
5169
+ 2: "gap-2",
5170
+ 3: "gap-3",
5171
+ 4: "gap-4",
5172
+ 5: "gap-5",
5173
+ 6: "gap-6",
5174
+ 8: "gap-8",
5175
+ 10: "gap-10",
5176
+ 12: "gap-12"
3855
5177
  };
3856
- var slideOut = {
3857
- left: "-translate-x-full",
3858
- right: "translate-x-full",
3859
- bottom: "translate-y-full"
5178
+ var alignClass2 = {
5179
+ start: "items-start",
5180
+ center: "items-center",
5181
+ end: "items-end",
5182
+ stretch: "items-stretch",
5183
+ baseline: "items-baseline"
3860
5184
  };
3861
- function Drawer({
3862
- isOpen,
3863
- onClose,
3864
- children,
3865
- side = "right",
3866
- size = "md",
3867
- ariaLabel,
3868
- closeOnBackdrop = true,
3869
- closeOnEsc = true,
5185
+ var justifyClass = {
5186
+ start: "justify-start",
5187
+ center: "justify-center",
5188
+ end: "justify-end",
5189
+ between: "justify-between",
5190
+ around: "justify-around",
5191
+ evenly: "justify-evenly"
5192
+ };
5193
+ var Stack = React.forwardRef(function Stack2({ children, direction = "vertical", gap = 4, align = "stretch", justify = "start", wrap = false, className, ...props }, ref) {
5194
+ return /* @__PURE__ */ jsxRuntime.jsx(
5195
+ "div",
5196
+ {
5197
+ ref,
5198
+ ...props,
5199
+ className: cn(
5200
+ "flex",
5201
+ direction === "vertical" ? "flex-col" : "flex-row",
5202
+ gapClass[gap],
5203
+ alignClass2[align],
5204
+ justifyClass[justify],
5205
+ wrap && "flex-wrap",
5206
+ className
5207
+ ),
5208
+ children
5209
+ }
5210
+ );
5211
+ });
5212
+ var ScrollArea = React.forwardRef(function ScrollArea2({ children, maxHeight, hideScrollbar = false, orientation = "vertical", className, style, ...props }, ref) {
5213
+ const overflowClass = {
5214
+ vertical: "overflow-y-auto overflow-x-hidden",
5215
+ horizontal: "overflow-x-auto overflow-y-hidden",
5216
+ both: "overflow-auto"
5217
+ }[orientation];
5218
+ return /* @__PURE__ */ jsxRuntime.jsx(
5219
+ "div",
5220
+ {
5221
+ ref,
5222
+ ...props,
5223
+ tabIndex: 0,
5224
+ className: cn(
5225
+ overflowClass,
5226
+ // Custom dark scrollbar styling
5227
+ "[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5",
5228
+ "[&::-webkit-scrollbar-track]:bg-transparent",
5229
+ "[&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-white/15 hover:[&::-webkit-scrollbar-thumb]:bg-white/25",
5230
+ hideScrollbar && "no-scrollbar",
5231
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/30 focus-visible:ring-inset",
5232
+ className
5233
+ ),
5234
+ style: {
5235
+ maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight,
5236
+ ...style
5237
+ },
5238
+ children
5239
+ }
5240
+ );
5241
+ });
5242
+ var defaultSeparator = /* @__PURE__ */ jsxRuntime.jsx(
5243
+ "svg",
5244
+ {
5245
+ className: "w-3.5 h-3.5 text-white/30 flex-shrink-0",
5246
+ viewBox: "0 0 16 16",
5247
+ fill: "none",
5248
+ stroke: "currentColor",
5249
+ strokeWidth: "2",
5250
+ strokeLinecap: "round",
5251
+ "aria-hidden": "true",
5252
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 4l4 4-4 4" })
5253
+ }
5254
+ );
5255
+ function DotsIcon() {
5256
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": "true", className: "h-4 w-4", viewBox: "0 0 16 16", fill: "currentColor", children: [
5257
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "3", cy: "8", r: "1.25" }),
5258
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8", cy: "8", r: "1.25" }),
5259
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "13", cy: "8", r: "1.25" })
5260
+ ] });
5261
+ }
5262
+ function renderItemContent(item) {
5263
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex min-w-0 items-center gap-1.5", children: [
5264
+ item.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-white/45", children: item.icon }) : null,
5265
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: item.label })
5266
+ ] });
5267
+ }
5268
+ function getVisibleItems(items, maxItems, itemsBeforeCollapse = 1, itemsAfterCollapse = 1) {
5269
+ if (!maxItems || items.length <= maxItems) {
5270
+ return items.map((item, index) => ({ type: "item", item, originalIndex: index }));
5271
+ }
5272
+ const before = Math.max(1, itemsBeforeCollapse);
5273
+ const after = Math.max(1, itemsAfterCollapse);
5274
+ if (before + after >= items.length) {
5275
+ return items.map((item, index) => ({ type: "item", item, originalIndex: index }));
5276
+ }
5277
+ const collapsedItems = items.slice(before, items.length - after);
5278
+ const startItems = items.slice(0, before).map((item, index) => ({ type: "item", item, originalIndex: index }));
5279
+ const endItems = items.slice(items.length - after).map((item, index) => ({
5280
+ type: "item",
5281
+ item,
5282
+ originalIndex: items.length - after + index
5283
+ }));
5284
+ return [
5285
+ ...startItems,
5286
+ { type: "collapse", items: collapsedItems },
5287
+ ...endItems
5288
+ ];
5289
+ }
5290
+ function Breadcrumbs({
5291
+ items,
5292
+ separator = defaultSeparator,
5293
+ maxItems,
5294
+ itemsBeforeCollapse = 1,
5295
+ itemsAfterCollapse = 1,
5296
+ renderLink,
3870
5297
  className
3871
5298
  }) {
3872
- const panelRef = React.useRef(null);
3873
- const lastActiveRef = React.useRef(null);
3874
- React.useEffect(() => {
3875
- if (!isOpen) return;
3876
- lastActiveRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
3877
- const raf = requestAnimationFrame(() => {
3878
- const el = panelRef.current;
3879
- if (!el) return;
3880
- const focusables = getFocusableElements(el);
3881
- focusSafely(focusables[0] ?? el);
3882
- });
3883
- return () => {
3884
- cancelAnimationFrame(raf);
3885
- const lastActive = lastActiveRef.current;
3886
- lastActiveRef.current = null;
3887
- if (lastActive?.isConnected) focusSafely(lastActive);
3888
- };
3889
- }, [isOpen]);
3890
- useScrollLock(isOpen);
3891
- if (!isOpen) return null;
3892
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50", role: "presentation", children: [
3893
- /* @__PURE__ */ jsxRuntime.jsx(
3894
- "div",
3895
- {
3896
- className: "absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity duration-200",
3897
- "aria-hidden": "true",
3898
- onClick: closeOnBackdrop ? onClose : void 0
3899
- }
3900
- ),
3901
- /* @__PURE__ */ jsxRuntime.jsx(
3902
- "div",
3903
- {
3904
- ref: panelRef,
3905
- role: "dialog",
3906
- "aria-modal": "true",
3907
- "aria-label": ariaLabel,
3908
- tabIndex: -1,
3909
- className: cn(
3910
- "fixed flex flex-col bg-surface-50 shadow-2xl ring-1 ring-white/10 transition-transform duration-300 ease-out focus:outline-none",
3911
- positionClass2[side],
3912
- sizeClass8[side][size],
3913
- isOpen ? slideIn[side] : slideOut[side],
3914
- className
3915
- ),
3916
- onKeyDownCapture: (e) => {
3917
- if (closeOnEsc && e.key === "Escape") {
3918
- e.preventDefault();
3919
- e.stopPropagation();
3920
- onClose();
3921
- return;
3922
- }
3923
- if (e.key !== "Tab") return;
3924
- const el = panelRef.current;
3925
- if (!el) return;
3926
- const focusables = getFocusableElements(el);
3927
- if (focusables.length === 0) {
3928
- e.preventDefault();
3929
- focusSafely(el);
3930
- return;
3931
- }
3932
- const active = document.activeElement;
3933
- const first = focusables[0];
3934
- const last = focusables[focusables.length - 1];
3935
- if (e.shiftKey) {
3936
- if (active === first) {
3937
- e.preventDefault();
3938
- focusSafely(last);
3939
- }
3940
- } else {
3941
- if (active === last) {
3942
- e.preventDefault();
3943
- focusSafely(first);
3944
- }
5299
+ if (items.length === 0) return null;
5300
+ const visibleItems = getVisibleItems(items, maxItems, itemsBeforeCollapse, itemsAfterCollapse);
5301
+ const lastItemIndex = items.length - 1;
5302
+ const renderLinkNode = (item, classNameValue) => {
5303
+ const content = renderItemContent(item);
5304
+ if (!item.href) {
5305
+ return content;
5306
+ }
5307
+ if (renderLink) {
5308
+ return renderLink({
5309
+ href: item.href,
5310
+ onClick: item.onClick,
5311
+ className: classNameValue,
5312
+ children: content,
5313
+ item
5314
+ });
5315
+ }
5316
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, onClick: item.onClick, className: classNameValue, children: content });
5317
+ };
5318
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: cn("flex items-center", className), children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex min-w-0 items-center gap-1.5 text-sm", children: visibleItems.map((entry, index) => {
5319
+ if (entry.type === "collapse") {
5320
+ return /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
5321
+ index > 0 ? /* @__PURE__ */ jsxRuntime.jsx("li", { className: "flex items-center", children: separator }) : null,
5322
+ /* @__PURE__ */ jsxRuntime.jsx("li", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
5323
+ Popover,
5324
+ {
5325
+ placement: "bottom",
5326
+ className: "min-w-[12rem] p-2",
5327
+ content: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: entry.items.map((item2, hiddenIndex) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: item2.href ? renderLink ? renderLink({
5328
+ href: item2.href,
5329
+ onClick: item2.onClick,
5330
+ className: "flex w-full items-center rounded-lg px-3 py-2 text-sm text-white/75 transition-colors hover:bg-white/10 hover:text-white",
5331
+ children: renderItemContent(item2),
5332
+ item: item2
5333
+ }) : /* @__PURE__ */ jsxRuntime.jsx(
5334
+ "a",
5335
+ {
5336
+ href: item2.href,
5337
+ onClick: item2.onClick,
5338
+ className: "flex w-full items-center rounded-lg px-3 py-2 text-sm text-white/75 transition-colors hover:bg-white/10 hover:text-white",
5339
+ children: renderItemContent(item2)
5340
+ }
5341
+ ) : item2.onClick ? /* @__PURE__ */ jsxRuntime.jsx(
5342
+ "button",
5343
+ {
5344
+ type: "button",
5345
+ onClick: item2.onClick,
5346
+ className: "flex w-full items-center rounded-lg px-3 py-2 text-left text-sm text-white/75 transition-colors hover:bg-white/10 hover:text-white",
5347
+ children: renderItemContent(item2)
5348
+ }
5349
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full items-center rounded-lg px-3 py-2 text-sm text-white/55", children: renderItemContent(item2) }) }, `${hiddenIndex}-${String(item2.href ?? item2.label)}`)) }),
5350
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5351
+ "button",
5352
+ {
5353
+ type: "button",
5354
+ "aria-label": "Show hidden breadcrumbs",
5355
+ className: "inline-flex h-8 w-8 items-center justify-center rounded-lg text-white/45 transition-colors hover:bg-white/10 hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40",
5356
+ children: /* @__PURE__ */ jsxRuntime.jsx(DotsIcon, {})
5357
+ }
5358
+ )
3945
5359
  }
3946
- },
3947
- children
3948
- }
3949
- )
3950
- ] });
5360
+ ) })
5361
+ ] }, `collapse-${index}`);
5362
+ }
5363
+ const isLast = entry.originalIndex === lastItemIndex;
5364
+ const item = entry.item;
5365
+ const interactiveClassName = "text-white/50 hover:text-white/80 transition-colors";
5366
+ return /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
5367
+ index > 0 ? /* @__PURE__ */ jsxRuntime.jsx("li", { className: "flex items-center", children: separator }) : null,
5368
+ /* @__PURE__ */ jsxRuntime.jsx("li", { className: "flex min-w-0 items-center", children: isLast ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex min-w-0 items-center gap-1.5 text-white font-medium", "aria-current": "page", children: [
5369
+ item.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-white/55", children: item.icon }) : null,
5370
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: item.label })
5371
+ ] }) : item.href ? renderLinkNode(item, interactiveClassName) : item.onClick ? /* @__PURE__ */ jsxRuntime.jsx(
5372
+ "button",
5373
+ {
5374
+ type: "button",
5375
+ onClick: item.onClick,
5376
+ className: cn("min-w-0", interactiveClassName),
5377
+ children: renderItemContent(item)
5378
+ }
5379
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white/50", children: renderItemContent(item) }) })
5380
+ ] }, `${entry.originalIndex}-${String(item.href ?? item.label)}`);
5381
+ }) }) });
3951
5382
  }
3952
5383
  var defaultFilter = (opt, q) => opt.label.toLowerCase().includes(q.toLowerCase());
3953
5384
  var Combobox = React.forwardRef(function Combobox2({
@@ -4270,6 +5701,12 @@ function VisuallyHidden({ children, as: Tag = "span", style, ...props }) {
4270
5701
  }
4271
5702
  );
4272
5703
  }
5704
+ function didResetKeysChange(previous, next) {
5705
+ if (!previous && !next) return false;
5706
+ if (!previous || !next) return true;
5707
+ if (previous.length !== next.length) return true;
5708
+ return previous.some((value, index) => !Object.is(value, next[index]));
5709
+ }
4273
5710
  var ErrorBoundary = class extends React.Component {
4274
5711
  constructor() {
4275
5712
  super(...arguments);
@@ -4284,6 +5721,12 @@ var ErrorBoundary = class extends React.Component {
4284
5721
  componentDidCatch(error, errorInfo) {
4285
5722
  this.props.onError?.(error, errorInfo);
4286
5723
  }
5724
+ componentDidUpdate(prevProps) {
5725
+ if (!this.state.error) return;
5726
+ if (!Object.is(prevProps.resetKey, this.props.resetKey) || didResetKeysChange(prevProps.resetKeys, this.props.resetKeys)) {
5727
+ this.reset();
5728
+ }
5729
+ }
4287
5730
  render() {
4288
5731
  const { error } = this.state;
4289
5732
  if (!error) return this.props.children;
@@ -4294,19 +5737,40 @@ var ErrorBoundary = class extends React.Component {
4294
5737
  if (fallback !== void 0) {
4295
5738
  return fallback;
4296
5739
  }
4297
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", className: cn("glass rounded-xl p-6 text-center"), children: [
4298
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-white mb-2", children: "Something went wrong" }),
4299
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-white/60 mb-4", children: error.message }),
4300
- /* @__PURE__ */ jsxRuntime.jsx(
4301
- "button",
4302
- {
4303
- type: "button",
4304
- onClick: this.reset,
4305
- className: "inline-flex items-center justify-center gap-2 rounded-xl font-semibold leading-none px-3.5 py-2.5 text-sm bg-gradient-to-r from-violet-600 to-purple-600 text-white shadow-glow hover:shadow-glow-lg hover:scale-[1.02] transition-[transform,background-color,box-shadow,opacity] active:translate-y-[0.5px]",
4306
- children: "Try again"
4307
- }
4308
- )
4309
- ] });
5740
+ const {
5741
+ actionLabel = "Try again",
5742
+ description,
5743
+ fullScreen = false,
5744
+ onAction,
5745
+ title = "Something went wrong"
5746
+ } = this.props;
5747
+ const descriptionContent = typeof description === "function" ? description(error) : description ?? error.message;
5748
+ const handleAction = () => {
5749
+ if (onAction) {
5750
+ onAction({ error, reset: this.reset });
5751
+ return;
5752
+ }
5753
+ this.reset();
5754
+ };
5755
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(
5756
+ "div",
5757
+ {
5758
+ role: "alert",
5759
+ className: cn(
5760
+ "glass rounded-xl p-6 text-center",
5761
+ fullScreen && "w-full max-w-md rounded-2xl p-8 shadow-surface"
5762
+ ),
5763
+ children: [
5764
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-white mb-2", children: title }),
5765
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-white/60 mb-4", children: descriptionContent }),
5766
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "primary", onClick: handleAction, children: actionLabel })
5767
+ ]
5768
+ }
5769
+ );
5770
+ if (fullScreen) {
5771
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-surface flex items-center justify-center p-6", children: content });
5772
+ }
5773
+ return content;
4310
5774
  }
4311
5775
  };
4312
5776
  function LoadingScreen({ message, size = "lg", className }) {
@@ -4341,6 +5805,8 @@ exports.ConfirmDialog = ConfirmDialog;
4341
5805
  exports.CooldownRing = CooldownRing;
4342
5806
  exports.CopyField = CopyField;
4343
5807
  exports.DashboardLayout = DashboardLayout;
5808
+ exports.DataTable = DataTable;
5809
+ exports.DateRangePicker = DateRangePicker;
4344
5810
  exports.Divider = Divider;
4345
5811
  exports.DotIndicator = DotIndicator;
4346
5812
  exports.Drawer = Drawer;
@@ -4394,6 +5860,7 @@ exports.Tabs = Tabs;
4394
5860
  exports.TagInput = TagInput;
4395
5861
  exports.Text = Text;
4396
5862
  exports.Textarea = Textarea;
5863
+ exports.Timeline = Timeline;
4397
5864
  exports.ToastProvider = ToastProvider;
4398
5865
  exports.Toggle = Toggle;
4399
5866
  exports.Tooltip = Tooltip;