@dimaan/ui 0.0.27 → 0.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -120,21 +120,21 @@ var AlertDialogDescription = react.forwardRef(function AlertDialogDescription2({
120
120
 
121
121
  // src/components/button/buttonVariants.ts
122
122
  var buttonVariantClass = {
123
- primary: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 focus-visible:ring-primary/40",
123
+ primary: "bg-primary text-primary-foreground shadow-[var(--shadow-btn)] hover:bg-primary/95 hover:-translate-y-px hover:shadow-[var(--shadow-btn-hover)] active:translate-y-0 active:shadow-[var(--shadow-btn-active)] focus-visible:ring-primary/40",
124
124
  secondary: "bg-muted text-foreground hover:bg-muted/80 focus-visible:ring-muted-foreground/30",
125
125
  outline: "border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground focus-visible:ring-ring/40",
126
126
  ghost: "bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground focus-visible:ring-ring/40",
127
- destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90 focus-visible:ring-destructive/40",
128
- success: "bg-success text-success-foreground shadow-sm hover:bg-success/90 focus-visible:ring-success/40",
129
- warning: "bg-warning text-warning-foreground shadow-sm hover:bg-warning/90 focus-visible:ring-warning/40",
127
+ destructive: "bg-destructive text-destructive-foreground shadow-[var(--shadow-solid)] hover:bg-destructive/95 hover:-translate-y-px hover:shadow-[var(--shadow-solid-hover)] active:translate-y-0 active:shadow-[var(--shadow-solid-active)] focus-visible:ring-destructive/40",
128
+ success: "bg-success text-success-foreground shadow-[var(--shadow-solid)] hover:bg-success/95 hover:-translate-y-px hover:shadow-[var(--shadow-solid-hover)] active:translate-y-0 active:shadow-[var(--shadow-solid-active)] focus-visible:ring-success/40",
129
+ warning: "bg-warning text-warning-foreground shadow-[var(--shadow-solid)] hover:bg-warning/95 hover:-translate-y-px hover:shadow-[var(--shadow-solid-hover)] active:translate-y-0 active:shadow-[var(--shadow-solid-active)] focus-visible:ring-warning/40",
130
130
  link: "text-primary underline-offset-4 hover:underline focus-visible:ring-primary/40 px-0 shadow-none"
131
131
  };
132
132
  var buttonSizeClass = {
133
- sm: "h-8 gap-1.5 rounded-md px-3 text-sm",
134
- md: "h-9 gap-2 rounded-md px-4 text-sm",
135
- lg: "h-11 gap-2.5 rounded-md px-6 text-base",
136
- icon: "h-9 w-9 shrink-0 rounded-md p-0",
137
- "icon-sm": "h-8 w-8 shrink-0 rounded-md p-0"
133
+ sm: "h-8 gap-1.5 rounded-[10px] px-3 text-sm",
134
+ md: "h-9 gap-2 rounded-[10px] px-4 text-sm",
135
+ lg: "h-11 gap-2.5 rounded-[10px] px-6 text-base",
136
+ icon: "size-9 shrink-0 rounded-[10px] p-0",
137
+ "icon-sm": "size-8 shrink-0 rounded-[10px] p-0"
138
138
  };
139
139
  var buttonBaseClass = "group/button relative inline-flex items-center justify-center font-medium select-none whitespace-nowrap outline-none transition-[background-color,color,box-shadow,opacity,transform] active:scale-[0.98] focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 motion-reduce:transition-none motion-reduce:active:scale-100 [&_svg]:pointer-events-none [&_svg]:shrink-0";
140
140
  var Button = react.forwardRef(function Button2({
@@ -197,10 +197,10 @@ var Button = react.forwardRef(function Button2({
197
197
  );
198
198
  });
199
199
  function Slot({ children }) {
200
- return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "inline-flex h-4 w-4 items-center justify-center", children });
200
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "inline-flex size-4 items-center justify-center", children });
201
201
  }
202
202
  function Spinner() {
203
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { "aria-hidden": "true", className: "h-4 w-4 animate-spin", "data-testid": "button-spinner" });
203
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { "aria-hidden": "true", className: "size-4 animate-spin", "data-testid": "button-spinner" });
204
204
  }
205
205
  var ConfirmDialogContext = react.createContext(null);
206
206
  function ConfirmDialogProvider({ labels, children }) {
@@ -475,7 +475,7 @@ var HeaderSearch = react.forwardRef(
475
475
  "span",
476
476
  {
477
477
  "aria-hidden": "true",
478
- className: "pointer-events-none absolute start-3 flex h-4 w-4 items-center justify-center text-muted-foreground",
478
+ className: "pointer-events-none absolute start-3 flex size-4 items-center justify-center text-muted-foreground",
479
479
  children: icon
480
480
  }
481
481
  ) : null,
@@ -602,6 +602,7 @@ function SidebarHeader({ className, children, ...props }) {
602
602
  function SidebarNav({ className, children, ...props }) {
603
603
  return /* @__PURE__ */ jsxRuntime.jsx("nav", { className: cn("flex flex-1 flex-col gap-1 overflow-y-auto p-2", className), ...props, children });
604
604
  }
605
+ var SidebarNavGroupContext = react.createContext(null);
605
606
  function SidebarNavGroup({
606
607
  icon,
607
608
  label,
@@ -627,19 +628,39 @@ function SidebarNavGroup({
627
628
  },
628
629
  [isControlled, onOpenChange]
629
630
  );
631
+ const [activeChildIds, setActiveChildIds] = react.useState(() => /* @__PURE__ */ new Set());
632
+ const reportActive = react.useCallback((id, isItemActive) => {
633
+ setActiveChildIds((prev) => {
634
+ if (isItemActive === prev.has(id)) return prev;
635
+ const next = new Set(prev);
636
+ if (isItemActive) next.add(id);
637
+ else next.delete(id);
638
+ return next;
639
+ });
640
+ }, []);
641
+ const contextValue = react.useMemo(() => ({ reportActive }), [reportActive]);
642
+ const hasActiveChild = activeChildIds.size > 0;
643
+ const isActive = active || hasActiveChild;
644
+ const prevHasActiveChild = react.useRef(false);
645
+ react.useEffect(() => {
646
+ if (hasActiveChild && !prevHasActiveChild.current && !collapsed) {
647
+ setOpen(true);
648
+ }
649
+ prevHasActiveChild.current = hasActiveChild;
650
+ }, [hasActiveChild, collapsed, setOpen]);
630
651
  react.useEffect(() => {
631
652
  if (collapsed && open) setOpen(false);
632
653
  }, [collapsed, open, setOpen]);
633
654
  const titleAttr = collapsed && typeof label === "string" ? label : props.title ?? void 0;
634
655
  const showChildren = !collapsed;
635
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
656
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-col", children: [
636
657
  /* @__PURE__ */ jsxRuntime.jsxs(
637
658
  "button",
638
659
  {
639
660
  type: "button",
640
661
  "aria-expanded": showChildren ? open : void 0,
641
662
  "aria-controls": showChildren ? submenuId : void 0,
642
- "data-active": active ? "true" : void 0,
663
+ "data-active": isActive ? "true" : void 0,
643
664
  title: titleAttr,
644
665
  onClick: (e) => {
645
666
  if (showChildren) setOpen(!open);
@@ -649,13 +670,20 @@ function SidebarNavGroup({
649
670
  "group relative flex h-9 w-full items-center gap-3 rounded-md px-3 text-sm font-medium outline-none transition-colors",
650
671
  "text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
651
672
  "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-sidebar",
652
- active && "bg-sidebar-accent text-sidebar-accent-foreground",
673
+ isActive && "bg-sidebar-accent text-sidebar-accent-foreground",
653
674
  collapsed && "justify-center px-0",
654
675
  className
655
676
  ),
656
677
  ...props,
657
678
  children: [
658
- icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "flex h-5 w-5 shrink-0 items-center justify-center", children: icon }) : null,
679
+ isActive ? /* @__PURE__ */ jsxRuntime.jsx(
680
+ "span",
681
+ {
682
+ "aria-hidden": "true",
683
+ className: "absolute inset-y-1.5 start-0 w-1 rounded-full bg-primary"
684
+ }
685
+ ) : null,
686
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "flex size-5 shrink-0 items-center justify-center", children: icon }) : null,
659
687
  /* @__PURE__ */ jsxRuntime.jsx(
660
688
  "span",
661
689
  {
@@ -680,7 +708,7 @@ function SidebarNavGroup({
680
708
  "grid transition-[grid-template-rows] duration-200 ease-out",
681
709
  showChildren && open ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
682
710
  ),
683
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5 ps-7 pt-1", children }) })
711
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5 ps-7 pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(SidebarNavGroupContext.Provider, { value: contextValue, children }) }) })
684
712
  }
685
713
  )
686
714
  ] });
