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