@bmsuisse/ui 0.8.0 → 0.12.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
@@ -625,7 +625,7 @@ DropdownMenuSubContent.displayName = "DropdownMenuSubContent";
625
625
  import { cva as cva3 } from "class-variance-authority";
626
626
  import * as DialogPrimitive2 from "@radix-ui/react-dialog";
627
627
  import { X as X2 } from "lucide-react";
628
- import { forwardRef as forwardRef15 } from "react";
628
+ import { forwardRef as forwardRef15, useEffect, useRef, useState } from "react";
629
629
  import { jsx as jsx18, jsxs as jsxs5 } from "react/jsx-runtime";
630
630
  var Sheet = DialogPrimitive2.Root;
631
631
  var SheetTrigger = DialogPrimitive2.Trigger;
@@ -641,14 +641,19 @@ var SheetOverlay = forwardRef15(({ className, ...props }, ref) => /* @__PURE__ *
641
641
  ));
642
642
  SheetOverlay.displayName = "SheetOverlay";
643
643
  var sheetVariants = cva3(
644
- "fixed z-50 gap-4 bg-background p-6 shadow-lg transition-transform duration-300 ease-in-out",
644
+ "fixed z-50 gap-4 bg-background p-6 shadow-lg transition-[transform,box-shadow] duration-300 ease-in-out",
645
645
  {
646
646
  variants: {
647
647
  side: {
648
- top: "inset-x-0 top-0 border-b data-[state=closed]:-translate-y-full data-[state=open]:translate-y-0",
649
- bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:translate-y-full data-[state=open]:translate-y-0",
650
- left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0 sm:max-w-sm",
651
- right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:translate-x-full data-[state=open]:translate-x-0 sm:max-w-sm"
648
+ // Every edge border below is paired with `border-border` explicitly —
649
+ // Tailwind v4's bare `border-*` utilities default to `currentColor`,
650
+ // not the theme's border token, which otherwise renders this seam in
651
+ // the foreground text color (a harsh, high-contrast line in both
652
+ // themes) instead of the intended subtle divider.
653
+ top: "inset-x-0 top-0 border-b border-border data-[state=closed]:-translate-y-full data-[state=open]:translate-y-0",
654
+ bottom: "inset-x-0 bottom-0 border-t border-border data-[state=closed]:translate-y-full data-[state=open]:translate-y-0",
655
+ left: "inset-y-0 left-0 h-full w-3/4 border-r border-border data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0 sm:max-w-sm",
656
+ right: "inset-y-0 right-0 h-full w-3/4 border-l border-border data-[state=closed]:translate-x-full data-[state=open]:translate-x-0 sm:max-w-sm"
652
657
  }
653
658
  },
654
659
  defaultVariants: {
@@ -656,17 +661,84 @@ var sheetVariants = cva3(
656
661
  }
657
662
  }
658
663
  );
664
+ var enterFromTransform = {
665
+ top: "translateY(-100%)",
666
+ bottom: "translateY(100%)",
667
+ left: "translateX(-100%)",
668
+ right: "translateX(100%)"
669
+ };
659
670
  var SheetContent = forwardRef15(
660
- ({ side = "right", className, children, ...props }, ref) => /* @__PURE__ */ jsxs5(SheetPortal, { children: [
661
- /* @__PURE__ */ jsx18(SheetOverlay, {}),
662
- /* @__PURE__ */ jsxs5(DialogPrimitive2.Content, { ref, className: cn(sheetVariants({ side }), className), ...props, children: [
663
- children,
664
- /* @__PURE__ */ jsxs5(DialogPrimitive2.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100", children: [
665
- /* @__PURE__ */ jsx18(X2, { className: "h-4 w-4" }),
666
- /* @__PURE__ */ jsx18("span", { className: "sr-only", children: "Close" })
667
- ] })
668
- ] })
669
- ] })
671
+ ({ side = "right", className, children, resizable = false, style: styleProp, ...props }, ref) => {
672
+ const [entered, setEntered] = useState(false);
673
+ useEffect(() => {
674
+ const id = requestAnimationFrame(() => setEntered(true));
675
+ return () => cancelAnimationFrame(id);
676
+ }, []);
677
+ const [dragHeight, setDragHeight] = useState(null);
678
+ const [isDragging, setIsDragging] = useState(false);
679
+ const dragStart = useRef(null);
680
+ const canResize = resizable && side === "bottom";
681
+ const onHandlePointerDown = (e) => {
682
+ const popup = e.currentTarget.closest('[data-slot="sheet-content"]');
683
+ if (!(popup instanceof HTMLElement)) return;
684
+ e.currentTarget.setPointerCapture(e.pointerId);
685
+ dragStart.current = { y: e.clientY, height: popup.getBoundingClientRect().height };
686
+ setIsDragging(true);
687
+ };
688
+ const onHandlePointerMove = (e) => {
689
+ if (!dragStart.current) return;
690
+ const delta = dragStart.current.y - e.clientY;
691
+ const next = dragStart.current.height + delta;
692
+ const min = window.innerHeight * 0.3;
693
+ const max = window.innerHeight * 0.95;
694
+ setDragHeight(Math.min(max, Math.max(min, next)));
695
+ };
696
+ const onHandlePointerUp = () => {
697
+ dragStart.current = null;
698
+ setIsDragging(false);
699
+ };
700
+ const style = entered ? { ...styleProp, ...canResize && dragHeight != null ? { height: dragHeight, maxHeight: dragHeight } : null } : { ...styleProp, transform: enterFromTransform[side ?? "right"] };
701
+ return /* @__PURE__ */ jsxs5(SheetPortal, { children: [
702
+ /* @__PURE__ */ jsx18(SheetOverlay, {}),
703
+ /* @__PURE__ */ jsxs5(
704
+ DialogPrimitive2.Content,
705
+ {
706
+ ref,
707
+ "data-slot": "sheet-content",
708
+ style,
709
+ className: cn(sheetVariants({ side }), isDragging && "shadow-2xl", className),
710
+ ...props,
711
+ children: [
712
+ canResize && /* @__PURE__ */ jsx18(
713
+ "div",
714
+ {
715
+ "data-testid": "sheet-drag-handle",
716
+ className: "group -mb-2 flex shrink-0 cursor-grab touch-none justify-center py-2 active:cursor-grabbing",
717
+ onPointerDown: onHandlePointerDown,
718
+ onPointerMove: onHandlePointerMove,
719
+ onPointerUp: onHandlePointerUp,
720
+ onPointerCancel: onHandlePointerUp,
721
+ children: /* @__PURE__ */ jsx18(
722
+ "div",
723
+ {
724
+ className: cn(
725
+ "h-1 w-10 rounded-full bg-muted-foreground/30 transition-all duration-150 group-hover:w-14 group-hover:bg-muted-foreground/50",
726
+ isDragging && "w-14 bg-primary/60"
727
+ )
728
+ }
729
+ )
730
+ }
731
+ ),
732
+ children,
733
+ /* @__PURE__ */ jsxs5(DialogPrimitive2.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100", children: [
734
+ /* @__PURE__ */ jsx18(X2, { className: "h-4 w-4" }),
735
+ /* @__PURE__ */ jsx18("span", { className: "sr-only", children: "Close" })
736
+ ] })
737
+ ]
738
+ }
739
+ )
740
+ ] });
741
+ }
670
742
  );
671
743
  SheetContent.displayName = "SheetContent";
672
744
  var SheetHeader = ({
@@ -730,7 +802,7 @@ var Modal = ({
730
802
  ] }) });
731
803
 
732
804
  // src/patterns/modal/ConfirmDialog.tsx