@@ -691,7 +719,7 @@ function ChevronCaret({ open }) {
691
719
  {
692
720
  "aria-hidden": "true",
693
721
  className: cn(
694
- "h-3.5 w-3.5 shrink-0 text-muted-foreground transition-transform duration-200",
722
+ "size-3.5 shrink-0 text-muted-foreground transition-transform duration-200",
695
723
  open && "rotate-180"
696
724
  )
697
725
  }
@@ -710,13 +738,20 @@ function SidebarNavItem({
710
738
  ...props
711
739
  }) {
712
740
  const { collapsed } = useDashboardLayout();
713
- const location = reactRouterDom.useLocation();
714
741
  const resolved = reactRouterDom.useResolvedPath(to);
715
- const isActive = forcedActive || (end ? location.pathname === resolved.pathname : location.pathname.startsWith(resolved.pathname));
742
+ const group = react.useContext(SidebarNavGroupContext);
743
+ const itemId = react.useId();
744
+ const routeMatch = reactRouterDom.useMatch({ path: resolved.pathname, end: end ?? false });
745
+ const isActive = forcedActive || routeMatch != null;
746
+ react.useEffect(() => {
747
+ if (!group) return;
748
+ group.reportActive(itemId, isActive);
749
+ return () => group.reportActive(itemId, false);
750
+ }, [group, itemId, isActive]);
716
751
  const labelContent = label ?? children;
717
752
  const titleAttr = collapsed && typeof labelContent === "string" ? labelContent : props.title;
718
753
  const getClassName = (active) => cn(
719
- "group relative flex h-9 items-center gap-3 rounded-md px-3 text-sm font-medium outline-none transition-colors",
754
+ "group relative flex h-9 shrink-0 items-center gap-3 rounded-md px-3 text-sm font-medium outline-none transition-colors",
720
755
  "text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
721
756
  "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-sidebar",
722
757
  active && "bg-sidebar-accent text-sidebar-accent-foreground",
@@ -724,7 +759,14 @@ function SidebarNavItem({
724
759
  className
725
760
  );
726
761
  const innerContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
727
- icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "flex h-5 w-5 shrink-0 items-center justify-center", children: icon }) : null,
762
+ isActive ? /* @__PURE__ */ jsxRuntime.jsx(
763
+ "span",
764
+ {
765
+ "aria-hidden": "true",
766
+ className: "absolute inset-y-1.5 start-0 w-1 rounded-full bg-primary"
767
+ }
768
+ ) : null,
769
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "flex size-5 shrink-0 items-center justify-center", children: icon }) : null,
728
770
  /* @__PURE__ */ jsxRuntime.jsx(
729
771
  "span",
730
772
  {
@@ -842,9 +884,9 @@ function AppShell({
842
884
  ) });
843
885
  }
844
886
  var sizeClass = {
845
- sm: "h-7 w-7 text-xs",
846
- md: "h-9 w-9 text-sm",
847
- lg: "h-11 w-11 text-base"
887
+ sm: "size-7 text-xs",
888
+ md: "size-9 text-sm",
889
+ lg: "size-11 text-base"
848
890
  };
849
891
  function Avatar({ src, alt = "", fallback, size = "md", className, ...props }) {
850
892
  const [errored, setErrored] = react.useState(false);
@@ -880,6 +922,14 @@ var badgeVariantClass = {
880
922
  destructive: "bg-destructive text-destructive-foreground border-transparent",
881
923
  outline: "border-border bg-transparent text-foreground"
882
924
  };
925
+ var badgeSoftVariantClass = {
926
+ default: "bg-muted text-muted-foreground border-transparent",
927
+ primary: "bg-primary/15 text-primary-soft-foreground border-transparent",
928
+ success: "bg-success/15 text-success-soft-foreground border-transparent",
929
+ warning: "bg-warning/15 text-warning-soft-foreground border-transparent",
930
+ destructive: "bg-destructive/15 text-destructive-soft-foreground border-transparent",
931
+ outline: "border-border bg-transparent text-foreground"
932
+ };
883
933
  var badgeSizeClass = {
884
934
  sm: "h-5 gap-1 px-2 text-[11px]",
885
935
  md: "h-6 gap-1.5 px-2.5 text-xs"
@@ -889,14 +939,16 @@ var badgeDotSizeClass = {
889
939
  md: "size-2"
890
940
  };
891
941
  var badgeBaseClass = "inline-flex shrink-0 items-center rounded-full border font-medium leading-none whitespace-nowrap select-none transition-colors";
892
- var Badge = react.forwardRef(function Badge2({ variant = "default", size = "md", dot = false, className, children, ...props }, ref) {
942
+ var Badge = react.forwardRef(function Badge2({ variant = "default", size = "md", tone = "solid", dot = false, className, children, ...props }, ref) {
943
+ const variantClass = tone === "soft" ? badgeSoftVariantClass[variant] : badgeVariantClass[variant];
893
944
  return /* @__PURE__ */ jsxRuntime.jsxs(
894
945
  "span",
895
946
  {
896
947
  ref,
897
948
  "data-slot": "badge",
898
949
  "data-variant": variant,
899
- className: cn(badgeBaseClass, badgeVariantClass[variant], badgeSizeClass[size], className),
950
+ "data-tone": tone,
951
+ className: cn(badgeBaseClass, variantClass, badgeSizeClass[size], className),
900
952
  ...props,
901
953
  children: [
902
954
  dot ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -911,9 +963,75 @@ var Badge = react.forwardRef(function Badge2({ variant = "default", size = "md",
911
963
  }
912
964
  );
913
965
  });
966
+
967
+ // src/components/card/cardVariants.ts
968
+ var cardBaseClass = "rounded-xl border border-border bg-card text-card-foreground shadow-[var(--shadow-card)]";
969
+ var cardHeaderClass = "flex flex-col gap-1.5 p-6";
970
+ var cardTitleClass = "text-lg font-semibold leading-none tracking-tight text-foreground";
971
+ var cardDescriptionClass = "text-sm text-muted-foreground";
972
+ var cardContentClass = "p-6 pt-0";
973
+ var cardFooterClass = "flex items-center gap-2 p-6 pt-0";
974
+ var Card = react.forwardRef(function Card2({ className, ...props }, ref) {
975
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, "data-slot": "card", className: cn(cardBaseClass, className), ...props });
976
+ });
977
+ var CardHeader = react.forwardRef(
978
+ function CardHeader2({ className, ...props }, ref) {
979
+ return /* @__PURE__ */ jsxRuntime.jsx(
980
+ "div",
981
+ {
982
+ ref,
983
+ "data-slot": "card-header",
984
+ className: cn(cardHeaderClass, className),
985
+ ...props
986
+ }
987
+ );
988
+ }
989
+ );
990
+ var CardTitle = react.forwardRef(
991
+ function CardTitle2({ className, ...props }, ref) {
992
+ return /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, "data-slot": "card-title", className: cn(cardTitleClass, className), ...props });
993
+ }
994
+ );
995
+ var CardDescription = react.forwardRef(function CardDescription2({ className, ...props }, ref) {
996
+ return /* @__PURE__ */ jsxRuntime.jsx(
997
+ "p",
998
+ {
999
+ ref,
1000
+ "data-slot": "card-description",
1001
+ className: cn(cardDescriptionClass, className),
1002
+ ...props
1003
+ }
1004
+ );
1005
+ });
1006
+ var CardContent = react.forwardRef(
1007
+ function CardContent2({ className, ...props }, ref) {
1008
+ return /* @__PURE__ */ jsxRuntime.jsx(
1009
+ "div",
1010
+ {
1011
+ ref,
1012
+ "data-slot": "card-content",
1013
+ className: cn(cardContentClass, className),
1014
+ ...props
1015
+ }
1016
+ );
1017
+ }
1018
+ );
1019
+ var CardFooter = react.forwardRef(
1020
+ function CardFooter2({ className, ...props }, ref) {
1021
+ return /* @__PURE__ */ jsxRuntime.jsx(
1022
+ "div",
1023
+ {
1024
+ ref,
1025
+ "data-slot": "card-footer",
1026
+ className: cn(cardFooterClass, className),
1027
+ ...props
1028
+ }
1029
+ );
1030
+ }
1031
+ );
914
1032
  var sizeClass2 = {
915
- sm: "h-3.5 w-3.5",
916
- md: "h-4 w-4"
1033
+ sm: "size-3.5",
1034
+ md: "size-4"
917
1035
  };
918
1036
  var Checkbox = react.forwardRef(function Checkbox2({
919
1037
  checked,
@@ -956,7 +1074,7 @@ var Checkbox = react.forwardRef(function Checkbox2({
956
1074
  "indeterminate:border-primary indeterminate:bg-primary",
957
1075
  "hover:border-ring",
958
1076
  "disabled:cursor-not-allowed disabled:opacity-50",
959
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background"
1077
+ "focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-primary-glow"
960
1078
  ),
961
1079
  ...rest
962
1080
  }
@@ -966,7 +1084,7 @@ var Checkbox = react.forwardRef(function Checkbox2({
966
1084
  {
967
1085
  "aria-hidden": "true",
968
1086
  strokeWidth: 3,
969
- className: "pointer-events-none absolute inset-0 m-auto h-3 w-3 text-primary-foreground opacity-0 peer-checked:opacity-100 peer-indeterminate:opacity-0"
1087
+ className: "pointer-events-none absolute inset-0 m-auto size-3 text-primary-foreground opacity-0 peer-checked:opacity-100 peer-indeterminate:opacity-0"
970
1088
  }
971
1089
  ),
972
1090
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -974,7 +1092,7 @@ var Checkbox = react.forwardRef(function Checkbox2({
974
1092
  {
975
1093
  "aria-hidden": "true",
976
1094
  strokeWidth: 3,
977
- className: "pointer-events-none absolute inset-0 m-auto h-3 w-3 text-primary-foreground opacity-0 peer-indeterminate:opacity-100"
1095
+ className: "pointer-events-none absolute inset-0 m-auto size-3 text-primary-foreground opacity-0 peer-indeterminate:opacity-100"
978
1096
  }
979
1097
  )
980
1098
  ] });
@@ -991,20 +1109,20 @@ var datePickerTriggerSizeClass = {
991
1109
  md: "h-9 rounded-md ps-3 pe-9 text-sm gap-2",
992
1110
  lg: "h-11 rounded-md ps-4 pe-10 text-base gap-2"
993
1111
  };
994
- var datePickerTriggerBaseClass = "group/datepicker relative inline-flex w-full items-center text-foreground outline-none transition-[background-color,border-color,box-shadow] focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive/40 disabled:pointer-events-none disabled:opacity-50 cursor-pointer";
1112
+ var datePickerTriggerBaseClass = "group/datepicker relative inline-flex w-full items-center text-foreground outline-none transition-[background-color,border-color,box-shadow] focus-visible:ring-[3px] focus-visible:ring-primary-glow aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive/40 disabled:pointer-events-none disabled:opacity-50 cursor-pointer";
995
1113
  var datePickerPlaceholderClass = "truncate text-muted-foreground";
996
1114
  var datePickerValueClass = "truncate text-foreground";
997
1115
  var datePickerContentClass = "z-50 overflow-hidden rounded-md border border-border bg-popover p-3 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95";
998
1116
  var datePickerCalendarClass = "text-sm";
999
1117
  var datePickerCaptionClass = "flex items-center justify-between gap-2 pb-2 text-sm font-semibold";
1000
- var datePickerNavButtonClass = "inline-flex h-7 w-7 items-center justify-center rounded-md border border-input bg-background text-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50";
1118
+ var datePickerNavButtonClass = "inline-flex size-7 items-center justify-center rounded-md border border-input bg-background text-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50";
1001
1119
  var datePickerDayWrapperClass = "p-0 text-center";
1002
- var datePickerDayBaseClass = "inline-flex h-8 w-8 items-center justify-center rounded-md text-sm text-foreground font-normal transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40";
1120
+ var datePickerDayBaseClass = "inline-flex size-8 items-center justify-center rounded-md text-sm text-foreground font-normal transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40";
1003
1121
  var datePickerSelectedClass = "[&_button]:bg-primary [&_button]:text-primary-foreground [&_button]:hover:bg-primary [&_button]:hover:text-primary-foreground";
1004
1122
  var datePickerTodayClass = "[&_button]:font-semibold [&_button]:ring-1 [&_button]:ring-inset [&_button]:ring-ring/40";
1005
1123
  var datePickerOutsideClass = "[&_button]:text-muted-foreground [&_button]:opacity-60";
1006
1124
  var datePickerDisabledClass = "[&_button]:pointer-events-none [&_button]:opacity-40";
1007
- var datePickerWeekdayClass = "h-8 w-8 text-center text-xs font-medium text-muted-foreground";
1125
+ var datePickerWeekdayClass = "size-8 text-center text-xs font-medium text-muted-foreground";
1008
1126
  var datePickerWeekClass = "flex w-full";
1009
1127
  var datePickerWeekdaysClass = "flex w-full";
1010
1128
  var datePickerMonthGridClass = "w-full border-collapse";
@@ -1315,6 +1433,9 @@ var pageHeaderBorderedClass = "border-b border-border pb-4";
1315
1433
  var pageHeaderTitleRowClass = "flex flex-wrap items-start justify-between gap-3 sm:gap-4";
1316
1434
  var pageHeaderTitleBlockClass = "min-w-0 flex-1 space-y-1";
1317
1435
  var pageHeaderTitleClass = "text-2xl font-semibold tracking-tight text-foreground";
1436
+ var pageHeaderEyebrowClass = "text-xs font-semibold uppercase tracking-wide text-primary";
1437
+ var pageHeaderTitleLineClass = "flex flex-wrap items-center gap-x-2.5 gap-y-1";
1438
+ var pageHeaderTitleMetaClass = "shrink-0";
1318
1439
  var pageHeaderDescriptionClass = "text-sm text-muted-foreground";
1319
1440
  var pageHeaderActionsClass = "flex shrink-0 flex-wrap items-center gap-2";
1320
1441
  var pageHeaderBackClass = "inline-flex items-center gap-1.5 self-start text-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-md";
@@ -1323,6 +1444,8 @@ var pageHeaderBreadcrumbsClass = "text-xs text-muted-foreground";
1323
1444
  var PageHeader = react.forwardRef(function PageHeader2({
1324
1445
  title,
1325
1446
  description,
1447
+ eyebrow,
1448
+ titleMeta,
1326
1449
  breadcrumbs,
1327
1450
  back,
1328
1451
  actions,
@@ -1343,11 +1466,15 @@ var PageHeader = react.forwardRef(function PageHeader2({
1343
1466
  back ? /* @__PURE__ */ jsxRuntime.jsx(PageHeaderBack, { ...back }) : null,
1344
1467
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "page-header-row", className: pageHeaderTitleRowClass, children: [
1345
1468
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: pageHeaderTitleBlockClass, children: [
1346
- react.createElement(
1347
- as,
1348
- { "data-slot": "page-header-title", className: pageHeaderTitleClass },
1349
- title
1350
- ),
1469
+ eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-slot": "page-header-eyebrow", className: pageHeaderEyebrowClass, children: eyebrow }) : null,
1470
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: pageHeaderTitleLineClass, children: [
1471
+ react.createElement(
1472
+ as,
1473
+ { "data-slot": "page-header-title", className: pageHeaderTitleClass },
1474
+ title
1475
+ ),
1476
+ titleMeta ? /* @__PURE__ */ jsxRuntime.jsx("span", { "data-slot": "page-header-title-meta", className: pageHeaderTitleMetaClass, children: titleMeta }) : null
1477
+ ] }),
1351
1478
  description ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-slot": "page-header-description", className: pageHeaderDescriptionClass, children: description }) : null
1352
1479
  ] }),
1353
1480
  actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "page-header-actions", className: pageHeaderActionsClass, children: actions }) : null
@@ -1379,7 +1506,7 @@ function PageHeaderBack({ label = "Back", to, onClick, render }) {
1379
1506
  var detailPageBaseClass = "flex w-full flex-col gap-6";
1380
1507
  var detailPageBodyClass = "flex flex-col gap-6";
1381
1508
  var detailPageSkeletonRowClass = "h-5 w-full animate-pulse rounded-md bg-muted";
1382
- var detailPageEmptyClass = "rounded-md border border-border bg-card";
1509
+ var detailPageEmptyClass = "rounded-xl border border-border bg-card";
1383
1510
  var DEFAULT_LABELS_LTR = {
1384
1511
  back: "Back",
1385
1512
  notFoundTitle: "Not found",
@@ -2046,7 +2173,7 @@ var inputSizeClass = {
2046
2173
  md: "h-9 rounded-md px-3 text-sm gap-2",
2047
2174
  lg: "h-11 rounded-md px-4 text-base gap-2.5"
2048
2175
  };
2049
- var inputBaseClass = "group/input relative inline-flex w-full items-center text-foreground outline-none transition-[background-color,border-color,box-shadow] focus-within:ring-2 focus-within:ring-ring/40 focus-within:ring-offset-1 focus-within:ring-offset-background aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive/40 has-[input:disabled]:pointer-events-none has-[input:disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0";
2176
+ var inputBaseClass = "group/input relative inline-flex w-full items-center text-foreground outline-none transition-[background-color,border-color,box-shadow] focus-within:ring-[3px] focus-within:ring-primary-glow aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive/40 has-[input:disabled]:pointer-events-none has-[input:disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0";
2050
2177
  var Input = react.forwardRef(function Input2({
2051
2178
  variant = "default",
2052
2179
  inputSize = "md",
@@ -2080,7 +2207,7 @@ var Input = react.forwardRef(function Input2({
2080
2207
  "span",
2081
2208
  {
2082
2209
  "aria-hidden": "true",
2083
- className: "inline-flex h-4 w-4 items-center justify-center text-muted-foreground",
2210
+ className: "inline-flex size-4 items-center justify-center text-muted-foreground",
2084
2211
  children: leadingIcon
2085
2212
  }
2086
2213
  ) : null,
@@ -2104,7 +2231,7 @@ var Input = react.forwardRef(function Input2({
2104
2231
  "span",
2105
2232
  {
2106
2233
  "aria-hidden": "true",
2107
- className: "inline-flex h-4 w-4 items-center justify-center text-muted-foreground",
2234
+ className: "inline-flex size-4 items-center justify-center text-muted-foreground",
2108
2235
  children: trailingIcon
2109
2236
  }
2110
2237
  ) : null
@@ -2225,7 +2352,7 @@ function Pagination({
2225
2352
  disabled: isFirst,
2226
2353
  onClick: goPrev,
2227
2354
  "aria-label": labels.previousPage,
2228
- children: isRtl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
2355
+ children: isRtl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { "aria-hidden": "true", className: "size-3.5" })
2229
2356
  }
2230
2357
  ),
2231
2358
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 text-foreground", children: [
@@ -2242,7 +2369,7 @@ function Pagination({
2242
2369
  disabled: isLast,
2243
2370
  onClick: goNext,
2244
2371
  "aria-label": labels.nextPage,
2245
- children: isRtl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
2372
+ children: isRtl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "size-3.5" })
2246
2373
  }
2247
2374
  )
2248
2375
  ] })
@@ -2271,23 +2398,23 @@ function Toolbar({ count, onClear, renderLabel, clearLabel, children }) {
2271
2398
  var tableSizeClass = {
2272
2399
  sm: {
2273
2400
  row: "",
2274
- cell: "px-3 py-1.5 text-xs",
2401
+ cell: "px-3 py-1.5 text-xs tabular-nums",
2275
2402
  head: "whitespace-nowrap px-3 py-2 text-xs font-medium"
2276
2403
  },
2277
2404
  md: {
2278
2405
  row: "",
2279
- cell: "px-4 py-2.5 text-sm",
2406
+ cell: "px-4 py-2.5 text-sm tabular-nums",
2280
2407
  head: "whitespace-nowrap px-4 py-2.5 text-xs font-medium uppercase tracking-wide"
2281
2408
  },
2282
2409
  lg: {
2283
2410
  row: "",
2284
- cell: "px-5 py-3.5 text-sm",
2411
+ cell: "px-5 py-3.5 text-sm tabular-nums",
2285
2412
  head: "whitespace-nowrap px-5 py-3 text-sm font-medium"
2286
2413
  }
2287
2414
  };
2288
2415
  var tableBaseClass = "w-full caption-bottom border-collapse";
2289
- var selectedRowClass = "bg-muted/40";
2290
- var sortIconClass = "inline-flex h-3 w-3 shrink-0 items-center justify-center";
2416
+ var selectedRowClass = "bg-primary/10";
2417
+ var sortIconClass = "inline-flex size-3 shrink-0 items-center justify-center";
2291
2418
  var alignClass = {
2292
2419
  start: "text-start",
2293
2420
  center: "text-center",
@@ -2414,7 +2541,7 @@ function Table(props) {
2414
2541
  "div",
2415
2542
  {
2416
2543
  className: cn(
2417
- "overflow-x-auto rounded-md border border-border bg-background",
2544
+ "overflow-x-auto rounded-xl border border-border bg-card shadow-[var(--shadow-card)]",
2418
2545
  maxHeight !== void 0 && "overflow-y-auto"
2419
2546
  ),
2420
2547
  style: maxHeight !== void 0 ? { maxHeight } : void 0,
@@ -2432,9 +2559,11 @@ function Table(props) {
2432
2559
  "thead",
2433
2560
  {
2434
2561
  className: cn(
2435
- // Opaque (not bg-muted/40) so a sticky header fully hides the rows
2436
- // scrolling underneath it.
2437
- "bg-muted text-muted-foreground",
2562
+ // Clean opaque header (so a sticky header fully hides the rows
2563
+ // scrolling underneath it) with a hairline bottom rule drawn via an
2564
+ // inset shadow — it stays attached to the sticky header instead of
2565
+ // collapsing into the first row's border.
2566
+ "bg-card text-muted-foreground shadow-[inset_0_-1px_0_var(--color-border)]",
2438
2567
  maxHeight !== void 0 && "sticky top-0 z-10"
2439
2568
  ),
2440
2569
  children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
@@ -2511,8 +2640,8 @@ function Table(props) {
2511
2640
  "data-selected": isSelected ? "true" : void 0,
2512
2641
  "aria-selected": enableRowSelection ? isSelected : void 0,
2513
2642
  className: cn(
2514
- "border-t border-border transition-colors",
2515
- "hover:bg-accent",
2643
+ "border-t border-border/60 first:border-t-0 transition-colors",
2644
+ "hover:bg-primary/5",
2516
2645
  striped && rowIndex % 2 === 1 && "bg-muted/20",
2517
2646
  isSelected && selectedRowClass,
2518
2647
  onRowClick && "cursor-pointer"
@@ -2595,10 +2724,7 @@ function SkeletonRows({ rowCount, columnCount, cellClassName }) {
2595
2724
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: rowKeys.map((rowKey) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "border-t border-border", "data-testid": "table-skeleton-row", children: colKeys.map((colKey) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: cellClassName, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block h-3 w-full animate-pulse rounded bg-muted" }) }, `${rowKey}-${colKey}`)) }, rowKey)) });
2596
2725
  }
2597
2726
  function SortIndicator({ active, direction }) {
2598
- const className = cn(
2599
- "h-3.5 w-3.5 shrink-0",
2600
- active ? "text-foreground" : "text-muted-foreground"
2601
- );
2727
+ const className = cn("size-3.5 shrink-0", active ? "text-foreground" : "text-muted-foreground");
2602
2728
  if (!active) return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { "aria-hidden": "true", className });
2603
2729
  return direction === "asc" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { "aria-hidden": "true", className }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": "true", className });
2604
2730
  }
@@ -2614,13 +2740,14 @@ var selectSizeClass = {
2614
2740
  md: "h-9 rounded-md ps-3 pe-9 text-sm",
2615
2741
  lg: "h-11 rounded-md ps-4 pe-10 text-base"
2616
2742
  };
2617
- var selectBaseClass = "group/select relative inline-flex w-full items-center text-foreground outline-none transition-[background-color,border-color,box-shadow] focus:ring-2 focus:ring-ring/40 focus:ring-offset-1 focus:ring-offset-background aria-[invalid=true]:border-destructive aria-[invalid=true]:focus:ring-destructive/40 disabled:pointer-events-none disabled:opacity-50 cursor-pointer data-[placeholder]:text-muted-foreground";
2743
+ var selectBaseClass = "group/select relative inline-flex w-full items-center text-foreground outline-none transition-[background-color,border-color,box-shadow] focus:ring-[3px] focus:ring-primary-glow aria-[invalid=true]:border-destructive aria-[invalid=true]:focus:ring-destructive/40 disabled:pointer-events-none disabled:opacity-50 cursor-pointer data-[placeholder]:text-muted-foreground";
2618
2744
  var selectContentClass = "z-50 max-h-(--radix-select-content-available-height) min-w-(--radix-select-trigger-width) overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95";
2619
2745
  var selectViewportClass = "p-1";
2620
2746
  var selectItemClass = "relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
2621
- var selectItemIndicatorClass = "absolute start-2 inline-flex h-3.5 w-3.5 items-center justify-center [&_svg]:h-3.5 [&_svg]:w-3.5";
2747
+ var selectItemIndicatorClass = "absolute start-2 inline-flex size-3.5 items-center justify-center [&_svg]:h-3.5 [&_svg]:w-3.5";
2622
2748
  var selectGroupLabelClass = "px-2 py-1.5 text-xs font-semibold text-muted-foreground";
2623
2749
  var selectSeparatorClass = "-mx-1 my-1 h-px bg-border";
2750
+ var selectStatusClass = "flex items-center justify-center gap-2 px-2 py-6 text-center text-sm text-muted-foreground";
2624
2751
 
2625
2752
  // src/components/multi-select/multiSelectVariants.ts
2626
2753
  var multiSelectTriggerSizeClass = {
@@ -2638,11 +2765,13 @@ var multiSelectOptionClass = "flex w-full cursor-pointer select-none items-cente
2638
2765
  var multiSelectEmptyClass = "px-2 py-6 text-center text-sm text-muted-foreground";
2639
2766
  var DEFAULT_LABELS_LTR4 = {
2640
2767
  search: "Search\u2026",
2641
- empty: "No results"
2768
+ empty: "No results",
2769
+ loading: "Loading\u2026"
2642
2770
  };
2643
2771
  var DEFAULT_LABELS_RTL4 = {
2644
2772
  search: "\u0628\u062D\u062B\u2026",
2645
- empty: "\u0644\u0627 \u0646\u062A\u0627\u0626\u062C"
2773
+ empty: "\u0644\u0627 \u0646\u062A\u0627\u0626\u062C",
2774
+ loading: "\u062C\u0627\u0631\u064D \u0627\u0644\u062A\u062D\u0645\u064A\u0644\u2026"
2646
2775
  };
2647
2776
  function toArray(value) {
2648
2777
  return Array.isArray(value) ? value : [];
@@ -2652,6 +2781,7 @@ var MultiSelect = react.forwardRef(function MultiSelect2({
2652
2781
  selectSize = "md",
2653
2782
  options,
2654
2783
  placeholder,
2784
+ loading = false,
2655
2785
  value,
2656
2786
  defaultValue,
2657
2787
  onValueChange,
@@ -2732,7 +2862,10 @@ var MultiSelect = react.forwardRef(function MultiSelect2({
2732
2862
  className
2733
2863
  ),
2734
2864
  children: [
2735
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: multiSelectValueRowClass, children: selected.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-muted-foreground", children: placeholder }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2865
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: multiSelectValueRowClass, children: loading ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2 text-muted-foreground", children: [
2866
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin" }),
2867
+ labels.loading
2868
+ ] }) : selected.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-muted-foreground", children: placeholder }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2736
2869
  shownValues.map((v) => /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "default", size: "sm", className: multiSelectChipClass, children: [
2737
2870
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: labelByValue.get(v) ?? v }),
2738
2871
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2767,7 +2900,7 @@ var MultiSelect = react.forwardRef(function MultiSelect2({
2767
2900
  ]
2768
2901
  }
2769
2902
  ) }),
2770
- /* @__PURE__ */ jsxRuntime.jsx(RadixPopover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
2903
+ /* @__PURE__ */ jsxRuntime.jsx(RadixPopover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2771
2904
  RadixPopover__namespace.Content,
2772
2905
  {
2773
2906
  align: "start",
@@ -2777,7 +2910,10 @@ var MultiSelect = react.forwardRef(function MultiSelect2({
2777
2910
  onOpenAutoFocus: (event) => {
2778
2911
  if (!searchable) event.preventDefault();
2779
2912
  },
2780
- children: [
2913
+ children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: multiSelectEmptyClass, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center justify-center gap-2", children: [
2914
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin" }),
2915
+ labels.loading
2916
+ ] }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2781
2917
  searchable ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: multiSelectSearchRowClass, children: /* @__PURE__ */ jsxRuntime.jsx(
2782
2918
  Input,
2783
2919
  {
@@ -2817,7 +2953,7 @@ var MultiSelect = react.forwardRef(function MultiSelect2({
2817
2953
  option.value
2818
2954
  );
2819
2955
  }) })
2820
- ]
2956
+ ] })
2821
2957
  }
2822
2958
  ) })
2823
2959
  ] });
@@ -2831,6 +2967,9 @@ var Select = react.forwardRef(function Select2({
2831
2967
  selectSize = "md",
2832
2968
  options,
2833
2969
  placeholder,
2970
+ loading = false,
2971
+ loadingText = "Loading\u2026",
2972
+ emptyText = "No options",
2834
2973
  value,
2835
2974
  defaultValue,
2836
2975
  onValueChange,
@@ -2889,7 +3028,7 @@ var Select = react.forwardRef(function Select2({
2889
3028
  className
2890
3029
  ),
2891
3030
  children: [
2892
- /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.Value, { placeholder }),
3031
+ /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.Value, { placeholder, children: loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center gap-2 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(SelectLoading, { text: loadingText }) }) : void 0 }),
2893
3032
  /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "pointer-events-none absolute end-3 top-1/2 size-4 shrink-0 -translate-y-1/2 text-muted-foreground" }) })
2894
3033
  ]
2895
3034
  }
@@ -2903,7 +3042,7 @@ var Select = react.forwardRef(function Select2({
2903
3042
  className: selectContentClass,
2904
3043
  children: [
2905
3044
  /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.ScrollUpButton, { className: "flex h-6 cursor-default items-center justify-center bg-popover text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "size-4" }) }),
2906
- /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.Viewport, { className: selectViewportClass, children: children ?? (options ? renderOptions(options) : null) }),
3045
+ /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.Viewport, { className: selectViewportClass, children: children ?? renderViewportContent({ loading, options, loadingText, emptyText }) }),
2907
3046
  /* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.ScrollDownButton, { className: "flex h-6 cursor-default items-center justify-center bg-popover text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4" }) })
2908
3047
  ]
2909
3048
  }
@@ -2912,6 +3051,26 @@ var Select = react.forwardRef(function Select2({
2912
3051
  }
2913
3052
  );
2914
3053
  });
3054
+ function SelectLoading({ text }) {
3055
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3056
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin" }),
3057
+ text
3058
+ ] });
3059
+ }
3060
+ function renderViewportContent({
3061
+ loading,
3062
+ options,
3063
+ loadingText,
3064
+ emptyText
3065
+ }) {
3066
+ if (loading) {
3067
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: selectStatusClass, role: "presentation", children: /* @__PURE__ */ jsxRuntime.jsx(SelectLoading, { text: loadingText }) });
3068
+ }
3069
+ if (!options || options.length === 0) {
3070
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: selectStatusClass, role: "presentation", children: emptyText });
3071
+ }
3072
+ return renderOptions(options);
3073
+ }
2915
3074
  function renderOptions(options) {
2916
3075
  if (isGroupedOptions(options)) {
2917
3076
  const lastIndex = options.length - 1;
@@ -2948,10 +3107,21 @@ function hasActiveFilters(filters, values) {
2948
3107
  }
2949
3108
  return false;
2950
3109
  }
3110
+ function countActiveFilters(filters, values) {
3111
+ let count = 0;
3112
+ for (const filter of filters ?? []) {
3113
+ const current = values?.[filter.key];
3114
+ if (current === void 0) continue;
3115
+ const value = filter.type === "text" ? current.trim() : current;
3116
+ if (value !== filterDefaultValue(filter)) count += 1;
3117
+ }
3118
+ return count;
3119
+ }
2951
3120
  function DebouncedFilterInput({
2952
3121
  value,
2953
3122
  onChange,
2954
3123
  debounceMs,
3124
+ id,
2955
3125
  ariaLabel,
2956
3126
  placeholder,
2957
3127
  wrapperClassName,
@@ -2989,6 +3159,7 @@ function DebouncedFilterInput({
2989
3159
  return /* @__PURE__ */ jsxRuntime.jsx(
2990
3160
  Input,
2991
3161
  {
3162
+ id,
2992
3163
  type: "search",
2993
3164
  "aria-label": ariaLabel,
2994
3165
  placeholder,
@@ -3010,7 +3181,6 @@ function ListPageFilterBar({
3010
3181
  labels
3011
3182
  }) {
3012
3183
  const manual = mode === "manual";
3013
- const active = hasActiveFilters(filters, values);
3014
3184
  const appliedKey = JSON.stringify(values ?? {});
3015
3185
  const [draft, setDraft] = react.useState(values ?? {});
3016
3186
  react.useEffect(() => {
@@ -3041,8 +3211,11 @@ function ListPageFilterBar({
3041
3211
  for (const filter of filters ?? []) {
3042
3212
  onChange?.(filter.key, filterDefaultValue(filter));
3043
3213
  }
3214
+ if (manual) setDraft({});
3044
3215
  };
3045
- const controls = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: filters?.map((filter) => /* @__PURE__ */ jsxRuntime.jsx(
3216
+ if (!filters || filters.length === 0) return null;
3217
+ const activeCount = countActiveFilters(filters, effectiveValues);
3218
+ const controls = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: filters.map((filter) => /* @__PURE__ */ jsxRuntime.jsx(
3046
3219
  FilterControl,
3047
3220
  {
3048
3221
  filter,
@@ -3053,26 +3226,55 @@ function ListPageFilterBar({
3053
3226
  },
3054
3227
  filter.key
3055
3228
  )) });
3056
- const resetButton = active && !disabled ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", onClick: reset, children: [
3057
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "size-4" }),
3058
- labels.reset
3059
- ] }) : null;
3229
+ const header = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-primary/5 px-4 py-3", children: [
3230
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-foreground", children: labels.title ?? "Filters" }),
3231
+ activeCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center rounded-full bg-primary/10 px-2 py-0.5 text-xs font-semibold text-primary", children: [
3232
+ activeCount,
3233
+ " ",
3234
+ labels.activeLabel ?? "active"
3235
+ ] }) : null,
3236
+ activeCount > 0 && !disabled ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "ms-auto", onClick: reset, children: [
3237
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "size-4" }),
3238
+ labels.reset
3239
+ ] }) : null
3240
+ ] });
3241
+ const cardClass = "overflow-hidden rounded-xl border border-border bg-card";
3060
3242
  if (manual) {
3061
- return /* @__PURE__ */ jsxRuntime.jsxs("form", { "data-slot": "list-page-filter-bar", className: "space-y-3", onSubmit: apply, children: [
3062
- controls,
3063
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
3064
- resetButton,
3065
- /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", size: "sm", disabled: disabled || !dirty, children: labels.apply ?? "Apply" })
3243
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { "data-slot": "list-page-filter-bar", className: cardClass, onSubmit: apply, children: [
3244
+ header,
3245
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 p-4", children: [
3246
+ controls,
3247
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(
3248
+ Button,
3249
+ {
3250
+ type: "submit",
3251
+ size: "sm",
3252
+ leadingIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "size-4" }),
3253
+ className: "min-w-32",
3254
+ disabled: disabled || !dirty,
3255
+ children: labels.apply ?? "Apply"
3256
+ }
3257
+ ) })
3066
3258
  ] })
3067
3259
  ] });
3068
3260
  }
3069
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "list-page-filter-bar", className: "space-y-3", children: [
3070
- controls,
3071
- resetButton ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: resetButton }) : null
3261
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "list-page-filter-bar", className: cardClass, children: [
3262
+ header,
3263
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: controls })
3072
3264
  ] });