733
- import { useState } from "react";
805
+ import { useState as useState2 } from "react";
734
806
  import { Fragment, jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
735
807
  var ConfirmDialog = ({
736
808
  open,
@@ -744,7 +816,7 @@ var ConfirmDialog = ({
744
816
  confirmTestId,
745
817
  cancelTestId
746
818
  }) => {
747
- const [pending, setPending] = useState(false);
819
+ const [pending, setPending] = useState2(false);
748
820
  const handleCancel = () => {
749
821
  onOpenChange(false);
750
822
  };
@@ -785,7 +857,7 @@ var ConfirmDialog = ({
785
857
  };
786
858
 
787
859
  // src/patterns/modal/FormModal.tsx
788
- import { useState as useState2 } from "react";
860
+ import { useState as useState3 } from "react";
789
861
  import { jsx as jsx22, jsxs as jsxs8 } from "react/jsx-runtime";
790
862
  var FormModal = ({
791
863
  open,
@@ -801,7 +873,7 @@ var FormModal = ({
801
873
  submitTestId,
802
874
  cancelTestId
803
875
  }) => {
804
- const [pending, setPending] = useState2(false);
876
+ const [pending, setPending] = useState3(false);
805
877
  const handleSubmit = async (event) => {
806
878
  event.preventDefault();
807
879
  setPending(true);
@@ -837,9 +909,236 @@ var FormModal = ({
837
909
  ] }) }) });
838
910
  };
839
911
 
912
+ // src/patterns/modal/ResponsivePanel.tsx
913
+ import { useRef as useRef2, useState as useState5 } from "react";
914
+
915
+ // src/lib/useMediaQuery.ts
916
+ import { useEffect as useEffect2, useState as useState4 } from "react";
917
+ function useMediaQuery(query) {
918
+ const [matches, setMatches] = useState4(
919
+ () => typeof window !== "undefined" ? window.matchMedia(query).matches : false
920
+ );
921
+ useEffect2(() => {
922
+ const mq = window.matchMedia(query);
923
+ setMatches(mq.matches);
924
+ const handler = (e) => setMatches(e.matches);
925
+ mq.addEventListener("change", handler);
926
+ return () => mq.removeEventListener("change", handler);
927
+ }, [query]);
928
+ return matches;
929
+ }
930
+
931
+ // src/patterns/modal/ResponsivePanel.tsx
932
+ import { jsx as jsx23, jsxs as jsxs9 } from "react/jsx-runtime";
933
+ var desktopSizeClasses = {
934
+ sm: "max-w-md",
935
+ md: "max-w-xl",
936
+ lg: "max-w-2xl",
937
+ xl: "max-w-7xl"
938
+ };
939
+ var drawerSizeClasses = {
940
+ sm: "max-h-[50vh]",
941
+ md: "max-h-[70vh]",
942
+ lg: "max-h-[90vh]",
943
+ xl: "max-h-[96vh]"
944
+ };
945
+ var MIN_PANEL_WIDTH = 320;
946
+ var MIN_PANEL_HEIGHT = 240;
947
+ var VIEWPORT_MARGIN = 16;
948
+ var cornerCursor = {
949
+ "top-left": "cursor-nwse-resize",
950
+ "bottom-right": "cursor-nwse-resize",
951
+ "top-right": "cursor-nesw-resize",
952
+ "bottom-left": "cursor-nesw-resize"
953
+ };
954
+ var cornerPosition = {
955
+ "top-left": "left-0 top-0",
956
+ "top-right": "right-0 top-0",
957
+ "bottom-left": "left-0 bottom-0",
958
+ "bottom-right": "right-0 bottom-0"
959
+ };
960
+ var cornerGripPosition = {
961
+ "top-left": "left-1 top-1 border-l-2 border-t-2",
962
+ "top-right": "right-1 top-1 border-r-2 border-t-2",
963
+ "bottom-left": "left-1 bottom-1 border-l-2 border-b-2",
964
+ "bottom-right": "right-1 bottom-1 border-r-2 border-b-2"
965
+ };
966
+ function useDesktopPanelGeometry() {
967
+ const [style, setStyle] = useState5(void 0);
968
+ const [isDragging, setIsDragging] = useState5(false);
969
+ const drag = useRef2(null);
970
+ const lastRect = useRef2(null);
971
+ const beginDrag = (mode, corner) => (e) => {
972
+ const content = e.currentTarget.closest('[data-slot="dialog-content"]');
973
+ if (!(content instanceof HTMLElement)) return;
974
+ e.currentTarget.setPointerCapture(e.pointerId);
975
+ const domRect = content.getBoundingClientRect();
976
+ const rect = lastRect.current ?? {
977
+ left: domRect.left,
978
+ top: domRect.top,
979
+ width: domRect.width,
980
+ height: domRect.height
981
+ };
982
+ drag.current = { mode, corner, x: e.clientX, y: e.clientY, rect };
983
+ setIsDragging(true);
984
+ };
985
+ const onPointerMove = (e) => {
986
+ const state = drag.current;
987
+ if (!state) return;
988
+ const deltaX = e.clientX - state.x;
989
+ const deltaY = e.clientY - state.y;
990
+ if (state.mode === "move") {
991
+ const maxLeft = window.innerWidth - VIEWPORT_MARGIN - state.rect.width;
992
+ const maxTop = window.innerHeight - VIEWPORT_MARGIN - state.rect.height;
993
+ const next2 = {
994
+ left: Math.min(maxLeft, Math.max(VIEWPORT_MARGIN, state.rect.left + deltaX)),
995
+ top: Math.min(maxTop, Math.max(VIEWPORT_MARGIN, state.rect.top + deltaY)),
996
+ width: state.rect.width,
997
+ height: state.rect.height
998
+ };
999
+ lastRect.current = next2;
1000
+ setStyle({ position: "fixed", transform: "none", translate: "none", maxWidth: "none", maxHeight: "none", ...next2 });
1001
+ return;
1002
+ }
1003
+ const corner = state.corner ?? "top-left";
1004
+ const growsLeft = corner === "top-left" || corner === "bottom-left";
1005
+ const growsUp = corner === "top-left" || corner === "top-right";
1006
+ const right = state.rect.left + state.rect.width;
1007
+ const bottom = state.rect.top + state.rect.height;
1008
+ const maxWidth = window.innerWidth - VIEWPORT_MARGIN * 2;
1009
+ const maxHeight = window.innerHeight - VIEWPORT_MARGIN * 2;
1010
+ let width = Math.max(
1011
+ MIN_PANEL_WIDTH,
1012
+ Math.min(maxWidth, growsLeft ? state.rect.width - deltaX : state.rect.width + deltaX)
1013
+ );
1014
+ let height = Math.max(
1015
+ MIN_PANEL_HEIGHT,
1016
+ Math.min(maxHeight, growsUp ? state.rect.height - deltaY : state.rect.height + deltaY)
1017
+ );
1018
+ const left = growsLeft ? right - Math.min(width, right - VIEWPORT_MARGIN) : state.rect.left;
1019
+ width = growsLeft ? right - left : Math.min(width, window.innerWidth - VIEWPORT_MARGIN - state.rect.left);
1020
+ const top = growsUp ? bottom - Math.min(height, bottom - VIEWPORT_MARGIN) : state.rect.top;
1021
+ height = growsUp ? bottom - top : Math.min(height, window.innerHeight - VIEWPORT_MARGIN - state.rect.top);
1022
+ const next = { left, top, width, height };
1023
+ lastRect.current = next;
1024
+ setStyle({ position: "fixed", transform: "none", translate: "none", maxWidth: "none", maxHeight: "none", ...next });
1025
+ };
1026
+ const onPointerUp = () => {
1027
+ drag.current = null;
1028
+ setIsDragging(false);
1029
+ };
1030
+ return {
1031
+ style,
1032
+ isDragging,
1033
+ startMove: beginDrag("move"),
1034
+ startResize: (corner) => beginDrag("resize", corner),
1035
+ onPointerMove,
1036
+ onPointerUp
1037
+ };
1038
+ }
1039
+ var ResponsivePanel = ({
1040
+ open,
1041
+ onOpenChange,
1042
+ title,
1043
+ description,
1044
+ children,
1045
+ footer,
1046
+ className,
1047
+ breakpoint = "(min-width: 1024px)",
1048
+ size = "lg",
1049
+ resizable = false,
1050
+ draggable = false,
1051
+ closeOnOutsideClick = true
1052
+ }) => {
1053
+ const isDesktop = useMediaQuery(breakpoint);
1054
+ const geometry = useDesktopPanelGeometry();
1055
+ const onInteractOutside = closeOnOutsideClick ? void 0 : (e) => e.preventDefault();
1056
+ if (isDesktop) {
1057
+ const corners = ["top-left", "top-right", "bottom-left", "bottom-right"];
1058
+ return /* @__PURE__ */ jsx23(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs9(
1059
+ DialogContent,
1060
+ {
1061
+ "data-slot": "dialog-content",
1062
+ onInteractOutside,
1063
+ style: resizable || draggable ? geometry.style : void 0,
1064
+ className: cn(
1065
+ "max-h-[85vh] overflow-y-auto transition-shadow duration-150 ease-out",
1066
+ geometry.isDragging && "shadow-2xl ring-2 ring-primary/30",
1067
+ desktopSizeClasses[size],
1068
+ className
1069
+ ),
1070
+ children: [
1071
+ resizable && corners.map((corner) => /* @__PURE__ */ jsx23(
1072
+ "div",
1073
+ {
1074
+ "data-testid": `panel-resize-handle-${corner}`,
1075
+ className: cn(
1076
+ "group absolute h-4 w-4 touch-none",
1077
+ cornerPosition[corner],
1078
+ cornerCursor[corner]
1079
+ ),
1080
+ onPointerDown: geometry.startResize(corner),
1081
+ onPointerMove: geometry.onPointerMove,
1082
+ onPointerUp: geometry.onPointerUp,
1083
+ onPointerCancel: geometry.onPointerUp,
1084
+ children: /* @__PURE__ */ jsx23(
1085
+ "div",
1086
+ {
1087
+ className: cn(
1088
+ "absolute h-2 w-2 scale-100 border-muted-foreground/40 transition-transform duration-150 group-hover:scale-125 group-hover:border-primary/60",
1089
+ cornerGripPosition[corner]
1090
+ )
1091
+ }
1092
+ )
1093
+ },
1094
+ corner
1095
+ )),
1096
+ /* @__PURE__ */ jsxs9(
1097
+ DialogHeader,
1098
+ {
1099
+ className: cn(draggable && "touch-none cursor-move select-none"),
1100
+ onPointerDown: draggable ? geometry.startMove : void 0,
1101
+ onPointerMove: draggable ? geometry.onPointerMove : void 0,
1102
+ onPointerUp: draggable ? geometry.onPointerUp : void 0,
1103
+ onPointerCancel: draggable ? geometry.onPointerUp : void 0,
1104
+ children: [
1105
+ /* @__PURE__ */ jsx23(DialogTitle, { children: title }),
1106
+ description ? /* @__PURE__ */ jsx23(DialogDescription, { children: description }) : null
1107
+ ]
1108
+ }
1109
+ ),
1110
+ children,
1111
+ footer ? /* @__PURE__ */ jsx23(DialogFooter, { children: footer }) : null
1112
+ ]
1113
+ }
1114
+ ) });
1115
+ }
1116
+ return /* @__PURE__ */ jsx23(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs9(
1117
+ SheetContent,
1118
+ {
1119
+ side: "bottom",
1120
+ resizable,
1121
+ onInteractOutside,
1122
+ className: cn(
1123
+ "flex flex-col overflow-y-auto rounded-t-2xl",
1124
+ drawerSizeClasses[size],
1125
+ className
1126
+ ),
1127
+ children: [
1128
+ /* @__PURE__ */ jsxs9(SheetHeader, { children: [
1129
+ /* @__PURE__ */ jsx23(SheetTitle, { children: title }),
1130
+ description ? /* @__PURE__ */ jsx23(SheetDescription, { children: description }) : null
1131
+ ] }),
1132
+ children,
1133
+ footer ? /* @__PURE__ */ jsx23(SheetFooter, { children: footer }) : null
1134
+ ]
1135
+ }
1136
+ ) });
1137
+ };
1138
+
840
1139
  // src/patterns/form-field/FormField.tsx
841
1140
  import { cloneElement, isValidElement, useId } from "react";
842
- import { jsx as jsx23, jsxs as jsxs9 } from "react/jsx-runtime";
1141
+ import { jsx as jsx24, jsxs as jsxs10 } from "react/jsx-runtime";
843
1142
  function FormField({
844
1143
  label,
845
1144
  htmlFor,
@@ -864,22 +1163,22 @@ function FormField({
864
1163
  ...messageId ? { "aria-describedby": messageId } : {}
865
1164
  }
866
1165
  ) : children;
867
- return /* @__PURE__ */ jsxs9("div", { className: cn("flex flex-col gap-1.5", className), children: [
868
- /* @__PURE__ */ jsxs9(Label, { htmlFor: effectiveId, children: [
1166
+ return /* @__PURE__ */ jsxs10("div", { className: cn("flex flex-col gap-1.5", className), children: [
1167
+ /* @__PURE__ */ jsxs10(Label, { htmlFor: effectiveId, children: [
869
1168
  label,
870
- required ? /* @__PURE__ */ jsxs9("span", { className: "text-destructive", "aria-hidden": "true", children: [
1169
+ required ? /* @__PURE__ */ jsxs10("span", { className: "text-destructive", "aria-hidden": "true", children: [
871
1170
  " ",
872
1171
  "*"
873
1172
  ] }) : null
874
1173
  ] }),
875
1174
  child,
876
- error ? /* @__PURE__ */ jsx23("p", { id: messageId, className: "text-sm text-destructive", children: error }) : description ? /* @__PURE__ */ jsx23("p", { id: messageId, className: "text-sm text-muted-foreground", children: description }) : null
1175
+ error ? /* @__PURE__ */ jsx24("p", { id: messageId, className: "text-sm text-destructive", children: error }) : description ? /* @__PURE__ */ jsx24("p", { id: messageId, className: "text-sm text-muted-foreground", children: description }) : null
877
1176
  ] });
878
1177
  }
879
1178
 
880
1179
  // src/patterns/combobox/Combobox.tsx
881
1180
  import { Check as Check4, ChevronsUpDown, X as X3 } from "lucide-react";
882
- import { useEffect, useMemo, useRef, useState as useState3 } from "react";
1181
+ import { useEffect as useEffect3, useMemo, useRef as useRef3, useState as useState6 } from "react";
883
1182
 
884
1183
  // src/lib/optionGrouping.ts
885
1184
  function groupMembers(options, group) {
@@ -907,8 +1206,78 @@ function buildRenderChunks(visibleOptions) {
907
1206
  return chunks;
908
1207
  }
909
1208
 
1209
+ // src/lib/optionGrid.tsx
1210
+ import { jsx as jsx25, jsxs as jsxs11 } from "react/jsx-runtime";
1211
+ function renderGridOptions({
1212
+ columns,
1213
+ options,
1214
+ activeIndex,
1215
+ multiple,
1216
+ isSelected,
1217
+ onSelect,
1218
+ onHover,
1219
+ testId
1220
+ }) {
1221
+ return /* @__PURE__ */ jsxs11(Table, { className: "text-sm", children: [
1222
+ /* @__PURE__ */ jsx25(TableHeader, { children: /* @__PURE__ */ jsxs11(TableRow, { className: "hover:bg-transparent", children: [
1223
+ multiple && /* @__PURE__ */ jsx25(TableHead, { className: "sticky top-0 z-10 w-6 bg-muted" }),
1224
+ columns.map((column) => /* @__PURE__ */ jsx25(
1225
+ TableHead,
1226
+ {
1227
+ className: cn("sticky top-0 z-10 whitespace-nowrap bg-muted text-xs", column.className),
1228
+ children: column.header
1229
+ },
1230
+ column.key
1231
+ ))
1232
+ ] }) }),
1233
+ /* @__PURE__ */ jsx25(TableBody, { children: options.map((option, index) => {
1234
+ const selected = isSelected(option);
1235
+ const active = index === activeIndex;
1236
+ return /* @__PURE__ */ jsxs11(
1237
+ TableRow,
1238
+ {
1239
+ role: "option",
1240
+ "aria-selected": selected,
1241
+ "aria-label": option.label,
1242
+ "aria-disabled": option.disabled,
1243
+ "data-testid": testId ? `${testId}-option` : void 0,
1244
+ "data-option-value": option.value,
1245
+ onMouseEnter: () => onHover(index),
1246
+ onClick: () => {
1247
+ if (!option.disabled) onSelect(option);
1248
+ },
1249
+ className: cn(
1250
+ "cursor-pointer outline-none",
1251
+ // `hover:bg-accent` repeats the active row's own background under
1252
+ // `:hover` -- otherwise TableRow's default `hover:bg-muted/50`
1253
+ // would win over the plain `bg-accent` below (later in the
1254
+ // stylesheet) and flash the active/keyboard-selected row to the
1255
+ // wrong color the instant the mouse sits over it.
1256
+ active && "bg-accent text-accent-foreground hover:bg-accent hover:text-accent-foreground",
1257
+ option.disabled && "pointer-events-none opacity-50"
1258
+ ),
1259
+ children: [
1260
+ multiple && /* @__PURE__ */ jsx25(TableCell, { className: "w-6", children: /* @__PURE__ */ jsx25(
1261
+ "input",
1262
+ {
1263
+ type: "checkbox",
1264
+ checked: selected,
1265
+ readOnly: true,
1266
+ tabIndex: -1,
1267
+ className: "pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary"
1268
+ }
1269
+ ) }),
1270
+ columns.map((column) => /* @__PURE__ */ jsx25(TableCell, { className: cn("truncate", column.className), children: column.key === "label" ? option.label : option.data?.[column.key] }, column.key))
1271
+ ]
1272
+ },
1273
+ option.value
1274
+ );
1275
+ }) })
1276
+ ] });
1277
+ }
1278
+
910
1279
  // src/patterns/combobox/Combobox.tsx
911
- import { jsx as jsx24, jsxs as jsxs10 } from "react/jsx-runtime";
1280
+ import { jsx as jsx26, jsxs as jsxs12 } from "react/jsx-runtime";
912
1281
  function resolveGroupTriggerLabel(options, selectedValues, groupLabel) {
913
1282
  const selectedSet = new Set(selectedValues);
914
1283
  const groupsPresent = Array.from(
@@ -943,13 +1312,14 @@ function Combobox(props) {
943
1312
  groupLabels,
944
1313
  container,
945
1314
  onSearchChange,
946
- selectedLabel
1315
+ selectedLabel,
1316
+ columns
947
1317
  } = props;
948
1318
  const testId = props["data-testid"];
949
- const [open, setOpen] = useState3(false);
950
- const [search, setSearch] = useState3("");
951
- const [activeIndex, setActiveIndex] = useState3(0);
952
- const inputRef = useRef(null);
1319
+ const [open, setOpen] = useState6(false);
1320
+ const [search, setSearch] = useState6("");
1321
+ const [activeIndex, setActiveIndex] = useState6(0);
1322
+ const inputRef = useRef3(null);
953
1323
  const selectedValues = useMemo(
954
1324
  () => props.multiple ? props.value : props.value ? [props.value] : [],
955
1325
  [props.multiple, props.value]
@@ -964,7 +1334,7 @@ function Combobox(props) {
964
1334
  if (!term) return options;
965
1335
  return options.filter((option) => option.label.toLowerCase().includes(term));
966
1336
  }, [options, search, onSearchChange]);
967
- useEffect(() => {
1337
+ useEffect3(() => {
968
1338
  if (!open) return;
969
1339
  setSearch("");
970
1340
  onSearchChange?.("");
@@ -973,7 +1343,7 @@ function Combobox(props) {
973
1343
  setActiveIndex(selectedIdx >= 0 ? selectedIdx : 0);
974
1344
  inputRef.current?.focus();
975
1345
  }, [open]);
976
- useEffect(() => {
1346
+ useEffect3(() => {
977
1347
  setActiveIndex((i) => Math.min(i, Math.max(visibleOptions.length - 1, 0)));
978
1348
  }, [visibleOptions.length]);
979
1349
  function selectOption(option) {
@@ -1007,11 +1377,11 @@ function Combobox(props) {
1007
1377
  props.onChange(next);
1008
1378
  }
1009
1379
  const triggerLabel = loading ? loadingMessage : selectedOptions.length === 0 ? selectedValues.length > 0 ? selectedLabel ?? placeholder : placeholder : selectedOptions.length === 1 ? selectedOptions[0]?.label ?? placeholder : (props.multiple ? resolveGroupTriggerLabel(options, selectedValues, groupLabel) : null) ?? `${selectedOptions.length} selected`;
1010
- const renderChunks = useMemo(() => buildRenderChunks(visibleOptions), [visibleOptions]);
1380
+ const renderChunks = useMemo(() => columns ? [] : buildRenderChunks(visibleOptions), [visibleOptions, columns]);
1011
1381
  function renderOption({ option, index }) {
1012
1382
  const isSelected = selectedValues.includes(option.value);
1013
1383
  const isActive = index === activeIndex;
1014
- return /* @__PURE__ */ jsxs10(
1384
+ return /* @__PURE__ */ jsxs12(
1015
1385
  "button",
1016
1386
  {
1017
1387
  type: "button",
@@ -1027,7 +1397,7 @@ function Combobox(props) {
1027
1397
  isActive && "bg-accent text-accent-foreground"
1028
1398
  ),
1029
1399
  children: [
1030
- props.multiple ? /* @__PURE__ */ jsx24(
1400
+ props.multiple ? /* @__PURE__ */ jsx26(
1031
1401
  "input",
1032
1402
  {
1033
1403
  type: "checkbox",
@@ -1036,15 +1406,15 @@ function Combobox(props) {
1036
1406
  tabIndex: -1,
1037
1407
  className: "pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary"
1038
1408
  }
1039
- ) : /* @__PURE__ */ jsx24(Check4, { className: cn("h-4 w-4 shrink-0", isSelected ? "opacity-100" : "opacity-0") }),
1040
- /* @__PURE__ */ jsx24("span", { className: "truncate", children: option.label })
1409
+ ) : /* @__PURE__ */ jsx26(Check4, { className: cn("h-4 w-4 shrink-0", isSelected ? "opacity-100" : "opacity-0") }),
1410
+ /* @__PURE__ */ jsx26("span", { className: "truncate", children: option.label })
1041
1411
  ]
1042
1412
  },
1043
1413
  option.value
1044
1414
  );
1045
1415
  }
1046
- return /* @__PURE__ */ jsxs10(Popover, { open, onOpenChange: setOpen, children: [
1047
- /* @__PURE__ */ jsx24(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs10(
1416
+ return /* @__PURE__ */ jsxs12(Popover, { open, onOpenChange: setOpen, children: [
1417
+ /* @__PURE__ */ jsx26(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
1048
1418
  Button,
1049
1419
  {
1050
1420
  id,
@@ -1060,9 +1430,9 @@ function Combobox(props) {
1060
1430
  className
1061
1431
  ),
1062
1432
  children: [
1063
- /* @__PURE__ */ jsx24("span", { className: "truncate", children: triggerLabel }),
1064
- /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-1", children: [
1065
- clearable && !loading && selectedValues.length > 0 ? /* @__PURE__ */ jsx24(
1433
+ /* @__PURE__ */ jsx26("span", { className: "truncate", children: triggerLabel }),
1434
+ /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-1", children: [
1435
+ clearable && !loading && selectedValues.length > 0 ? /* @__PURE__ */ jsx26(
1066
1436
  "span",
1067
1437
  {
1068
1438
  role: "button",
@@ -1077,23 +1447,26 @@ function Combobox(props) {
1077
1447
  props.onChange(null);
1078
1448
  }
1079
1449
  },
1080
- children: /* @__PURE__ */ jsx24(X3, { className: "h-3.5 w-3.5" })
1450
+ children: /* @__PURE__ */ jsx26(X3, { className: "h-3.5 w-3.5" })
1081
1451
  }
1082
1452
  ) : null,
1083
- /* @__PURE__ */ jsx24(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50", "aria-hidden": "true" })
1453
+ /* @__PURE__ */ jsx26(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50", "aria-hidden": "true" })
1084
1454
  ] })
1085
1455
  ]
1086
1456
  }
1087
1457
  ) }),
1088
- /* @__PURE__ */ jsx24(
1458
+ /* @__PURE__ */ jsx26(
1089
1459
  PopoverContent,
1090
1460
  {
1091
1461
  align: "start",
1092
1462
  container,
1093
- className: "w-[var(--radix-popover-trigger-width)] min-w-[10rem] p-2",
1463
+ className: cn(
1464
+ "w-[var(--radix-popover-trigger-width)] min-w-[10rem] p-2",
1465
+ columns && "w-max min-w-[var(--radix-popover-trigger-width)] max-w-[min(40rem,90vw)]"
1466
+ ),
1094
1467
  onOpenAutoFocus: (event) => event.preventDefault(),
1095
- children: /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-2", children: [
1096
- /* @__PURE__ */ jsx24(
1468
+ children: /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-2", children: [
1469
+ /* @__PURE__ */ jsx26(
1097
1470
  Input,
1098
1471
  {
1099
1472
  ref: inputRef,
@@ -1107,7 +1480,16 @@ function Combobox(props) {
1107
1480
  "aria-label": searchPlaceholder
1108
1481
  }
1109
1482
  ),
1110
- /* @__PURE__ */ jsx24("div", { role: "listbox", className: "flex max-h-60 flex-col gap-0.5 overflow-y-auto", children: renderChunks.length === 0 ? /* @__PURE__ */ jsx24("p", { className: "py-2 text-center text-sm text-muted-foreground", children: emptyMessage }) : renderChunks.map((chunk) => {
1483
+ /* @__PURE__ */ jsx26("div", { role: "listbox", className: cn("max-h-60 overflow-y-auto", !columns && "flex flex-col gap-0.5"), children: visibleOptions.length === 0 ? /* @__PURE__ */ jsx26("p", { className: "py-2 text-center text-sm text-muted-foreground", children: emptyMessage }) : columns ? renderGridOptions({
1484
+ columns,
1485
+ options: visibleOptions,
1486
+ activeIndex,
1487
+ multiple: Boolean(props.multiple),
1488
+ isSelected: (option) => selectedValues.includes(option.value),
1489
+ onSelect: selectOption,
1490
+ onHover: setActiveIndex,
1491
+ testId
1492
+ }) : renderChunks.map((chunk) => {
1111
1493
  if (chunk.kind === "single") return renderOption(chunk.row);
1112
1494
  const headerState = groupCheckState(options, selectedValues, chunk.group);
1113
1495
  return (
@@ -1118,14 +1500,14 @@ function Combobox(props) {
1118
1500
  // lives on this wrapper's `pt-1`, not on the header itself -- a margin on
1119
1501
  // the sticky element would travel with it once stuck, leaving a gap at the
1120
1502
  // scrollport's top that the row behind it shows through.
1121
- /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-0.5 pt-1 first:pt-0", children: [
1122
- /* @__PURE__ */ jsxs10(
1503
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-0.5 pt-1 first:pt-0", children: [
1504
+ /* @__PURE__ */ jsxs12(
1123
1505
  "div",
1124
1506
  {
1125
1507
  "data-group-header": true,
1126
1508
  className: "sticky top-0 z-10 flex items-center gap-2 rounded-sm bg-muted px-2 py-1.5 text-sm font-semibold text-foreground",
1127
1509
  children: [
1128
- props.multiple ? /* @__PURE__ */ jsx24(
1510
+ props.multiple ? /* @__PURE__ */ jsx26(
1129
1511
  "input",
1130
1512
  {
1131
1513
  type: "checkbox",
@@ -1139,7 +1521,7 @@ function Combobox(props) {
1139
1521
  "aria-label": `Select all of ${groupLabel(chunk.group)}`
1140
1522
  }
1141
1523
  ) : null,
1142
- /* @__PURE__ */ jsx24("span", { className: "truncate", children: groupLabel(chunk.group) })
1524
+ /* @__PURE__ */ jsx26("span", { className: "truncate", children: groupLabel(chunk.group) })
1143
1525
  ]
1144
1526
  }
1145
1527
  ),
@@ -1155,8 +1537,8 @@ function Combobox(props) {
1155
1537
 
1156
1538
  // src/patterns/tag-combobox/TagCombobox.tsx
1157
1539
  import { X as X4 } from "lucide-react";
1158
- import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState4 } from "react";
1159
- import { jsx as jsx25, jsxs as jsxs11 } from "react/jsx-runtime";
1540
+ import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState7 } from "react";
1541
+ import { jsx as jsx27, jsxs as jsxs13 } from "react/jsx-runtime";
1160
1542
  function TagCombobox({
1161
1543
  options,
1162
1544
  value,
@@ -1171,14 +1553,15 @@ function TagCombobox({
1171
1553
  onSearchChange,
1172
1554
  container,
1173
1555
  groupLabels,
1556
+ columns,
1174
1557
  ...rest
1175
1558
  }) {
1176
1559
  const testId = rest["data-testid"];
1177
- const [open, setOpen] = useState4(false);
1178
- const [search, setSearch] = useState4("");
1179
- const [activeIndex, setActiveIndex] = useState4(0);
1180
- const inputRef = useRef2(null);
1181
- const fieldRef = useRef2(null);
1560
+ const [open, setOpen] = useState7(false);
1561
+ const [search, setSearch] = useState7("");
1562
+ const [activeIndex, setActiveIndex] = useState7(0);
1563
+ const inputRef = useRef4(null);
1564
+ const fieldRef = useRef4(null);
1182
1565
  const selectedOptions = useMemo2(
1183
1566
  () => value.map((v) => options.find((o) => o.value === v) ?? { value: v, label: v }),
1184
1567
  [options, value]
@@ -1189,11 +1572,11 @@ function TagCombobox({
1189
1572
  if (!term) return options;
1190
1573
  return options.filter((option) => option.label.toLowerCase().includes(term));
1191
1574
  }, [options, search, onSearchChange]);
1192
- useEffect2(() => {
1575
+ useEffect4(() => {
1193
1576
  setActiveIndex((i) => Math.min(Math.max(i, 0), Math.max(visibleOptions.length - 1, 0)));
1194
1577
  }, [visibleOptions.length]);
1195
- const renderChunks = useMemo2(() => buildRenderChunks(visibleOptions), [visibleOptions]);
1196
- useEffect2(() => {
1578
+ const renderChunks = useMemo2(() => columns ? [] : buildRenderChunks(visibleOptions), [visibleOptions, columns]);
1579
+ useEffect4(() => {
1197
1580
  if (!open) return;
1198
1581
  setSearch("");
1199
1582
  onSearchChange?.("");
@@ -1246,7 +1629,7 @@ function TagCombobox({
1246
1629
  function renderOption({ option, index }) {
1247
1630
  const isSelected = value.includes(option.value);
1248
1631
  const isActive = index === activeIndex;
1249
- return /* @__PURE__ */ jsxs11(
1632
+ return /* @__PURE__ */ jsxs13(
1250
1633
  "button",
1251
1634
  {
1252
1635
  type: "button",
@@ -1262,7 +1645,7 @@ function TagCombobox({
1262
1645
  isActive && "bg-accent text-accent-foreground"
1263
1646
  ),
1264
1647
  children: [
1265
- /* @__PURE__ */ jsx25(
1648
+ /* @__PURE__ */ jsx27(
1266
1649
  "input",
1267
1650
  {
1268
1651
  type: "checkbox",
@@ -1272,14 +1655,14 @@ function TagCombobox({
1272
1655
  className: "pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary"
1273
1656
  }
1274
1657
  ),
1275
- /* @__PURE__ */ jsx25("span", { className: "truncate", children: option.label })
1658
+ /* @__PURE__ */ jsx27("span", { className: "truncate", children: option.label })
1276
1659
  ]
1277
1660
  },
1278
1661
  option.value
1279
1662
  );
1280
1663
  }
1281
- return /* @__PURE__ */ jsxs11(Popover, { open, onOpenChange: setOpen, children: [
1282
- /* @__PURE__ */ jsx25(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs11(
1664
+ return /* @__PURE__ */ jsxs13(Popover, { open, onOpenChange: setOpen, children: [
1665
+ /* @__PURE__ */ jsx27(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs13(
1283
1666
  "div",
1284
1667
  {
1285
1668
  ref: fieldRef,
@@ -1297,13 +1680,13 @@ function TagCombobox({
1297
1680
  if (!disabled) inputRef.current?.focus();
1298
1681
  },
1299
1682
  children: [
1300
- selectedOptions.map((option) => /* @__PURE__ */ jsxs11(
1683
+ selectedOptions.map((option) => /* @__PURE__ */ jsxs13(
1301
1684
  "span",
1302
1685
  {
1303
1686
  className: "inline-flex items-center gap-1 rounded-full bg-muted py-0.5 pr-1 pl-2.5 text-xs font-medium text-muted-foreground",
1304
1687
  children: [
1305
- /* @__PURE__ */ jsx25("span", { className: "max-w-48 truncate", children: option.label }),
1306
- !disabled && /* @__PURE__ */ jsx25(
1688
+ /* @__PURE__ */ jsx27("span", { className: "max-w-48 truncate", children: option.label }),
1689
+ !disabled && /* @__PURE__ */ jsx27(
1307
1690
  "button",
1308
1691
  {
1309
1692
  type: "button",
@@ -1313,14 +1696,14 @@ function TagCombobox({
1313
1696
  event.stopPropagation();
1314
1697
  removeValue(option.value);
1315
1698
  },
1316
- children: /* @__PURE__ */ jsx25(X4, { className: "h-3 w-3" })
1699
+ children: /* @__PURE__ */ jsx27(X4, { className: "h-3 w-3" })
1317
1700
  }
1318
1701
  )
1319
1702
  ]
1320
1703
  },
1321
1704
  option.value
1322
1705
  )),
1323
- /* @__PURE__ */ jsx25(
1706
+ /* @__PURE__ */ jsx27(
1324
1707
  "input",
1325
1708
  {
1326
1709
  ref: inputRef,
@@ -1338,18 +1721,30 @@ function TagCombobox({
1338
1721
  ]
1339
1722
  }
1340
1723
  ) }),
1341
- /* @__PURE__ */ jsx25(
1724
+ /* @__PURE__ */ jsx27(
1342
1725
  PopoverContent,
1343
1726
  {
1344
1727
  align: "start",
1345
1728
  container,
1346
- className: "w-[var(--radix-popover-trigger-width)] min-w-[10rem] p-2",
1729
+ className: cn(
1730
+ "w-[var(--radix-popover-trigger-width)] min-w-[10rem] p-2",
1731
+ columns && "w-max min-w-[var(--radix-popover-trigger-width)] max-w-[min(40rem,90vw)]"
1732
+ ),
1347
1733
  onOpenAutoFocus: (event) => event.preventDefault(),
1348
1734
  onCloseAutoFocus: (event) => event.preventDefault(),
1349
1735
  onInteractOutside: (event) => {
1350
1736
  if (fieldRef.current?.contains(event.target)) event.preventDefault();
1351
1737
  },
1352
- children: /* @__PURE__ */ jsx25("div", { role: "listbox", className: "flex max-h-60 flex-col gap-0.5 overflow-y-auto", children: loading ? /* @__PURE__ */ jsx25("p", { className: "py-2 text-center text-sm text-muted-foreground", children: loadingMessage }) : renderChunks.length === 0 ? /* @__PURE__ */ jsx25("p", { className: "py-2 text-center text-sm text-muted-foreground", children: emptyMessage }) : renderChunks.map((chunk) => {
1738
+ children: /* @__PURE__ */ jsx27("div", { role: "listbox", className: cn("max-h-60 overflow-y-auto", !columns && "flex flex-col gap-0.5"), children: loading ? /* @__PURE__ */ jsx27("p", { className: "py-2 text-center text-sm text-muted-foreground", children: loadingMessage }) : visibleOptions.length === 0 ? /* @__PURE__ */ jsx27("p", { className: "py-2 text-center text-sm text-muted-foreground", children: emptyMessage }) : columns ? renderGridOptions({
1739
+ columns,
1740
+ options: visibleOptions,
1741
+ activeIndex,
1742
+ multiple: true,
1743
+ isSelected: (option) => value.includes(option.value),
1744
+ onSelect: toggleOption,
1745
+ onHover: setActiveIndex,
1746
+ testId
1747
+ }) : renderChunks.map((chunk) => {
1353
1748
  if (chunk.kind === "single") return renderOption(chunk.row);
1354
1749
  const headerState = groupCheckState(options, value, chunk.group);
1355
1750
  return (
@@ -1359,14 +1754,14 @@ function TagCombobox({
1359
1754
  // past its first row. Spacing above a group lives on this wrapper's
1360
1755
  // `pt-1`/`first:pt-0`, not on the header itself -- see `Combobox`'s own
1361
1756
  // identical structure for why both of these matter.
1362
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-0.5 pt-1 first:pt-0", children: [
1363
- /* @__PURE__ */ jsxs11(
1757
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-0.5 pt-1 first:pt-0", children: [
1758
+ /* @__PURE__ */ jsxs13(
1364
1759
  "div",
1365
1760
  {
1366
1761
  "data-group-header": true,
1367
1762
  className: "sticky top-0 z-10 flex items-center gap-2 rounded-sm bg-muted px-2 py-1.5 text-sm font-semibold text-foreground",
1368
1763
  children: [
1369
- /* @__PURE__ */ jsx25(
1764
+ /* @__PURE__ */ jsx27(
1370
1765
  "input",
1371
1766
  {
1372
1767
  type: "checkbox",
@@ -1380,7 +1775,7 @@ function TagCombobox({
1380
1775
  "aria-label": `Select all of ${groupLabel(chunk.group)}`
1381
1776
  }
1382
1777
  ),
1383
- /* @__PURE__ */ jsx25("span", { className: "truncate", children: groupLabel(chunk.group) })
1778
+ /* @__PURE__ */ jsx27("span", { className: "truncate", children: groupLabel(chunk.group) })
1384
1779
  ]
1385
1780
  }
1386
1781
  ),
@@ -1395,37 +1790,37 @@ function TagCombobox({
1395
1790
 
1396
1791
  // src/patterns/alert-box/AlertBox.tsx
1397
1792
  import { AlertCircle, AlertTriangle, CheckCircle2, Info } from "lucide-react";
1398
- import { jsx as jsx26, jsxs as jsxs12 } from "react/jsx-runtime";
1793
+ import { jsx as jsx28, jsxs as jsxs14 } from "react/jsx-runtime";
1399
1794
  var variantStyles = {
1400
- error: "border-destructive bg-destructive/10 text-destructive",
1401
- warning: "border-amber-500 bg-amber-500/10 text-amber-700 dark:text-amber-300",
1795
+ error: "border-destructive bg-destructive/10 text-red-800 dark:text-red-300",
1796
+ warning: "border-amber-500 bg-amber-500/10 text-amber-900 dark:text-amber-200",
1402
1797
  info: "border-sky-500 bg-sky-500/10 text-sky-700 dark:text-sky-300",
1403
1798
  success: "border-emerald-500 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"
1404
1799
  };
1405
1800
  var defaultIcons = {
1406
- error: /* @__PURE__ */ jsx26(AlertCircle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
1407
- warning: /* @__PURE__ */ jsx26(AlertTriangle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
1408
- info: /* @__PURE__ */ jsx26(Info, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
1409
- success: /* @__PURE__ */ jsx26(CheckCircle2, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" })
1801
+ error: /* @__PURE__ */ jsx28(AlertCircle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
1802
+ warning: /* @__PURE__ */ jsx28(AlertTriangle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
1803
+ info: /* @__PURE__ */ jsx28(Info, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
1804
+ success: /* @__PURE__ */ jsx28(CheckCircle2, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" })
1410
1805
  };
1411
1806
  var AlertBox = ({ variant, title, children, className, icon }) => {
1412
1807
  const resolvedIcon = icon === void 0 ? defaultIcons[variant] : icon;
1413
- return /* @__PURE__ */ jsx26("div", { className: cn("rounded-md border p-3 text-sm", variantStyles[variant], className), children: /* @__PURE__ */ jsxs12("div", { className: "flex flex-row items-start gap-2", children: [
1414
- resolvedIcon != null && /* @__PURE__ */ jsx26("span", { className: "mt-0.5 shrink-0", children: resolvedIcon }),
1415
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-1", children: [
1416
- title && /* @__PURE__ */ jsx26("p", { className: "font-bold", children: title }),
1417
- /* @__PURE__ */ jsx26("div", { children })
1808
+ return /* @__PURE__ */ jsx28("div", { className: cn("rounded-md border p-3 text-sm", variantStyles[variant], className), children: /* @__PURE__ */ jsxs14("div", { className: "flex flex-row items-start gap-2", children: [
1809
+ resolvedIcon != null && /* @__PURE__ */ jsx28("span", { className: "mt-0.5 shrink-0", children: resolvedIcon }),
1810
+ /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-1", children: [
1811
+ title && /* @__PURE__ */ jsx28("p", { className: "font-bold", children: title }),
1812
+ /* @__PURE__ */ jsx28("div", { children })
1418
1813
  ] })
1419
1814
  ] }) });
1420
1815
  };
1421
1816
 
1422
1817
  // src/patterns/status-badge/StatusBadge.tsx
1423
- import { jsx as jsx27 } from "react/jsx-runtime";
1818
+ import { jsx as jsx29 } from "react/jsx-runtime";
1424
1819
  var TONE_CLASSES = {
1425
1820
  success: "border-transparent bg-emerald-500/15 text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-300",
1426
- warning: "border-transparent bg-amber-500/15 text-amber-700 dark:bg-amber-500/20 dark:text-amber-300",
1821
+ warning: "border-transparent bg-amber-500/15 text-amber-800 dark:bg-amber-500/20 dark:text-amber-300",
1427
1822
  info: "border-transparent bg-sky-500/15 text-sky-700 dark:bg-sky-500/20 dark:text-sky-300",
1428
- error: "border-transparent bg-destructive/15 text-destructive",
1823
+ error: "border-transparent bg-destructive/15 text-red-800 dark:text-red-300",
1429
1824
  neutral: "border-transparent bg-muted text-muted-foreground"
1430
1825
  };
1431
1826
  var DEFAULT_TONE_MAP = {
@@ -1467,11 +1862,11 @@ function resolveTone(status, tone, toneMap) {
1467
1862
  var StatusBadge = ({ status, label, tone, toneMap, className, ...props }) => {
1468
1863
  const resolvedTone = resolveTone(status, tone, toneMap);
1469
1864
  const displayLabel = label ?? deriveLabel(status);
1470
- return /* @__PURE__ */ jsx27(Badge, { variant: "outline", className: cn(TONE_CLASSES[resolvedTone], className), ...props, children: displayLabel });
1865
+ return /* @__PURE__ */ jsx29(Badge, { variant: "outline", className: cn(TONE_CLASSES[resolvedTone], className), ...props, children: displayLabel });
1471
1866
  };
1472
1867
 
1473
1868
  // src/patterns/button-group/ButtonGroup.tsx
1474
- import { jsx as jsx28, jsxs as jsxs13 } from "react/jsx-runtime";
1869
+ import { jsx as jsx30, jsxs as jsxs15 } from "react/jsx-runtime";
1475
1870
  function ButtonGroup({
1476
1871
  options,
1477
1872
  value,
@@ -1481,10 +1876,10 @@ function ButtonGroup({
1481
1876
  className,
1482
1877
  ...props
1483
1878
  }) {
1484
- return /* @__PURE__ */ jsx28("div", { role: "group", "aria-label": props["aria-label"], className: cn("inline-flex", className), "data-testid": props["data-testid"], children: options.map((option, index) => {
1879
+ return /* @__PURE__ */ jsx30("div", { role: "group", "aria-label": props["aria-label"], className: cn("inline-flex", className), "data-testid": props["data-testid"], children: options.map((option, index) => {
1485
1880
  const selected = option.value === value;
1486
1881
  const Icon2 = option.icon;
1487
- return /* @__PURE__ */ jsxs13(
1882
+ return /* @__PURE__ */ jsxs15(
1488
1883
  Button,
1489
1884
  {
1490
1885
  type: "button",
@@ -1502,7 +1897,7 @@ function ButtonGroup({
1502
1897
  index > 0 && "-ml-px"
1503
1898
  ),
1504
1899
  children: [
1505
- Icon2 && /* @__PURE__ */ jsx28(Icon2, { className: "h-4 w-4" }),
1900
+ Icon2 && /* @__PURE__ */ jsx30(Icon2, { className: "h-4 w-4" }),
1506
1901
  option.label
1507
1902
  ]
1508
1903
  },
@@ -1514,7 +1909,7 @@ function ButtonGroup({
1514
1909
  // src/patterns/loading-spinner/LoadingSpinner.tsx
1515
1910
  import { cva as cva4 } from "class-variance-authority";
1516
1911
  import { Loader2 } from "lucide-react";
1517
- import { jsx as jsx29, jsxs as jsxs14 } from "react/jsx-runtime";
1912
+ import { jsx as jsx31, jsxs as jsxs16 } from "react/jsx-runtime";
1518
1913
  var loadingSpinnerIconVariants = cva4("animate-spin text-muted-foreground", {
1519
1914
  variants: {
1520
1915
  size: {
@@ -1532,27 +1927,27 @@ var LoadingSpinner = ({
1532
1927
  label,
1533
1928
  className,
1534
1929
  ...props
1535
- }) => /* @__PURE__ */ jsxs14("span", { role: "status", className: cn("inline-flex items-center gap-2", className), ...props, children: [
1536
- /* @__PURE__ */ jsx29(Loader2, { className: cn(loadingSpinnerIconVariants({ size })), "aria-hidden": "true" }),
1537
- label ? /* @__PURE__ */ jsx29("span", { children: label }) : null
1930
+ }) => /* @__PURE__ */ jsxs16("span", { role: "status", className: cn("inline-flex items-center gap-2", className), ...props, children: [
1931
+ /* @__PURE__ */ jsx31(Loader2, { className: cn(loadingSpinnerIconVariants({ size })), "aria-hidden": "true" }),
1932
+ label ? /* @__PURE__ */ jsx31("span", { children: label }) : null
1538
1933
  ] });
1539
1934
  var LoadingOverlay = ({
1540
1935
  size = "lg",
1541
1936
  label,
1542
1937
  className,
1543
1938
  ...props
1544
- }) => /* @__PURE__ */ jsx29(
1939
+ }) => /* @__PURE__ */ jsx31(
1545
1940
  "div",
1546
1941
  {
1547
1942
  className: cn("flex h-full min-h-32 w-full items-center justify-center", className),
1548
1943
  ...props,
1549
- children: /* @__PURE__ */ jsx29(LoadingSpinner, { size, label })
1944
+ children: /* @__PURE__ */ jsx31(LoadingSpinner, { size, label })
1550
1945
  }
1551
1946
  );
1552
1947
 
1553
1948
  // src/patterns/search-bar/SearchBar.tsx
1554
1949
  import { Search, X as X5 } from "lucide-react";
1555
- import { jsx as jsx30, jsxs as jsxs15 } from "react/jsx-runtime";
1950
+ import { jsx as jsx32, jsxs as jsxs17 } from "react/jsx-runtime";
1556
1951
  function SearchBar({
1557
1952
  value,
1558
1953
  onChange,
@@ -1564,9 +1959,9 @@ function SearchBar({
1564
1959
  ...props
1565
1960
  }) {
1566
1961
  const showClear = onClear !== false && value.length > 0;
1567
- return /* @__PURE__ */ jsxs15("div", { className: cn("relative", className), children: [
1568
- /* @__PURE__ */ jsx30("span", { className: "pointer-events-none absolute top-1/2 left-4 -translate-y-1/2 text-muted-foreground", children: isLoading ? /* @__PURE__ */ jsx30(LoadingSpinner, { size: "sm" }) : /* @__PURE__ */ jsx30(Search, { className: "h-4 w-4", "aria-hidden": "true" }) }),
1569
- /* @__PURE__ */ jsx30(
1962
+ return /* @__PURE__ */ jsxs17("div", { className: cn("relative", className), children: [
1963
+ /* @__PURE__ */ jsx32("span", { className: "pointer-events-none absolute top-1/2 left-4 -translate-y-1/2 text-muted-foreground", children: isLoading ? /* @__PURE__ */ jsx32(LoadingSpinner, { size: "sm" }) : /* @__PURE__ */ jsx32(Search, { className: "h-4 w-4", "aria-hidden": "true" }) }),
1964
+ /* @__PURE__ */ jsx32(
1570
1965
  "input",
1571
1966
  {
1572
1967
  ref: inputRef,
@@ -1585,19 +1980,370 @@ function SearchBar({
1585
1980
  ...props
1586
1981
  }
1587
1982
  ),
1588
- showClear && /* @__PURE__ */ jsx30(
1983
+ showClear && /* @__PURE__ */ jsx32(
1589
1984
  "button",
1590
1985
  {
1591
1986
  type: "button",
1592
1987
  onClick: () => onClear ? onClear() : onChange(""),
1593
1988
  "aria-label": clearLabel,
1594
1989
  className: "absolute top-1/2 right-2 flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full text-muted-foreground hover:bg-accent hover:text-foreground",
1595
- children: /* @__PURE__ */ jsx30(X5, { className: "h-4 w-4", "aria-hidden": "true" })
1990
+ children: /* @__PURE__ */ jsx32(X5, { className: "h-4 w-4", "aria-hidden": "true" })
1596
1991
  }
1597
1992
  )
1598
1993
  ] });
1599
1994
  }
1600
1995
 
1996
+ // src/patterns/kpi-card/KpiCard.tsx
1997
+ import { memo } from "react";
1998
+ import { Fragment as Fragment2, jsx as jsx33, jsxs as jsxs18 } from "react/jsx-runtime";
1999
+ var DONUT_COLORS = [
2000
+ "var(--chart-1, #3b82f6)",
2001
+ "var(--chart-2, #22c55e)",
2002
+ "var(--chart-3, #f59e0b)",
2003
+ "var(--chart-4, #8b5cf6)",
2004
+ "var(--chart-5, #ef4444)",
2005
+ "var(--chart-6, #06b6d4)"
2006
+ ];
2007
+ function DonutChart({
2008
+ data,
2009
+ size = 96,
2010
+ thickness = 14,
2011
+ centerValue,
2012
+ centerLabel
2013
+ }) {
2014
+ const total = data.reduce((sum, d) => sum + d.value, 0);
2015
+ if (total <= 0) return null;
2016
+ const radius = (size - thickness) / 2;
2017
+ const circumference = 2 * Math.PI * radius;
2018
+ let offset = 0;
2019
+ return /* @__PURE__ */ jsxs18("div", { className: "relative inline-flex shrink-0 items-center justify-center", style: { width: size, height: size }, children: [
2020
+ /* @__PURE__ */ jsxs18("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "-rotate-90", children: [
2021
+ /* @__PURE__ */ jsx33("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", stroke: "currentColor", className: "text-muted/40", strokeWidth: thickness }),
2022
+ data.map((segment, i) => {
2023
+ const fraction = segment.value / total;
2024
+ const dash = fraction * circumference;
2025
+ const el = /* @__PURE__ */ jsx33(
2026
+ "circle",
2027
+ {
2028
+ cx: size / 2,
2029
+ cy: size / 2,
2030
+ r: radius,
2031
+ fill: "none",
2032
+ stroke: segment.color ?? DONUT_COLORS[i % DONUT_COLORS.length],
2033
+ strokeWidth: thickness,
2034
+ strokeDasharray: `${dash} ${circumference - dash}`,
2035
+ strokeDashoffset: -offset,
2036
+ strokeLinecap: data.length > 1 ? "butt" : "round"
2037
+ },
2038
+ segment.label
2039
+ );
2040
+ offset += dash;
2041
+ return el;
2042
+ })
2043
+ ] }),
2044
+ (centerValue || centerLabel) && /* @__PURE__ */ jsxs18("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: [
2045
+ centerValue && /* @__PURE__ */ jsx33("span", { className: "text-base font-black tracking-tight text-foreground tabular-nums", children: centerValue }),
2046
+ centerLabel && /* @__PURE__ */ jsx33("span", { className: "text-[9px] font-medium text-muted-foreground uppercase", children: centerLabel })
2047
+ ] })
2048
+ ] });
2049
+ }
2050
+ function Sparkline({ data, color }) {
2051
+ if (data.length < 2) return null;
2052
+ const min = Math.min(...data);
2053
+ const max = Math.max(...data);
2054
+ const range = max - min || 1;
2055
+ const W = 72;
2056
+ const H = 28;
2057
+ const pts = data.map((v, i) => `${i / (data.length - 1) * W},${H - (v - min) / range * (H - 2) - 1}`).join(" ");
2058
+ return /* @__PURE__ */ jsx33("svg", { width: W, height: H, viewBox: `0 0 ${W} ${H}`, className: "overflow-visible opacity-70", children: /* @__PURE__ */ jsx33("polyline", { points: pts, fill: "none", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
2059
+ }
2060
+ function AreaSparkline({ data, color }) {
2061
+ if (data.length < 2) return null;
2062
+ const min = Math.min(...data);
2063
+ const max = Math.max(...data);
2064
+ const range = max - min || 1;
2065
+ const W = 200;
2066
+ const H = 28;
2067
+ const P = 2;
2068
+ const xs = data.map((_, i) => i / (data.length - 1) * W);
2069
+ const ys = data.map((v) => H - (v - min) / range * (H - 2 * P) - P);
2070
+ const linePts = xs.map((x, i) => `${x},${ys[i]}`).join(" ");
2071
+ const areaPath = `M${xs[0]},${H} ` + xs.map((x, i) => `L${x},${ys[i]}`).join(" ") + ` L${xs[xs.length - 1]},${H} Z`;
2072
+ return /* @__PURE__ */ jsxs18("svg", { width: W, height: H, viewBox: `0 0 ${W} ${H}`, className: "overflow-visible", preserveAspectRatio: "none", children: [
2073
+ /* @__PURE__ */ jsx33("defs", { children: /* @__PURE__ */ jsxs18("linearGradient", { id: "kpi-card-spark-fill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
2074
+ /* @__PURE__ */ jsx33("stop", { offset: "0%", stopColor: color, stopOpacity: "0.22" }),
2075
+ /* @__PURE__ */ jsx33("stop", { offset: "100%", stopColor: color, stopOpacity: "0" })
2076
+ ] }) }),
2077
+ /* @__PURE__ */ jsx33("path", { d: areaPath, fill: "url(#kpi-card-spark-fill)" }),
2078
+ /* @__PURE__ */ jsx33("polyline", { points: linePts, fill: "none", stroke: color, strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }),
2079
+ /* @__PURE__ */ jsx33("circle", { cx: xs[xs.length - 1], cy: ys[ys.length - 1], r: "2.5", fill: color })
2080
+ ] });
2081
+ }
2082
+ var rowBetween = "flex items-center justify-between";
2083
+ var KpiCard = memo(function KpiCard2({
2084
+ label,
2085
+ value,
2086
+ icon: Icon2,
2087
+ badge,
2088
+ badgeLabel,
2089
+ variant = "default",
2090
+ loading = false,
2091
+ sub,
2092
+ subTone = "default",
2093
+ href,
2094
+ sparkline,
2095
+ sparklineColor = "var(--color-primary, #3b82f6)",
2096
+ progress,
2097
+ progressLabel,
2098
+ segments,
2099
+ centerValue,
2100
+ testId
2101
+ }) {
2102
+ if (variant === "hero") {
2103
+ return /* @__PURE__ */ jsxs18(
2104
+ "div",
2105
+ {
2106
+ "data-testid": testId,
2107
+ className: "relative col-span-2 flex min-w-0 flex-1 flex-col gap-1.5 overflow-hidden rounded-2xl p-4 md:p-3 lg:col-span-1 lg:max-w-[340px] lg:min-w-[260px]",
2108
+ style: {
2109
+ background: "var(--color-primary)",
2110
+ boxShadow: "0 2px 10px color-mix(in oklch, var(--color-primary) 18%, transparent)"
2111
+ },
2112
+ children: [
2113
+ /* @__PURE__ */ jsxs18("div", { className: "relative flex items-start justify-between", children: [
2114
+ /* @__PURE__ */ jsx33("p", { className: "text-[11px] font-bold tracking-[0.14em] text-white/70 uppercase", children: label }),
2115
+ Icon2 && /* @__PURE__ */ jsx33("div", { className: "flex h-6 w-6 items-center justify-center rounded-lg bg-white/15 ring-1 ring-white/20", children: /* @__PURE__ */ jsx33(Icon2, { className: "h-3 w-3 text-white/90", "aria-hidden": "true" }) })
2116
+ ] }),
2117
+ /* @__PURE__ */ jsx33("div", { className: "relative", children: loading ? /* @__PURE__ */ jsx33("div", { className: "h-6 w-28 animate-pulse rounded-lg bg-white/15" }) : /* @__PURE__ */ jsx33("p", { className: "text-2xl leading-none font-black tracking-tight text-white tabular-nums md:text-[22px]", children: value ?? "\u2014" }) }),
2118
+ (badge || badgeLabel) && !loading && /* @__PURE__ */ jsxs18("div", { className: "relative flex items-center gap-2", children: [
2119
+ badge && /* @__PURE__ */ jsx33(
2120
+ "span",
2121
+ {
2122
+ className: cn(
2123
+ "inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-[11px] font-bold tabular-nums ring-1",
2124
+ badge.positive ? "bg-white/15 text-white ring-white/25" : "bg-black/25 text-white ring-white/15"
2125
+ ),
2126
+ children: badge.text
2127
+ }
2128
+ ),
2129
+ badgeLabel && /* @__PURE__ */ jsx33("span", { className: "text-[11px] text-white/70", children: badgeLabel })
2130
+ ] }),
2131
+ sub && !loading && /* @__PURE__ */ jsx33("p", { className: "relative -mt-1 text-[11px] font-medium text-white/75 tabular-nums", children: sub }),
2132
+ progress != null && !loading && /* @__PURE__ */ jsxs18("div", { className: "relative flex items-center gap-1.5", children: [
2133
+ /* @__PURE__ */ jsx33("div", { className: "h-1 flex-1 overflow-hidden rounded-full bg-white/20", children: /* @__PURE__ */ jsx33("div", { className: "h-1 rounded-full bg-white/85", style: { width: `${Math.min(100, Math.max(0, progress))}%` } }) }),
2134
+ progressLabel && /* @__PURE__ */ jsx33("span", { className: "shrink-0 text-[11px] font-semibold text-white/80 tabular-nums", children: progressLabel })
2135
+ ] }),
2136
+ sparkline && sparkline.length > 1 && !loading && /* @__PURE__ */ jsx33("div", { className: "relative -mx-4 mt-auto -mb-4 md:-mx-3 md:-mb-3", children: /* @__PURE__ */ jsx33(AreaSparkline, { data: sparkline, color: "#ffffff" }) })
2137
+ ]
2138
+ }
2139
+ );
2140
+ }
2141
+ if (variant === "mini") {
2142
+ const iconSlot = Icon2 ? href ? /* @__PURE__ */ jsx33(
2143
+ "a",
2144
+ {
2145
+ href,
2146
+ className: "tap-target flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary transition-[background-color,scale] hover:bg-primary/20 active:scale-90 motion-reduce:transition-none md:h-6 md:w-6",
2147
+ children: /* @__PURE__ */ jsx33(Icon2, { className: "h-4 w-4 md:h-3.5 md:w-3.5", "aria-hidden": "true" })
2148
+ }
2149
+ ) : /* @__PURE__ */ jsx33("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary md:h-6 md:w-6", children: /* @__PURE__ */ jsx33(Icon2, { className: "h-4 w-4 md:h-3.5 md:w-3.5", "aria-hidden": "true" }) }) : null;
2150
+ return /* @__PURE__ */ jsxs18(
2151
+ "div",
2152
+ {
2153
+ "data-testid": testId,
2154
+ className: cn(
2155
+ "flex h-full min-w-0 flex-1 flex-col gap-1.5 overflow-hidden rounded-2xl border border-border bg-card p-3 transition-shadow md:p-2.5",
2156
+ href && "hover:border-primary/20 hover:shadow-md"
2157
+ ),
2158
+ children: [
2159
+ /* @__PURE__ */ jsxs18("div", { className: rowBetween, children: [
2160
+ /* @__PURE__ */ jsx33("p", { className: "text-[11px] font-bold tracking-[0.12em] text-muted-foreground uppercase", children: label }),
2161
+ iconSlot
2162
+ ] }),
2163
+ /* @__PURE__ */ jsx33("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: loading ? /* @__PURE__ */ jsx33(Skeleton, { className: "h-6 w-16" }) : /* @__PURE__ */ jsxs18(Fragment2, { children: [
2164
+ /* @__PURE__ */ jsx33("p", { className: "min-w-0 animate-in truncate text-[20px] leading-none font-black tracking-tight text-foreground duration-200 fade-in-0 tabular-nums motion-reduce:animate-none md:text-[16px]", children: value ?? "\u2014" }),
2165
+ badge && /* @__PURE__ */ jsx33(
2166
+ "span",
2167
+ {
2168
+ className: cn(
2169
+ "shrink-0 animate-in rounded-md px-1.5 py-0.5 text-[11px] font-bold duration-200 fade-in-0 tabular-nums motion-reduce:animate-none",
2170
+ badge.positive ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400" : "bg-muted text-muted-foreground"
2171
+ ),
2172
+ children: badge.text
2173
+ }
2174
+ )
2175
+ ] }) }),
2176
+ (sub || sparkline) && !loading && /* @__PURE__ */ jsxs18("div", { className: "flex items-end justify-between gap-2", children: [
2177
+ sub && /* @__PURE__ */ jsx33(
2178
+ "p",
2179
+ {
2180
+ className: cn(
2181
+ "text-[11px]",
2182
+ subTone === "danger" ? "font-semibold text-red-600 dark:text-red-400" : subTone === "warn" ? "font-semibold text-amber-700 dark:text-amber-300" : "text-muted-foreground"
2183
+ ),
2184
+ children: sub
2185
+ }
2186
+ ),
2187
+ sparkline && /* @__PURE__ */ jsx33(Sparkline, { data: sparkline, color: sparklineColor })
2188
+ ] })
2189
+ ]
2190
+ }
2191
+ );
2192
+ }
2193
+ if (variant === "donut") {
2194
+ const total = segments?.reduce((sum, s) => sum + s.value, 0) ?? 0;
2195
+ return /* @__PURE__ */ jsxs18("div", { "data-testid": testId, className: "rounded-xl border border-border bg-card p-5", children: [
2196
+ /* @__PURE__ */ jsxs18("div", { className: rowBetween, children: [
2197
+ /* @__PURE__ */ jsx33("p", { className: "text-[11px] font-bold tracking-[0.12em] text-muted-foreground uppercase", children: label }),
2198
+ Icon2 && /* @__PURE__ */ jsx33("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/8 text-primary", children: /* @__PURE__ */ jsx33(Icon2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }) })
2199
+ ] }),
2200
+ loading ? /* @__PURE__ */ jsxs18("div", { className: "mt-3 flex items-center gap-4", children: [
2201
+ /* @__PURE__ */ jsx33(Skeleton, { className: "h-24 w-24 shrink-0 rounded-full" }),
2202
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-1 flex-col gap-2", children: [
2203
+ /* @__PURE__ */ jsx33(Skeleton, { className: "h-3 w-full" }),
2204
+ /* @__PURE__ */ jsx33(Skeleton, { className: "h-3 w-3/4" }),
2205
+ /* @__PURE__ */ jsx33(Skeleton, { className: "h-3 w-1/2" })
2206
+ ] })
2207
+ ] }) : segments && segments.length > 0 ? /* @__PURE__ */ jsxs18("div", { className: "mt-3 flex items-center gap-4", children: [
2208
+ /* @__PURE__ */ jsx33(DonutChart, { data: segments, centerValue: centerValue ?? String(total) }),
2209
+ /* @__PURE__ */ jsx33("ul", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: segments.map((segment, i) => /* @__PURE__ */ jsxs18("li", { className: "flex items-center gap-2 text-[12px]", children: [
2210
+ /* @__PURE__ */ jsx33(
2211
+ "span",
2212
+ {
2213
+ className: "h-2 w-2 shrink-0 rounded-full",
2214
+ style: { backgroundColor: segment.color ?? DONUT_COLORS[i % DONUT_COLORS.length] },
2215
+ "aria-hidden": "true"
2216
+ }
2217
+ ),
2218
+ /* @__PURE__ */ jsx33("span", { className: "min-w-0 flex-1 truncate text-muted-foreground", children: segment.label }),
2219
+ /* @__PURE__ */ jsx33("span", { className: "shrink-0 font-semibold text-foreground tabular-nums", children: total > 0 ? `${Math.round(segment.value / total * 100)}%` : segment.value })
2220
+ ] }, segment.label)) })
2221
+ ] }) : /* @__PURE__ */ jsx33("span", { className: "mt-3 block text-2xl font-black text-muted-foreground/40", children: "\u2014" }),
2222
+ sub && !loading && /* @__PURE__ */ jsx33("p", { className: "mt-2.5 text-[11px] text-muted-foreground tabular-nums", children: sub })
2223
+ ] });
2224
+ }
2225
+ const strValue = value != null ? String(value) : null;
2226
+ const parts = strValue ? strValue.split(/\s(.+)/) : null;
2227
+ const plain = !parts || parts.length === 1;
2228
+ const isSuffix = !plain && /^\d/.test(parts[0]) && parts[1].length <= 3;
2229
+ const prefix = isSuffix ? null : parts?.[0];
2230
+ const number = isSuffix ? parts[0] : parts?.[1] ?? parts?.[0];
2231
+ const suffix = isSuffix ? parts[1] : null;
2232
+ return /* @__PURE__ */ jsxs18("div", { "data-testid": testId, className: "rounded-xl border border-border bg-card p-5", children: [
2233
+ /* @__PURE__ */ jsxs18("div", { className: rowBetween, children: [
2234
+ /* @__PURE__ */ jsx33("p", { className: "text-[11px] font-bold tracking-[0.12em] text-muted-foreground uppercase", children: label }),
2235
+ Icon2 && /* @__PURE__ */ jsx33("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/8 text-primary", children: /* @__PURE__ */ jsx33(Icon2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }) })
2236
+ ] }),
2237
+ /* @__PURE__ */ jsxs18("div", { className: "mt-3", children: [
2238
+ loading ? /* @__PURE__ */ jsx33(Skeleton, { className: "h-7 w-20" }) : value == null ? /* @__PURE__ */ jsx33("span", { className: "text-2xl font-black text-muted-foreground/40", children: "\u2014" }) : plain ? /* @__PURE__ */ jsx33("span", { className: "animate-in text-2xl font-black tracking-tight text-foreground duration-200 fade-in-0 tabular-nums motion-reduce:animate-none", children: strValue }) : /* @__PURE__ */ jsxs18("span", { className: "animate-in font-black tracking-tight text-foreground duration-200 fade-in-0 tabular-nums motion-reduce:animate-none", children: [
2239
+ prefix && /* @__PURE__ */ jsxs18("span", { className: "text-sm text-muted-foreground", children: [
2240
+ prefix,
2241
+ " "
2242
+ ] }),
2243
+ /* @__PURE__ */ jsx33("span", { className: "text-2xl", children: number }),
2244
+ suffix && /* @__PURE__ */ jsxs18("span", { className: "text-sm text-muted-foreground", children: [
2245
+ " ",
2246
+ suffix
2247
+ ] })
2248
+ ] }),
2249
+ sub && !loading && /* @__PURE__ */ jsx33("p", { className: "mt-0.5 text-[11px] text-muted-foreground tabular-nums", children: sub })
2250
+ ] }),
2251
+ (badge || badgeLabel || sparkline) && !loading && /* @__PURE__ */ jsxs18("div", { className: "mt-2.5 flex items-end justify-between gap-2", children: [
2252
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-wrap items-center gap-2", children: [
2253
+ badge && /* @__PURE__ */ jsx33(
2254
+ "span",
2255
+ {
2256
+ className: cn(
2257
+ "rounded-md px-1.5 py-0.5 text-[11px] font-semibold tabular-nums",
2258
+ badge.positive ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400" : "bg-muted text-muted-foreground"
2259
+ ),
2260
+ children: badge.text
2261
+ }
2262
+ ),
2263
+ badgeLabel && /* @__PURE__ */ jsx33("span", { className: "text-[11px] text-muted-foreground", children: badgeLabel })
2264
+ ] }),
2265
+ sparkline && /* @__PURE__ */ jsx33(Sparkline, { data: sparkline, color: sparklineColor })
2266
+ ] })
2267
+ ] });
2268
+ });
2269
+
2270
+ // src/patterns/search-panel/SearchPanel.tsx
2271
+ import { Search as Search2 } from "lucide-react";
2272
+ import { jsx as jsx34, jsxs as jsxs19 } from "react/jsx-runtime";
2273
+ function SearchPanel({
2274
+ value,
2275
+ onChange,
2276
+ isLoading,
2277
+ trailingSlot,
2278
+ shortcutHint,
2279
+ modes,
2280
+ activeMode,
2281
+ onModeChange,
2282
+ expanded = false,
2283
+ inputRef,
2284
+ className,
2285
+ ...props
2286
+ }) {
2287
+ return /* @__PURE__ */ jsxs19(
2288
+ "div",
2289
+ {
2290
+ className: cn(
2291
+ "flex flex-col border border-border bg-card shadow-sm",
2292
+ expanded ? "rounded-t-2xl border-b-transparent" : "rounded-2xl",
2293
+ className
2294
+ ),
2295
+ children: [
2296
+ /* @__PURE__ */ jsxs19("div", { className: "flex h-14 items-center gap-3 px-4", children: [
2297
+ isLoading ? /* @__PURE__ */ jsx34(LoadingSpinner, { size: "sm" }) : /* @__PURE__ */ jsx34(Search2, { className: "h-5 w-5 shrink-0 text-muted-foreground", "aria-hidden": "true" }),
2298
+ /* @__PURE__ */ jsx34(
2299
+ "input",
2300
+ {
2301
+ ref: inputRef,
2302
+ type: "text",
2303
+ value,
2304
+ onChange: (event) => onChange(event.target.value),
2305
+ className: "min-w-0 flex-1 bg-transparent text-[15px] text-foreground outline-none placeholder:text-muted-foreground",
2306
+ ...props
2307
+ }
2308
+ ),
2309
+ trailingSlot,
2310
+ shortcutHint && /* @__PURE__ */ jsx34(
2311
+ "kbd",
2312
+ {
2313
+ "aria-hidden": "true",
2314
+ className: "hidden shrink-0 items-center rounded border border-border bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground select-none sm:inline-flex",
2315
+ children: shortcutHint
2316
+ }
2317
+ )
2318
+ ] }),
2319
+ modes && modes.length > 0 && /* @__PURE__ */ jsx34("div", { className: "flex items-center gap-2 px-4 pb-3", children: modes.map(({ key, label, icon: Icon2 }) => /* @__PURE__ */ jsxs19(
2320
+ "button",
2321
+ {
2322
+ type: "button",
2323
+ onClick: () => onModeChange?.(key),
2324
+ className: cn(
2325
+ "flex items-center gap-1.5 rounded-full px-3 py-1.5 text-[13px] font-medium transition-colors",
2326
+ activeMode === key ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"
2327
+ ),
2328
+ children: [
2329
+ Icon2 && /* @__PURE__ */ jsx34(Icon2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
2330
+ label
2331
+ ]
2332
+ },
2333
+ key
2334
+ )) })
2335
+ ]
2336
+ }
2337
+ );
2338
+ }
2339
+
2340
+ // src/patterns/search-panel/SearchTrigger.tsx
2341
+ import { Search as Search3 } from "lucide-react";
2342
+ import { jsx as jsx35 } from "react/jsx-runtime";
2343
+ function SearchTrigger({ label = "Search", ...props }) {
2344
+ return /* @__PURE__ */ jsx35(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": label, ...props, children: /* @__PURE__ */ jsx35(Search3, { className: "h-[18px] w-[18px]", "aria-hidden": "true" }) });
2345
+ }
2346
+
1601
2347
  // src/patterns/sidebar/context.ts
1602
2348
  import { createContext, useContext } from "react";
1603
2349
  var SidebarContext = createContext({ collapsed: false });
@@ -1607,7 +2353,7 @@ function useSidebarCollapsed() {
1607
2353
  }
1608
2354
 
1609
2355
  // src/patterns/sidebar/NavItem.tsx
1610
- import { jsx as jsx31, jsxs as jsxs16 } from "react/jsx-runtime";
2356
+ import { jsx as jsx36, jsxs as jsxs20 } from "react/jsx-runtime";
1611
2357
  function NavItem({
1612
2358
  as,
1613
2359
  icon: Icon2,
@@ -1619,7 +2365,7 @@ function NavItem({
1619
2365
  }) {
1620
2366
  const collapsed = useSidebarCollapsed();
1621
2367
  const Comp = as ?? "a";
1622
- const row = /* @__PURE__ */ jsxs16(
2368
+ const row = /* @__PURE__ */ jsxs20(
1623
2369
  Comp,
1624
2370
  {
1625
2371
  className: cn(
@@ -1631,7 +2377,7 @@ function NavItem({
1631
2377
  ),
1632
2378
  ...rest,
1633
2379
  children: [
1634
- Icon2 && /* @__PURE__ */ jsx31(
2380
+ Icon2 && /* @__PURE__ */ jsx36(
1635
2381
  Icon2,
1636
2382
  {
1637
2383
  className: cn("h-[18px] w-[18px] shrink-0", active ? "text-nav-primary" : "text-muted-foreground"),
@@ -1639,7 +2385,7 @@ function NavItem({
1639
2385
  "aria-hidden": true
1640
2386
  }
1641
2387
  ),
1642
- /* @__PURE__ */ jsx31(
2388
+ /* @__PURE__ */ jsx36(
1643
2389
  "span",
1644
2390
  {
1645
2391
  className: cn(
@@ -1654,9 +2400,9 @@ function NavItem({
1654
2400
  }
1655
2401
  );
1656
2402
  if (!collapsed) return row;
1657
- return /* @__PURE__ */ jsxs16(Tooltip, { children: [
1658
- /* @__PURE__ */ jsx31(TooltipTrigger, { asChild: true, children: row }),
1659
- /* @__PURE__ */ jsxs16(TooltipContent, { side: "right", className: "flex items-center gap-1.5", children: [
2403
+ return /* @__PURE__ */ jsxs20(Tooltip, { children: [
2404
+ /* @__PURE__ */ jsx36(TooltipTrigger, { asChild: true, children: row }),
2405
+ /* @__PURE__ */ jsxs20(TooltipContent, { side: "right", className: "flex items-center gap-1.5", children: [
1660
2406
  label,
1661
2407
  badge
1662
2408
  ] })
@@ -1665,8 +2411,8 @@ function NavItem({
1665
2411
 
1666
2412
  // src/patterns/sidebar/NavGroup.tsx
1667
2413
  import { ChevronDown as ChevronDown2 } from "lucide-react";
1668
- import { useState as useState5 } from "react";
1669
- import { jsx as jsx32, jsxs as jsxs17 } from "react/jsx-runtime";
2414
+ import { useState as useState8 } from "react";
2415
+ import { jsx as jsx37, jsxs as jsxs21 } from "react/jsx-runtime";
1670
2416
  function NavGroup({
1671
2417
  label,
1672
2418
  defaultCollapsed = false,
@@ -1675,15 +2421,15 @@ function NavGroup({
1675
2421
  children,
1676
2422
  className
1677
2423
  }) {
1678
- const [internalCollapsed, setInternalCollapsed] = useState5(defaultCollapsed);
2424
+ const [internalCollapsed, setInternalCollapsed] = useState8(defaultCollapsed);
1679
2425
  const groupCollapsed = collapsed ?? internalCollapsed;
1680
2426
  const railCollapsed = useSidebarCollapsed();
1681
2427
  const setGroupCollapsed = (next) => {
1682
2428
  onCollapsedChange?.(next);
1683
2429
  if (collapsed === void 0) setInternalCollapsed(next);
1684
2430
  };
1685
- return /* @__PURE__ */ jsxs17("div", { className: cn("flex flex-col gap-0.5", className), children: [
1686
- label && (railCollapsed ? /* @__PURE__ */ jsx32("div", { className: "mx-2 my-1 h-px bg-border/50", "aria-hidden": true }) : /* @__PURE__ */ jsxs17(
2431
+ return /* @__PURE__ */ jsxs21("div", { className: cn("flex flex-col gap-0.5", className), children: [
2432
+ label && (railCollapsed ? /* @__PURE__ */ jsx37("div", { className: "mx-2 my-1 h-px bg-border/50", "aria-hidden": true }) : /* @__PURE__ */ jsxs21(
1687
2433
  "button",
1688
2434
  {
1689
2435
  type: "button",
@@ -1691,8 +2437,8 @@ function NavGroup({
1691
2437
  "aria-expanded": !groupCollapsed,
1692
2438
  className: "group flex w-full items-center justify-between px-2.5 py-0.5 text-[11px] font-medium text-muted-foreground/80 hover:text-foreground",
1693
2439
  children: [
1694
- /* @__PURE__ */ jsx32("span", { children: label }),
1695
- /* @__PURE__ */ jsx32(
2440
+ /* @__PURE__ */ jsx37("span", { children: label }),
2441
+ /* @__PURE__ */ jsx37(
1696
2442
  ChevronDown2,
1697
2443
  {
1698
2444
  className: cn(
@@ -1705,7 +2451,7 @@ function NavGroup({
1705
2451
  ]
1706
2452
  }
1707
2453
  )),
1708
- !groupCollapsed && /* @__PURE__ */ jsx32("div", { className: "flex flex-col gap-0.5", children })
2454
+ !groupCollapsed && /* @__PURE__ */ jsx37("div", { className: "flex flex-col gap-0.5", children })
1709
2455
  ] });
1710
2456
  }
1711
2457
 
@@ -1713,11 +2459,11 @@ function NavGroup({
1713
2459
  import { PanelLeftClose, PanelLeftOpen } from "lucide-react";
1714
2460
  import {
1715
2461
  useCallback,
1716
- useEffect as useEffect3,
1717
- useRef as useRef3,
1718
- useState as useState6
2462
+ useEffect as useEffect5,
2463
+ useRef as useRef5,
2464
+ useState as useState9
1719
2465
  } from "react";
1720
- import { jsx as jsx33, jsxs as jsxs18 } from "react/jsx-runtime";
2466
+ import { Fragment as Fragment3, jsx as jsx38, jsxs as jsxs22 } from "react/jsx-runtime";
1721
2467
  function resolve(value, collapsed) {
1722
2468
  return typeof value === "function" ? value(collapsed) : value;
1723
2469
  }
@@ -1736,9 +2482,9 @@ function Sidebar({
1736
2482
  children,
1737
2483
  className
1738
2484
  }) {
1739
- const [internalWidth, setInternalWidth] = useState6(defaultWidth);
2485
+ const [internalWidth, setInternalWidth] = useState9(defaultWidth);
1740
2486
  const currentWidth = width ?? internalWidth;
1741
- const [isDragging, setIsDragging] = useState6(false);
2487
+ const [isDragging, setIsDragging] = useState9(false);
1742
2488
  const setWidth = useCallback(
1743
2489
  (next) => {
1744
2490
  const clamped = Math.min(maxWidth, Math.max(minWidth, next));
@@ -1747,7 +2493,7 @@ function Sidebar({
1747
2493
  },
1748
2494
  [maxWidth, minWidth, onWidthChange, width]
1749
2495
  );
1750
- const dragStartRef = useRef3(null);
2496
+ const dragStartRef = useRef5(null);
1751
2497
  const handlePointerDown = (event) => {
1752
2498
  event.currentTarget.setPointerCapture(event.pointerId);
1753
2499
  dragStartRef.current = { x: event.clientX, width: currentWidth };
@@ -1764,7 +2510,7 @@ function Sidebar({
1764
2510
  dragStartRef.current = null;
1765
2511
  setIsDragging(false);
1766
2512
  };
1767
- return /* @__PURE__ */ jsx33(SidebarContextProvider, { value: { collapsed }, children: /* @__PURE__ */ jsx33(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs18(
2513
+ return /* @__PURE__ */ jsx38(SidebarContextProvider, { value: { collapsed }, children: /* @__PURE__ */ jsx38(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs22(
1768
2514
  "aside",
1769
2515
  {
1770
2516
  style: { width: collapsed ? railWidth : currentWidth },
@@ -1774,22 +2520,47 @@ function Sidebar({
1774
2520
  className
1775
2521
  ),
1776
2522
  children: [
1777
- (header || onCollapsedChange) && /* @__PURE__ */ jsxs18("div", { className: "flex h-16 items-center gap-2 border-b border-border px-3", children: [
1778
- header && /* @__PURE__ */ jsx33("div", { className: "min-w-0 flex-1", children: resolve(header, collapsed) }),
1779
- onCollapsedChange && /* @__PURE__ */ jsx33(
2523
+ (header || onCollapsedChange) && /* @__PURE__ */ jsx38("div", { className: "flex h-16 items-center gap-2 border-b border-border px-3", children: collapsed && onCollapsedChange ? (
2524
+ // Collapsed rail: the header slot (e.g. a compact logo mark) and the
2525
+ // expand toggle would otherwise compete for the narrow rail's width
2526
+ // and clip each other, so they're stacked instead — the header shows
2527
+ // by default and cross-fades to the toggle icon on hover, matching
2528
+ // the same affordance OneSales' own sidebar rail uses.
2529
+ /* @__PURE__ */ jsxs22(
1780
2530
  "button",
1781
2531
  {
1782
2532
  type: "button",
1783
2533
  onClick: () => onCollapsedChange(!collapsed),
1784
- "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
2534
+ "aria-label": "Expand sidebar",
2535
+ className: "group relative flex h-9 w-9 shrink-0 items-center justify-center",
2536
+ children: [
2537
+ header && /* @__PURE__ */ jsx38("span", { className: "transition-opacity group-hover:opacity-0", children: resolve(header, collapsed) }),
2538
+ /* @__PURE__ */ jsx38(
2539
+ PanelLeftOpen,
2540
+ {
2541
+ className: "absolute h-4 w-4 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
2542
+ "aria-hidden": true
2543
+ }
2544
+ )
2545
+ ]
2546
+ }
2547
+ )
2548
+ ) : /* @__PURE__ */ jsxs22(Fragment3, { children: [
2549
+ header && /* @__PURE__ */ jsx38("div", { className: "min-w-0 flex-1", children: resolve(header, collapsed) }),
2550
+ onCollapsedChange && /* @__PURE__ */ jsx38(
2551
+ "button",
2552
+ {
2553
+ type: "button",
2554
+ onClick: () => onCollapsedChange(!collapsed),
2555
+ "aria-label": "Collapse sidebar",
1785
2556
  className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground",
1786
- children: collapsed ? /* @__PURE__ */ jsx33(PanelLeftOpen, { className: "h-4 w-4", "aria-hidden": true }) : /* @__PURE__ */ jsx33(PanelLeftClose, { className: "h-4 w-4", "aria-hidden": true })
2557
+ children: /* @__PURE__ */ jsx38(PanelLeftClose, { className: "h-4 w-4", "aria-hidden": true })
1787
2558
  }
1788
2559
  )
1789
- ] }),
1790
- /* @__PURE__ */ jsx33(SidebarNav, { children }),
1791
- footer && /* @__PURE__ */ jsx33("div", { className: "border-t border-border/50 px-2 py-2", children: resolve(footer, collapsed) }),
1792
- resizable && !collapsed && /* @__PURE__ */ jsx33(
2560
+ ] }) }),
2561
+ /* @__PURE__ */ jsx38(SidebarNav, { children }),
2562
+ footer && /* @__PURE__ */ jsx38("div", { className: "border-t border-border/50 px-2 py-2", children: resolve(footer, collapsed) }),
2563
+ resizable && !collapsed && /* @__PURE__ */ jsx38(
1793
2564
  "div",
1794
2565
  {
1795
2566
  onPointerDown: handlePointerDown,
@@ -1804,9 +2575,9 @@ function Sidebar({
1804
2575
  ) }) });
1805
2576
  }
1806
2577
  function SidebarNav({ children, className, ...rest }) {
1807
- const ref = useRef3(null);
1808
- const [showFade, setShowFade] = useState6(false);
1809
- useEffect3(() => {
2578
+ const ref = useRef5(null);
2579
+ const [showFade, setShowFade] = useState9(false);
2580
+ useEffect5(() => {
1810
2581
  const el = ref.current;
1811
2582
  if (!el) return;
1812
2583
  const update = () => setShowFade(el.scrollHeight - el.scrollTop - el.clientHeight > 1);
@@ -1819,8 +2590,8 @@ function SidebarNav({ children, className, ...rest }) {
1819
2590
  observer.disconnect();
1820
2591
  };
1821
2592
  }, []);
1822
- return /* @__PURE__ */ jsxs18("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [
1823
- /* @__PURE__ */ jsx33(
2593
+ return /* @__PURE__ */ jsxs22("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [
2594
+ /* @__PURE__ */ jsx38(
1824
2595
  "div",
1825
2596
  {
1826
2597
  ref,
@@ -1829,7 +2600,7 @@ function SidebarNav({ children, className, ...rest }) {
1829
2600
  children
1830
2601
  }
1831
2602
  ),
1832
- showFade && /* @__PURE__ */ jsx33(
2603
+ showFade && /* @__PURE__ */ jsx38(
1833
2604
  "div",
1834
2605
  {
1835
2606
  className: "pointer-events-none absolute right-0 bottom-0 left-0 h-6 bg-gradient-to-t from-sidebar to-transparent",
@@ -1859,6 +2630,7 @@ export {
1859
2630
  DialogHeader,
1860
2631
  DialogTitle,
1861
2632
  DialogTrigger,
2633
+ DonutChart,
1862
2634
  DropdownMenu,
1863
2635
  DropdownMenuCheckboxItem,
1864
2636
  DropdownMenuContent,
@@ -1877,6 +2649,7 @@ export {
1877
2649
  FormField,
1878
2650
  FormModal,
1879
2651
  Input,
2652
+ KpiCard,
1880
2653
  Label,
1881
2654
  LoadingOverlay,
1882
2655
  LoadingSpinner,
@@ -1887,9 +2660,12 @@ export {
1887
2660
  PopoverAnchor,
1888
2661
  PopoverContent,
1889
2662
  PopoverTrigger,
2663
+ ResponsivePanel,
1890
2664
  ScrollArea,
1891
2665
  ScrollBar,
1892
2666
  SearchBar,
2667
+ SearchPanel,
2668
+ SearchTrigger,
1893
2669
  Select,
1894
2670
  SelectContent,
1895
2671
  SelectGroup,
@@ -1909,6 +2685,7 @@ export {
1909
2685
  Sidebar,
1910
2686
  SidebarNav,
1911
2687
  Skeleton,
2688
+ Sparkline,
1912
2689
  StatusBadge,
1913
2690
  Switch,
1914
2691
  Table,
@@ -1934,6 +2711,7 @@ export {
1934
2711
  cn,
1935
2712
  loadingSpinnerIconVariants,
1936
2713
  sheetVariants,
2714
+ useMediaQuery,
1937
2715
  useSidebarCollapsed
1938
2716
  };
1939
2717
  //# sourceMappingURL=index.js.map