3073
3265
  }
3074
3266
  function FilterControl({ filter, value, onChange, disabled, mode }) {
3075
3267
  const spanClass = FILTER_SPAN_CLASS[filter.width ?? "default"];
3268
+ const label = filter.label ?? filter.key;
3269
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, className: spanClass, children: renderFilterControl({ filter, value, onChange, disabled, mode }) });
3270
+ }
3271
+ function renderFilterControl({
3272
+ filter,
3273
+ value,
3274
+ onChange,
3275
+ disabled,
3276
+ mode
3277
+ }) {
3076
3278
  const ariaLabel = typeof filter.label === "string" ? filter.label : filter.key;
3077
3279
  switch (filter.type) {
3078
3280
  case "select":
@@ -3083,7 +3285,6 @@ function FilterControl({ filter, value, onChange, disabled, mode }) {
3083
3285
  value: value ?? filterDefaultValue(filter),
3084
3286
  onValueChange: (v) => onChange?.(filter.key, v),
3085
3287
  options: filter.options,
3086
- className: spanClass,
3087
3288
  disabled
3088
3289
  }
3089
3290
  );
@@ -3096,7 +3297,6 @@ function FilterControl({ filter, value, onChange, disabled, mode }) {
3096
3297
  debounceMs: mode === "live" ? filter.debounceMs ?? DEFAULT_TEXT_DEBOUNCE_MS : 0,
3097
3298
  ariaLabel,
3098
3299
  placeholder: filter.placeholder,
3099
- wrapperClassName: spanClass,
3100
3300
  disabled
3101
3301
  }
3102
3302
  );
@@ -3108,7 +3308,6 @@ function FilterControl({ filter, value, onChange, disabled, mode }) {
3108
3308
  placeholder: filter.placeholder,
3109
3309
  value: value ?? "",
3110
3310
  onValueChange: (v) => onChange?.(filter.key, v),
3111
- className: spanClass,
3112
3311
  disabled
3113
3312
  }
3114
3313
  );
@@ -3121,7 +3320,6 @@ function FilterControl({ filter, value, onChange, disabled, mode }) {
3121
3320
  options: filter.options,
3122
3321
  value: value ? value.split(",").filter(Boolean) : [],
3123
3322
  onValueChange: (values) => onChange?.(filter.key, values.join(",")),
3124
- className: spanClass,
3125
3323
  disabled
3126
3324
  }
3127
3325
  );
@@ -3130,6 +3328,8 @@ function FilterControl({ filter, value, onChange, disabled, mode }) {
3130
3328
  var EN_LABELS2 = {
3131
3329
  reset: "Reset filters",
3132
3330
  apply: "Apply",
3331
+ filtersTitle: "Filters",
3332
+ filtersActive: "active",
3133
3333
  emptyTitle: "No results",
3134
3334
  emptyDescription: "Try clearing the search or adjusting the filters.",
3135
3335
  noDataTitle: "No data yet",
@@ -3137,7 +3337,9 @@ var EN_LABELS2 = {
3137
3337
  };
3138
3338
  var AR_LABELS2 = {
3139
3339
  reset: "\u0625\u0639\u0627\u062F\u0629 \u062A\u0639\u064A\u064A\u0646 \u0627\u0644\u0641\u0644\u0627\u062A\u0631",
3140
- apply: "\u062A\u0637\u0628\u064A\u0642",
3340
+ apply: "\u0639\u0631\u0636 \u0627\u0644\u0646\u062A\u0627\u0626\u062C",
3341
+ filtersTitle: "\u0627\u0644\u062A\u0635\u0641\u064A\u0629",
3342
+ filtersActive: "\u0645\u0641\u0639\u0651\u0644",
3141
3343
  emptyTitle: "\u0644\u0627 \u062A\u0648\u062C\u062F \u0646\u062A\u0627\u0626\u062C",
3142
3344
  emptyDescription: "\u062C\u0631\u0651\u0628 \u0645\u0633\u062D \u0627\u0644\u0628\u062D\u062B \u0623\u0648 \u062A\u0639\u062F\u064A\u0644 \u0627\u0644\u0641\u0644\u0627\u062A\u0631.",
3143
3345
  noDataTitle: "\u0644\u0627 \u062A\u0648\u062C\u062F \u0628\u064A\u0627\u0646\u0627\u062A \u0628\u0639\u062F",
@@ -3162,6 +3364,7 @@ function ListPage({
3162
3364
  pagination,
3163
3365
  onPaginationChange,
3164
3366
  totalCount,
3367
+ eyebrow,
3165
3368
  pageSizeOptions,
3166
3369
  emptyState,
3167
3370
  noDataState,
@@ -3182,7 +3385,17 @@ function ListPage({
3182
3385
  };
3183
3386
  const tableMode = isLoading ? "loading" : data.length === 0 && !hasActiveQuery ? "no-data" : data.length === 0 && hasActiveQuery ? "no-results" : "rows";
3184
3387
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "list-page", className: cn("space-y-6", className), children: [
3185
- /* @__PURE__ */ jsxRuntime.jsx(PageHeader, { title, description, bordered, actions }),
3388
+ /* @__PURE__ */ jsxRuntime.jsx(
3389
+ PageHeader,
3390
+ {
3391
+ title,
3392
+ description,
3393
+ eyebrow,
3394
+ titleMeta: typeof totalCount === "number" && totalCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "primary", tone: "soft", size: "sm", children: totalCount }) : void 0,
3395
+ bordered,
3396
+ actions
3397
+ }
3398
+ ),
3186
3399
  showFilterBar ? /* @__PURE__ */ jsxRuntime.jsx(
3187
3400
  ListPageFilterBar,
3188
3401
  {
@@ -3190,7 +3403,12 @@ function ListPage({
3190
3403
  values: filterValues,
3191
3404
  onChange: onFilterChange,
3192
3405
  mode: filterMode,
3193
- labels: { reset: labels.reset, apply: labels.apply }
3406
+ labels: {
3407
+ reset: labels.reset,
3408
+ apply: labels.apply,
3409
+ title: labels.filtersTitle,
3410
+ activeLabel: labels.filtersActive
3411
+ }
3194
3412
  }
3195
3413
  ) : null,
3196
3414
  tableMode === "loading" || tableMode === "rows" ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -3267,7 +3485,7 @@ var radioLabelSizeClass = {
3267
3485
  md: "text-sm",
3268
3486
  lg: "text-base"
3269
3487
  };
3270
- var radioItemBaseClass = "aspect-square shrink-0 rounded-full border border-input bg-background text-primary outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-2 focus-visible:ring-offset-background hover:border-ring disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive/40 data-[state=checked]:border-primary";
3488
+ var radioItemBaseClass = "aspect-square shrink-0 rounded-full border border-input bg-background text-primary outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-primary-glow hover:border-ring disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive/40 data-[state=checked]:border-primary";
3271
3489
  var radioIndicatorBaseClass = "flex h-full w-full items-center justify-center";
3272
3490
  var radioIndicatorDotClass = "rounded-full bg-primary";
3273
3491
  var radioOptionRowClass = "flex cursor-pointer items-start gap-2 has-[button:disabled]:cursor-not-allowed";
@@ -3438,7 +3656,7 @@ var switchThumbClass = {
3438
3656
  md: "size-4 data-[state=checked]:translate-x-4 data-[state=checked]:rtl:-translate-x-4",
3439
3657
  lg: "size-5 data-[state=checked]:translate-x-5 data-[state=checked]:rtl:-translate-x-5"
3440
3658
  };
3441
- var switchTrackBaseClass = "relative inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent bg-input transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary aria-[invalid=true]:ring-2 aria-[invalid=true]:ring-destructive/40";
3659
+ var switchTrackBaseClass = "relative inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent bg-input transition-colors focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-primary-glow disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary aria-[invalid=true]:ring-[3px] aria-[invalid=true]:ring-destructive/40";
3442
3660
  var switchThumbBaseClass = "pointer-events-none block rounded-full bg-background shadow-sm ring-0 transition-transform";
3443
3661
  var Switch = react.forwardRef(function Switch2({
3444
3662
  switchSize = "md",
@@ -3519,7 +3737,7 @@ var textareaResizeClass = {
3519
3737
  horizontal: "resize-x",
3520
3738
  both: "resize"
3521
3739
  };
3522
- var textareaBaseClass = "group/textarea relative flex w-full text-foreground outline-none transition-[background-color,border-color,box-shadow] focus-within:ring-2 focus-within:ring-ring/40 focus-within:ring-offset-1 focus-within:ring-offset-background aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive/40 has-[textarea:disabled]:pointer-events-none has-[textarea:disabled]:opacity-50";
3740
+ var textareaBaseClass = "group/textarea relative flex w-full text-foreground outline-none transition-[background-color,border-color,box-shadow] focus-within:ring-[3px] focus-within:ring-primary-glow aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive/40 has-[textarea:disabled]:pointer-events-none has-[textarea:disabled]:opacity-50";
3523
3741
  var Textarea = react.forwardRef(function Textarea2({
3524
3742
  variant = "default",
3525
3743
  textareaSize = "md",
@@ -3682,6 +3900,12 @@ exports.AppShell = AppShell;
3682
3900
  exports.Avatar = Avatar;
3683
3901
  exports.Badge = Badge;
3684
3902
  exports.Button = Button;
3903
+ exports.Card = Card;
3904
+ exports.CardContent = CardContent;
3905
+ exports.CardDescription = CardDescription;
3906
+ exports.CardFooter = CardFooter;
3907
+ exports.CardHeader = CardHeader;
3908
+ exports.CardTitle = CardTitle;
3685
3909
  exports.Checkbox = Checkbox;
3686
3910
  exports.ConfirmDialogProvider = ConfirmDialogProvider;
3687
3911
  exports.DashboardContent = DashboardContent;
@@ -3743,10 +3967,17 @@ exports.TooltipProvider = TooltipProvider;
3743
3967
  exports.badgeBaseClass = badgeBaseClass;
3744
3968
  exports.badgeDotSizeClass = badgeDotSizeClass;
3745
3969
  exports.badgeSizeClass = badgeSizeClass;
3970
+ exports.badgeSoftVariantClass = badgeSoftVariantClass;
3746
3971
  exports.badgeVariantClass = badgeVariantClass;
3747
3972
  exports.buttonBaseClass = buttonBaseClass;
3748
3973
  exports.buttonSizeClass = buttonSizeClass;
3749
3974
  exports.buttonVariantClass = buttonVariantClass;
3975
+ exports.cardBaseClass = cardBaseClass;
3976
+ exports.cardContentClass = cardContentClass;
3977
+ exports.cardDescriptionClass = cardDescriptionClass;
3978
+ exports.cardFooterClass = cardFooterClass;
3979
+ exports.cardHeaderClass = cardHeaderClass;
3980
+ exports.cardTitleClass = cardTitleClass;
3750
3981
  exports.cn = cn;
3751
3982
  exports.datePickerCalendarClass = datePickerCalendarClass;
3752
3983
  exports.datePickerCaptionClass = datePickerCaptionClass;
@@ -3827,8 +4058,11 @@ exports.pageHeaderBaseClass = pageHeaderBaseClass;
3827
4058
  exports.pageHeaderBorderedClass = pageHeaderBorderedClass;
3828
4059
  exports.pageHeaderBreadcrumbsClass = pageHeaderBreadcrumbsClass;
3829
4060
  exports.pageHeaderDescriptionClass = pageHeaderDescriptionClass;
4061
+ exports.pageHeaderEyebrowClass = pageHeaderEyebrowClass;
3830
4062
  exports.pageHeaderTitleBlockClass = pageHeaderTitleBlockClass;
3831
4063
  exports.pageHeaderTitleClass = pageHeaderTitleClass;
4064
+ exports.pageHeaderTitleLineClass = pageHeaderTitleLineClass;
4065
+ exports.pageHeaderTitleMetaClass = pageHeaderTitleMetaClass;
3832
4066
  exports.pageHeaderTitleRowClass = pageHeaderTitleRowClass;
3833
4067
  exports.radioGroupBaseClass = radioGroupBaseClass;
3834
4068
  exports.radioGroupOrientationClass = radioGroupOrientationClass;