@bmsuisse/ui 0.8.0 → 0.11.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,7 +641,7 @@ 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: {
@@ -656,17 +656,84 @@ var sheetVariants = cva3(
656
656
  }
657
657
  }
658
658
  );
659
+ var enterFromTransform = {
660
+ top: "translateY(-100%)",
661
+ bottom: "translateY(100%)",
662
+ left: "translateX(-100%)",
663
+ right: "translateX(100%)"
664
+ };
659
665
  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
- ] })
666
+ ({ side = "right", className, children, resizable = false, style: styleProp, ...props }, ref) => {
667
+ const [entered, setEntered] = useState(false);
668
+ useEffect(() => {
669
+ const id = requestAnimationFrame(() => setEntered(true));
670
+ return () => cancelAnimationFrame(id);
671
+ }, []);
672
+ const [dragHeight, setDragHeight] = useState(null);
673
+ const [isDragging, setIsDragging] = useState(false);
674
+ const dragStart = useRef(null);
675
+ const canResize = resizable && side === "bottom";
676
+ const onHandlePointerDown = (e) => {
677
+ const popup = e.currentTarget.closest('[data-slot="sheet-content"]');
678
+ if (!(popup instanceof HTMLElement)) return;
679
+ e.currentTarget.setPointerCapture(e.pointerId);
680
+ dragStart.current = { y: e.clientY, height: popup.getBoundingClientRect().height };
681
+ setIsDragging(true);
682
+ };
683
+ const onHandlePointerMove = (e) => {
684
+ if (!dragStart.current) return;
685
+ const delta = dragStart.current.y - e.clientY;
686
+ const next = dragStart.current.height + delta;
687
+ const min = window.innerHeight * 0.3;
688
+ const max = window.innerHeight * 0.95;
689
+ setDragHeight(Math.min(max, Math.max(min, next)));
690
+ };
691
+ const onHandlePointerUp = () => {
692
+ dragStart.current = null;
693
+ setIsDragging(false);
694
+ };
695
+ const style = entered ? { ...styleProp, ...canResize && dragHeight != null ? { height: dragHeight, maxHeight: dragHeight } : null } : { ...styleProp, transform: enterFromTransform[side ?? "right"] };
696
+ return /* @__PURE__ */ jsxs5(SheetPortal, { children: [
697
+ /* @__PURE__ */ jsx18(SheetOverlay, {}),
698
+ /* @__PURE__ */ jsxs5(
699
+ DialogPrimitive2.Content,
700
+ {
701
+ ref,
702
+ "data-slot": "sheet-content",
703
+ style,
704
+ className: cn(sheetVariants({ side }), isDragging && "shadow-2xl", className),
705
+ ...props,
706
+ children: [
707
+ canResize && /* @__PURE__ */ jsx18(
708
+ "div",
709
+ {
710
+ "data-testid": "sheet-drag-handle",
711
+ className: "group -mb-2 flex shrink-0 cursor-grab touch-none justify-center py-2 active:cursor-grabbing",
712
+ onPointerDown: onHandlePointerDown,
713
+ onPointerMove: onHandlePointerMove,
714
+ onPointerUp: onHandlePointerUp,
715
+ onPointerCancel: onHandlePointerUp,
716
+ children: /* @__PURE__ */ jsx18(
717
+ "div",
718
+ {
719
+ className: cn(
720
+ "h-1 w-10 rounded-full bg-muted-foreground/30 transition-all duration-150 group-hover:w-14 group-hover:bg-muted-foreground/50",
721
+ isDragging && "w-14 bg-primary/60"
722
+ )
723
+ }
724
+ )
725
+ }
726
+ ),
727
+ children,
728
+ /* @__PURE__ */ jsxs5(DialogPrimitive2.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100", children: [
729
+ /* @__PURE__ */ jsx18(X2, { className: "h-4 w-4" }),
730
+ /* @__PURE__ */ jsx18("span", { className: "sr-only", children: "Close" })
731
+ ] })
732
+ ]
733
+ }
734
+ )
735
+ ] });
736
+ }
670
737
  );
671
738
  SheetContent.displayName = "SheetContent";
672
739
  var SheetHeader = ({
@@ -730,7 +797,7 @@ var Modal = ({
730
797
  ] }) });
731
798
 
732
799
  // src/patterns/modal/ConfirmDialog.tsx
733
- import { useState } from "react";
800
+ import { useState as useState2 } from "react";
734
801
  import { Fragment, jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
735
802
  var ConfirmDialog = ({
736
803
  open,
@@ -744,7 +811,7 @@ var ConfirmDialog = ({
744
811
  confirmTestId,
745
812
  cancelTestId
746
813
  }) => {
747
- const [pending, setPending] = useState(false);
814
+ const [pending, setPending] = useState2(false);
748
815
  const handleCancel = () => {
749
816
  onOpenChange(false);
750
817
  };
@@ -785,7 +852,7 @@ var ConfirmDialog = ({
785
852
  };
786
853
 
787
854
  // src/patterns/modal/FormModal.tsx
788
- import { useState as useState2 } from "react";
855
+ import { useState as useState3 } from "react";
789
856
  import { jsx as jsx22, jsxs as jsxs8 } from "react/jsx-runtime";
790
857
  var FormModal = ({
791
858
  open,
@@ -801,7 +868,7 @@ var FormModal = ({
801
868
  submitTestId,
802
869
  cancelTestId
803
870
  }) => {
804
- const [pending, setPending] = useState2(false);
871
+ const [pending, setPending] = useState3(false);
805
872
  const handleSubmit = async (event) => {
806
873
  event.preventDefault();
807
874
  setPending(true);
@@ -837,9 +904,236 @@ var FormModal = ({
837
904
  ] }) }) });
838
905
  };
839
906
 
907
+ // src/patterns/modal/ResponsivePanel.tsx
908
+ import { useRef as useRef2, useState as useState5 } from "react";
909
+
910
+ // src/lib/useMediaQuery.ts
911
+ import { useEffect as useEffect2, useState as useState4 } from "react";
912
+ function useMediaQuery(query) {
913
+ const [matches, setMatches] = useState4(
914
+ () => typeof window !== "undefined" ? window.matchMedia(query).matches : false
915
+ );
916
+ useEffect2(() => {
917
+ const mq = window.matchMedia(query);
918
+ setMatches(mq.matches);
919
+ const handler = (e) => setMatches(e.matches);
920
+ mq.addEventListener("change", handler);
921
+ return () => mq.removeEventListener("change", handler);
922
+ }, [query]);
923
+ return matches;
924
+ }
925
+
926
+ // src/patterns/modal/ResponsivePanel.tsx
927
+ import { jsx as jsx23, jsxs as jsxs9 } from "react/jsx-runtime";
928
+ var desktopSizeClasses = {
929
+ sm: "max-w-md",
930
+ md: "max-w-xl",
931
+ lg: "max-w-2xl",
932
+ xl: "max-w-4xl"
933
+ };
934
+ var drawerSizeClasses = {
935
+ sm: "max-h-[50vh]",
936
+ md: "max-h-[70vh]",
937
+ lg: "max-h-[90vh]",
938
+ xl: "max-h-[96vh]"
939
+ };
940
+ var MIN_PANEL_WIDTH = 320;
941
+ var MIN_PANEL_HEIGHT = 240;
942
+ var VIEWPORT_MARGIN = 16;
943
+ var cornerCursor = {
944
+ "top-left": "cursor-nwse-resize",
945
+ "bottom-right": "cursor-nwse-resize",
946
+ "top-right": "cursor-nesw-resize",
947
+ "bottom-left": "cursor-nesw-resize"
948
+ };
949
+ var cornerPosition = {
950
+ "top-left": "left-0 top-0",
951
+ "top-right": "right-0 top-0",
952
+ "bottom-left": "left-0 bottom-0",
953
+ "bottom-right": "right-0 bottom-0"
954
+ };
955
+ var cornerGripPosition = {
956
+ "top-left": "left-1 top-1 border-l-2 border-t-2",
957
+ "top-right": "right-1 top-1 border-r-2 border-t-2",
958
+ "bottom-left": "left-1 bottom-1 border-l-2 border-b-2",
959
+ "bottom-right": "right-1 bottom-1 border-r-2 border-b-2"
960
+ };
961
+ function useDesktopPanelGeometry() {
962
+ const [style, setStyle] = useState5(void 0);
963
+ const [isDragging, setIsDragging] = useState5(false);
964
+ const drag = useRef2(null);
965
+ const lastRect = useRef2(null);
966
+ const beginDrag = (mode, corner) => (e) => {
967
+ const content = e.currentTarget.closest('[data-slot="dialog-content"]');
968
+ if (!(content instanceof HTMLElement)) return;
969
+ e.currentTarget.setPointerCapture(e.pointerId);
970
+ const domRect = content.getBoundingClientRect();
971
+ const rect = lastRect.current ?? {
972
+ left: domRect.left,
973
+ top: domRect.top,
974
+ width: domRect.width,
975
+ height: domRect.height
976
+ };
977
+ drag.current = { mode, corner, x: e.clientX, y: e.clientY, rect };
978
+ setIsDragging(true);
979
+ };
980
+ const onPointerMove = (e) => {
981
+ const state = drag.current;
982
+ if (!state) return;
983
+ const deltaX = e.clientX - state.x;
984
+ const deltaY = e.clientY - state.y;
985
+ if (state.mode === "move") {
986
+ const maxLeft = window.innerWidth - VIEWPORT_MARGIN - state.rect.width;
987
+ const maxTop = window.innerHeight - VIEWPORT_MARGIN - state.rect.height;
988
+ const next2 = {
989
+ left: Math.min(maxLeft, Math.max(VIEWPORT_MARGIN, state.rect.left + deltaX)),
990
+ top: Math.min(maxTop, Math.max(VIEWPORT_MARGIN, state.rect.top + deltaY)),
991
+ width: state.rect.width,
992
+ height: state.rect.height
993
+ };
994
+ lastRect.current = next2;
995
+ setStyle({ position: "fixed", transform: "none", translate: "none", maxWidth: "none", maxHeight: "none", ...next2 });
996
+ return;
997
+ }
998
+ const corner = state.corner ?? "top-left";
999
+ const growsLeft = corner === "top-left" || corner === "bottom-left";
1000
+ const growsUp = corner === "top-left" || corner === "top-right";
1001
+ const right = state.rect.left + state.rect.width;
1002
+ const bottom = state.rect.top + state.rect.height;
1003
+ const maxWidth = window.innerWidth - VIEWPORT_MARGIN * 2;
1004
+ const maxHeight = window.innerHeight - VIEWPORT_MARGIN * 2;
1005
+ let width = Math.max(
1006
+ MIN_PANEL_WIDTH,
1007
+ Math.min(maxWidth, growsLeft ? state.rect.width - deltaX : state.rect.width + deltaX)
1008
+ );
1009
+ let height = Math.max(
1010
+ MIN_PANEL_HEIGHT,
1011
+ Math.min(maxHeight, growsUp ? state.rect.height - deltaY : state.rect.height + deltaY)
1012
+ );
1013
+ const left = growsLeft ? right - Math.min(width, right - VIEWPORT_MARGIN) : state.rect.left;
1014
+ width = growsLeft ? right - left : Math.min(width, window.innerWidth - VIEWPORT_MARGIN - state.rect.left);
1015
+ const top = growsUp ? bottom - Math.min(height, bottom - VIEWPORT_MARGIN) : state.rect.top;
1016
+ height = growsUp ? bottom - top : Math.min(height, window.innerHeight - VIEWPORT_MARGIN - state.rect.top);
1017
+ const next = { left, top, width, height };
1018
+ lastRect.current = next;
1019
+ setStyle({ position: "fixed", transform: "none", translate: "none", maxWidth: "none", maxHeight: "none", ...next });
1020
+ };
1021
+ const onPointerUp = () => {
1022
+ drag.current = null;
1023
+ setIsDragging(false);
1024
+ };
1025
+ return {
1026
+ style,
1027
+ isDragging,
1028
+ startMove: beginDrag("move"),
1029
+ startResize: (corner) => beginDrag("resize", corner),
1030
+ onPointerMove,
1031
+ onPointerUp
1032
+ };
1033
+ }
1034
+ var ResponsivePanel = ({
1035
+ open,
1036
+ onOpenChange,
1037
+ title,
1038
+ description,
1039
+ children,
1040
+ footer,
1041
+ className,
1042
+ breakpoint = "(min-width: 1024px)",
1043
+ size = "lg",
1044
+ resizable = false,
1045
+ draggable = false,
1046
+ closeOnOutsideClick = true
1047
+ }) => {
1048
+ const isDesktop = useMediaQuery(breakpoint);
1049
+ const geometry = useDesktopPanelGeometry();
1050
+ const onInteractOutside = closeOnOutsideClick ? void 0 : (e) => e.preventDefault();
1051
+ if (isDesktop) {
1052
+ const corners = ["top-left", "top-right", "bottom-left", "bottom-right"];
1053
+ return /* @__PURE__ */ jsx23(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs9(
1054
+ DialogContent,
1055
+ {
1056
+ "data-slot": "dialog-content",
1057
+ onInteractOutside,
1058
+ style: resizable || draggable ? geometry.style : void 0,
1059
+ className: cn(
1060
+ "max-h-[85vh] overflow-y-auto transition-shadow duration-150 ease-out",
1061
+ geometry.isDragging && "shadow-2xl ring-2 ring-primary/30",
1062
+ desktopSizeClasses[size],
1063
+ className
1064
+ ),
1065
+ children: [
1066
+ resizable && corners.map((corner) => /* @__PURE__ */ jsx23(
1067
+ "div",
1068
+ {
1069
+ "data-testid": `panel-resize-handle-${corner}`,
1070
+ className: cn(
1071
+ "group absolute h-4 w-4 touch-none",
1072
+ cornerPosition[corner],
1073
+ cornerCursor[corner]
1074
+ ),
1075
+ onPointerDown: geometry.startResize(corner),
1076
+ onPointerMove: geometry.onPointerMove,
1077
+ onPointerUp: geometry.onPointerUp,
1078
+ onPointerCancel: geometry.onPointerUp,
1079
+ children: /* @__PURE__ */ jsx23(
1080
+ "div",
1081
+ {
1082
+ className: cn(
1083
+ "absolute h-2 w-2 scale-100 border-muted-foreground/40 transition-transform duration-150 group-hover:scale-125 group-hover:border-primary/60",
1084
+ cornerGripPosition[corner]
1085
+ )
1086
+ }
1087
+ )
1088
+ },
1089
+ corner
1090
+ )),
1091
+ /* @__PURE__ */ jsxs9(
1092
+ DialogHeader,
1093
+ {
1094
+ className: cn(draggable && "touch-none cursor-move select-none"),
1095
+ onPointerDown: draggable ? geometry.startMove : void 0,
1096
+ onPointerMove: draggable ? geometry.onPointerMove : void 0,
1097
+ onPointerUp: draggable ? geometry.onPointerUp : void 0,
1098
+ onPointerCancel: draggable ? geometry.onPointerUp : void 0,
1099
+ children: [
1100
+ /* @__PURE__ */ jsx23(DialogTitle, { children: title }),
1101
+ description ? /* @__PURE__ */ jsx23(DialogDescription, { children: description }) : null
1102
+ ]
1103
+ }
1104
+ ),
1105
+ children,
1106
+ footer ? /* @__PURE__ */ jsx23(DialogFooter, { children: footer }) : null
1107
+ ]
1108
+ }
1109
+ ) });
1110
+ }
1111
+ return /* @__PURE__ */ jsx23(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs9(
1112
+ SheetContent,
1113
+ {
1114
+ side: "bottom",
1115
+ resizable,
1116
+ onInteractOutside,
1117
+ className: cn(
1118
+ "flex flex-col overflow-y-auto rounded-t-2xl",
1119
+ drawerSizeClasses[size],
1120
+ className
1121
+ ),
1122
+ children: [
1123
+ /* @__PURE__ */ jsxs9(SheetHeader, { children: [
1124
+ /* @__PURE__ */ jsx23(SheetTitle, { children: title }),
1125
+ description ? /* @__PURE__ */ jsx23(SheetDescription, { children: description }) : null
1126
+ ] }),
1127
+ children,
1128
+ footer ? /* @__PURE__ */ jsx23(SheetFooter, { children: footer }) : null
1129
+ ]
1130
+ }
1131
+ ) });
1132
+ };
1133
+
840
1134
  // src/patterns/form-field/FormField.tsx
841
1135
  import { cloneElement, isValidElement, useId } from "react";
842
- import { jsx as jsx23, jsxs as jsxs9 } from "react/jsx-runtime";
1136
+ import { jsx as jsx24, jsxs as jsxs10 } from "react/jsx-runtime";
843
1137
  function FormField({
844
1138
  label,
845
1139
  htmlFor,
@@ -864,22 +1158,22 @@ function FormField({
864
1158
  ...messageId ? { "aria-describedby": messageId } : {}
865
1159
  }
866
1160
  ) : children;
867
- return /* @__PURE__ */ jsxs9("div", { className: cn("flex flex-col gap-1.5", className), children: [
868
- /* @__PURE__ */ jsxs9(Label, { htmlFor: effectiveId, children: [
1161
+ return /* @__PURE__ */ jsxs10("div", { className: cn("flex flex-col gap-1.5", className), children: [
1162
+ /* @__PURE__ */ jsxs10(Label, { htmlFor: effectiveId, children: [
869
1163
  label,
870
- required ? /* @__PURE__ */ jsxs9("span", { className: "text-destructive", "aria-hidden": "true", children: [
1164
+ required ? /* @__PURE__ */ jsxs10("span", { className: "text-destructive", "aria-hidden": "true", children: [
871
1165
  " ",
872
1166
  "*"
873
1167
  ] }) : null
874
1168
  ] }),
875
1169
  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
1170
+ 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
1171
  ] });
878
1172
  }
879
1173
 
880
1174
  // src/patterns/combobox/Combobox.tsx
881
1175
  import { Check as Check4, ChevronsUpDown, X as X3 } from "lucide-react";
882
- import { useEffect, useMemo, useRef, useState as useState3 } from "react";
1176
+ import { useEffect as useEffect3, useMemo, useRef as useRef3, useState as useState6 } from "react";
883
1177
 
884
1178
  // src/lib/optionGrouping.ts
885
1179
  function groupMembers(options, group) {
@@ -908,7 +1202,7 @@ function buildRenderChunks(visibleOptions) {
908
1202
  }
909
1203
 
910
1204
  // src/patterns/combobox/Combobox.tsx
911
- import { jsx as jsx24, jsxs as jsxs10 } from "react/jsx-runtime";
1205
+ import { jsx as jsx25, jsxs as jsxs11 } from "react/jsx-runtime";
912
1206
  function resolveGroupTriggerLabel(options, selectedValues, groupLabel) {
913
1207
  const selectedSet = new Set(selectedValues);
914
1208
  const groupsPresent = Array.from(
@@ -946,10 +1240,10 @@ function Combobox(props) {
946
1240
  selectedLabel
947
1241
  } = props;
948
1242
  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);
1243
+ const [open, setOpen] = useState6(false);
1244
+ const [search, setSearch] = useState6("");
1245
+ const [activeIndex, setActiveIndex] = useState6(0);
1246
+ const inputRef = useRef3(null);
953
1247
  const selectedValues = useMemo(
954
1248
  () => props.multiple ? props.value : props.value ? [props.value] : [],
955
1249
  [props.multiple, props.value]
@@ -964,7 +1258,7 @@ function Combobox(props) {
964
1258
  if (!term) return options;
965
1259
  return options.filter((option) => option.label.toLowerCase().includes(term));
966
1260
  }, [options, search, onSearchChange]);
967
- useEffect(() => {
1261
+ useEffect3(() => {
968
1262
  if (!open) return;
969
1263
  setSearch("");
970
1264
  onSearchChange?.("");
@@ -973,7 +1267,7 @@ function Combobox(props) {
973
1267
  setActiveIndex(selectedIdx >= 0 ? selectedIdx : 0);
974
1268
  inputRef.current?.focus();
975
1269
  }, [open]);
976
- useEffect(() => {
1270
+ useEffect3(() => {
977
1271
  setActiveIndex((i) => Math.min(i, Math.max(visibleOptions.length - 1, 0)));
978
1272
  }, [visibleOptions.length]);
979
1273
  function selectOption(option) {
@@ -1011,7 +1305,7 @@ function Combobox(props) {
1011
1305
  function renderOption({ option, index }) {
1012
1306
  const isSelected = selectedValues.includes(option.value);
1013
1307
  const isActive = index === activeIndex;
1014
- return /* @__PURE__ */ jsxs10(
1308
+ return /* @__PURE__ */ jsxs11(
1015
1309
  "button",
1016
1310
  {
1017
1311
  type: "button",
@@ -1027,7 +1321,7 @@ function Combobox(props) {
1027
1321
  isActive && "bg-accent text-accent-foreground"
1028
1322
  ),
1029
1323
  children: [
1030
- props.multiple ? /* @__PURE__ */ jsx24(
1324
+ props.multiple ? /* @__PURE__ */ jsx25(
1031
1325
  "input",
1032
1326
  {
1033
1327
  type: "checkbox",
@@ -1036,15 +1330,15 @@ function Combobox(props) {
1036
1330
  tabIndex: -1,
1037
1331
  className: "pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary"
1038
1332
  }
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 })
1333
+ ) : /* @__PURE__ */ jsx25(Check4, { className: cn("h-4 w-4 shrink-0", isSelected ? "opacity-100" : "opacity-0") }),
1334
+ /* @__PURE__ */ jsx25("span", { className: "truncate", children: option.label })
1041
1335
  ]
1042
1336
  },
1043
1337
  option.value
1044
1338
  );
1045
1339
  }
1046
- return /* @__PURE__ */ jsxs10(Popover, { open, onOpenChange: setOpen, children: [
1047
- /* @__PURE__ */ jsx24(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs10(
1340
+ return /* @__PURE__ */ jsxs11(Popover, { open, onOpenChange: setOpen, children: [
1341
+ /* @__PURE__ */ jsx25(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs11(
1048
1342
  Button,
1049
1343
  {
1050
1344
  id,
@@ -1060,9 +1354,9 @@ function Combobox(props) {
1060
1354
  className
1061
1355
  ),
1062
1356
  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(
1357
+ /* @__PURE__ */ jsx25("span", { className: "truncate", children: triggerLabel }),
1358
+ /* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-1", children: [
1359
+ clearable && !loading && selectedValues.length > 0 ? /* @__PURE__ */ jsx25(
1066
1360
  "span",
1067
1361
  {
1068
1362
  role: "button",
@@ -1077,23 +1371,23 @@ function Combobox(props) {
1077
1371
  props.onChange(null);
1078
1372
  }
1079
1373
  },
1080
- children: /* @__PURE__ */ jsx24(X3, { className: "h-3.5 w-3.5" })
1374
+ children: /* @__PURE__ */ jsx25(X3, { className: "h-3.5 w-3.5" })
1081
1375
  }
1082
1376
  ) : null,
1083
- /* @__PURE__ */ jsx24(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50", "aria-hidden": "true" })
1377
+ /* @__PURE__ */ jsx25(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50", "aria-hidden": "true" })
1084
1378
  ] })
1085
1379
  ]
1086
1380
  }
1087
1381
  ) }),
1088
- /* @__PURE__ */ jsx24(
1382
+ /* @__PURE__ */ jsx25(
1089
1383
  PopoverContent,
1090
1384
  {
1091
1385
  align: "start",
1092
1386
  container,
1093
1387
  className: "w-[var(--radix-popover-trigger-width)] min-w-[10rem] p-2",
1094
1388
  onOpenAutoFocus: (event) => event.preventDefault(),
1095
- children: /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-2", children: [
1096
- /* @__PURE__ */ jsx24(
1389
+ children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-2", children: [
1390
+ /* @__PURE__ */ jsx25(
1097
1391
  Input,
1098
1392
  {
1099
1393
  ref: inputRef,
@@ -1107,7 +1401,7 @@ function Combobox(props) {
1107
1401
  "aria-label": searchPlaceholder
1108
1402
  }
1109
1403
  ),
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) => {
1404
+ /* @__PURE__ */ jsx25("div", { role: "listbox", className: "flex max-h-60 flex-col gap-0.5 overflow-y-auto", children: renderChunks.length === 0 ? /* @__PURE__ */ jsx25("p", { className: "py-2 text-center text-sm text-muted-foreground", children: emptyMessage }) : renderChunks.map((chunk) => {
1111
1405
  if (chunk.kind === "single") return renderOption(chunk.row);
1112
1406
  const headerState = groupCheckState(options, selectedValues, chunk.group);
1113
1407
  return (
@@ -1118,14 +1412,14 @@ function Combobox(props) {
1118
1412
  // lives on this wrapper's `pt-1`, not on the header itself -- a margin on
1119
1413
  // the sticky element would travel with it once stuck, leaving a gap at the
1120
1414
  // 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(
1415
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-0.5 pt-1 first:pt-0", children: [
1416
+ /* @__PURE__ */ jsxs11(
1123
1417
  "div",
1124
1418
  {
1125
1419
  "data-group-header": true,
1126
1420
  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
1421
  children: [
1128
- props.multiple ? /* @__PURE__ */ jsx24(
1422
+ props.multiple ? /* @__PURE__ */ jsx25(
1129
1423
  "input",
1130
1424
  {
1131
1425
  type: "checkbox",
@@ -1139,7 +1433,7 @@ function Combobox(props) {
1139
1433
  "aria-label": `Select all of ${groupLabel(chunk.group)}`
1140
1434
  }
1141
1435
  ) : null,
1142
- /* @__PURE__ */ jsx24("span", { className: "truncate", children: groupLabel(chunk.group) })
1436
+ /* @__PURE__ */ jsx25("span", { className: "truncate", children: groupLabel(chunk.group) })
1143
1437
  ]
1144
1438
  }
1145
1439
  ),
@@ -1155,8 +1449,8 @@ function Combobox(props) {
1155
1449
 
1156
1450
  // src/patterns/tag-combobox/TagCombobox.tsx
1157
1451
  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";
1452
+ import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState7 } from "react";
1453
+ import { jsx as jsx26, jsxs as jsxs12 } from "react/jsx-runtime";
1160
1454
  function TagCombobox({
1161
1455
  options,
1162
1456
  value,
@@ -1174,11 +1468,11 @@ function TagCombobox({
1174
1468
  ...rest
1175
1469
  }) {
1176
1470
  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);
1471
+ const [open, setOpen] = useState7(false);
1472
+ const [search, setSearch] = useState7("");
1473
+ const [activeIndex, setActiveIndex] = useState7(0);
1474
+ const inputRef = useRef4(null);
1475
+ const fieldRef = useRef4(null);
1182
1476
  const selectedOptions = useMemo2(
1183
1477
  () => value.map((v) => options.find((o) => o.value === v) ?? { value: v, label: v }),
1184
1478
  [options, value]
@@ -1189,11 +1483,11 @@ function TagCombobox({
1189
1483
  if (!term) return options;
1190
1484
  return options.filter((option) => option.label.toLowerCase().includes(term));
1191
1485
  }, [options, search, onSearchChange]);
1192
- useEffect2(() => {
1486
+ useEffect4(() => {
1193
1487
  setActiveIndex((i) => Math.min(Math.max(i, 0), Math.max(visibleOptions.length - 1, 0)));
1194
1488
  }, [visibleOptions.length]);
1195
1489
  const renderChunks = useMemo2(() => buildRenderChunks(visibleOptions), [visibleOptions]);
1196
- useEffect2(() => {
1490
+ useEffect4(() => {
1197
1491
  if (!open) return;
1198
1492
  setSearch("");
1199
1493
  onSearchChange?.("");
@@ -1246,7 +1540,7 @@ function TagCombobox({
1246
1540
  function renderOption({ option, index }) {
1247
1541
  const isSelected = value.includes(option.value);
1248
1542
  const isActive = index === activeIndex;
1249
- return /* @__PURE__ */ jsxs11(
1543
+ return /* @__PURE__ */ jsxs12(
1250
1544
  "button",
1251
1545
  {
1252
1546
  type: "button",
@@ -1262,7 +1556,7 @@ function TagCombobox({
1262
1556
  isActive && "bg-accent text-accent-foreground"
1263
1557
  ),
1264
1558
  children: [
1265
- /* @__PURE__ */ jsx25(
1559
+ /* @__PURE__ */ jsx26(
1266
1560
  "input",
1267
1561
  {
1268
1562
  type: "checkbox",
@@ -1272,14 +1566,14 @@ function TagCombobox({
1272
1566
  className: "pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary"
1273
1567
  }
1274
1568
  ),
1275
- /* @__PURE__ */ jsx25("span", { className: "truncate", children: option.label })
1569
+ /* @__PURE__ */ jsx26("span", { className: "truncate", children: option.label })
1276
1570
  ]
1277
1571
  },
1278
1572
  option.value
1279
1573
  );
1280
1574
  }
1281
- return /* @__PURE__ */ jsxs11(Popover, { open, onOpenChange: setOpen, children: [
1282
- /* @__PURE__ */ jsx25(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs11(
1575
+ return /* @__PURE__ */ jsxs12(Popover, { open, onOpenChange: setOpen, children: [
1576
+ /* @__PURE__ */ jsx26(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs12(
1283
1577
  "div",
1284
1578
  {
1285
1579
  ref: fieldRef,
@@ -1297,13 +1591,13 @@ function TagCombobox({
1297
1591
  if (!disabled) inputRef.current?.focus();
1298
1592
  },
1299
1593
  children: [
1300
- selectedOptions.map((option) => /* @__PURE__ */ jsxs11(
1594
+ selectedOptions.map((option) => /* @__PURE__ */ jsxs12(
1301
1595
  "span",
1302
1596
  {
1303
1597
  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
1598
  children: [
1305
- /* @__PURE__ */ jsx25("span", { className: "max-w-48 truncate", children: option.label }),
1306
- !disabled && /* @__PURE__ */ jsx25(
1599
+ /* @__PURE__ */ jsx26("span", { className: "max-w-48 truncate", children: option.label }),
1600
+ !disabled && /* @__PURE__ */ jsx26(
1307
1601
  "button",
1308
1602
  {
1309
1603
  type: "button",
@@ -1313,14 +1607,14 @@ function TagCombobox({
1313
1607
  event.stopPropagation();
1314
1608
  removeValue(option.value);
1315
1609
  },
1316
- children: /* @__PURE__ */ jsx25(X4, { className: "h-3 w-3" })
1610
+ children: /* @__PURE__ */ jsx26(X4, { className: "h-3 w-3" })
1317
1611
  }
1318
1612
  )
1319
1613
  ]
1320
1614
  },
1321
1615
  option.value
1322
1616
  )),
1323
- /* @__PURE__ */ jsx25(
1617
+ /* @__PURE__ */ jsx26(
1324
1618
  "input",
1325
1619
  {
1326
1620
  ref: inputRef,
@@ -1338,7 +1632,7 @@ function TagCombobox({
1338
1632
  ]
1339
1633
  }
1340
1634
  ) }),
1341
- /* @__PURE__ */ jsx25(
1635
+ /* @__PURE__ */ jsx26(
1342
1636
  PopoverContent,
1343
1637
  {
1344
1638
  align: "start",
@@ -1349,7 +1643,7 @@ function TagCombobox({
1349
1643
  onInteractOutside: (event) => {
1350
1644
  if (fieldRef.current?.contains(event.target)) event.preventDefault();
1351
1645
  },
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) => {
1646
+ children: /* @__PURE__ */ jsx26("div", { role: "listbox", className: "flex max-h-60 flex-col gap-0.5 overflow-y-auto", children: loading ? /* @__PURE__ */ jsx26("p", { className: "py-2 text-center text-sm text-muted-foreground", children: loadingMessage }) : renderChunks.length === 0 ? /* @__PURE__ */ jsx26("p", { className: "py-2 text-center text-sm text-muted-foreground", children: emptyMessage }) : renderChunks.map((chunk) => {
1353
1647
  if (chunk.kind === "single") return renderOption(chunk.row);
1354
1648
  const headerState = groupCheckState(options, value, chunk.group);
1355
1649
  return (
@@ -1359,14 +1653,14 @@ function TagCombobox({
1359
1653
  // past its first row. Spacing above a group lives on this wrapper's
1360
1654
  // `pt-1`/`first:pt-0`, not on the header itself -- see `Combobox`'s own
1361
1655
  // 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(
1656
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-0.5 pt-1 first:pt-0", children: [
1657
+ /* @__PURE__ */ jsxs12(
1364
1658
  "div",
1365
1659
  {
1366
1660
  "data-group-header": true,
1367
1661
  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
1662
  children: [
1369
- /* @__PURE__ */ jsx25(
1663
+ /* @__PURE__ */ jsx26(
1370
1664
  "input",
1371
1665
  {
1372
1666
  type: "checkbox",
@@ -1380,7 +1674,7 @@ function TagCombobox({
1380
1674
  "aria-label": `Select all of ${groupLabel(chunk.group)}`
1381
1675
  }
1382
1676
  ),
1383
- /* @__PURE__ */ jsx25("span", { className: "truncate", children: groupLabel(chunk.group) })
1677
+ /* @__PURE__ */ jsx26("span", { className: "truncate", children: groupLabel(chunk.group) })
1384
1678
  ]
1385
1679
  }
1386
1680
  ),
@@ -1395,7 +1689,7 @@ function TagCombobox({
1395
1689
 
1396
1690
  // src/patterns/alert-box/AlertBox.tsx
1397
1691
  import { AlertCircle, AlertTriangle, CheckCircle2, Info } from "lucide-react";
1398
- import { jsx as jsx26, jsxs as jsxs12 } from "react/jsx-runtime";
1692
+ import { jsx as jsx27, jsxs as jsxs13 } from "react/jsx-runtime";
1399
1693
  var variantStyles = {
1400
1694
  error: "border-destructive bg-destructive/10 text-destructive",
1401
1695
  warning: "border-amber-500 bg-amber-500/10 text-amber-700 dark:text-amber-300",
@@ -1403,24 +1697,24 @@ var variantStyles = {
1403
1697
  success: "border-emerald-500 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"
1404
1698
  };
1405
1699
  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" })
1700
+ error: /* @__PURE__ */ jsx27(AlertCircle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
1701
+ warning: /* @__PURE__ */ jsx27(AlertTriangle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
1702
+ info: /* @__PURE__ */ jsx27(Info, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
1703
+ success: /* @__PURE__ */ jsx27(CheckCircle2, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" })
1410
1704
  };
1411
1705
  var AlertBox = ({ variant, title, children, className, icon }) => {
1412
1706
  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 })
1707
+ return /* @__PURE__ */ jsx27("div", { className: cn("rounded-md border p-3 text-sm", variantStyles[variant], className), children: /* @__PURE__ */ jsxs13("div", { className: "flex flex-row items-start gap-2", children: [
1708
+ resolvedIcon != null && /* @__PURE__ */ jsx27("span", { className: "mt-0.5 shrink-0", children: resolvedIcon }),
1709
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-1", children: [
1710
+ title && /* @__PURE__ */ jsx27("p", { className: "font-bold", children: title }),
1711
+ /* @__PURE__ */ jsx27("div", { children })
1418
1712
  ] })
1419
1713
  ] }) });
1420
1714
  };
1421
1715
 
1422
1716
  // src/patterns/status-badge/StatusBadge.tsx
1423
- import { jsx as jsx27 } from "react/jsx-runtime";
1717
+ import { jsx as jsx28 } from "react/jsx-runtime";
1424
1718
  var TONE_CLASSES = {
1425
1719
  success: "border-transparent bg-emerald-500/15 text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-300",
1426
1720
  warning: "border-transparent bg-amber-500/15 text-amber-700 dark:bg-amber-500/20 dark:text-amber-300",
@@ -1467,11 +1761,11 @@ function resolveTone(status, tone, toneMap) {
1467
1761
  var StatusBadge = ({ status, label, tone, toneMap, className, ...props }) => {
1468
1762
  const resolvedTone = resolveTone(status, tone, toneMap);
1469
1763
  const displayLabel = label ?? deriveLabel(status);
1470
- return /* @__PURE__ */ jsx27(Badge, { variant: "outline", className: cn(TONE_CLASSES[resolvedTone], className), ...props, children: displayLabel });
1764
+ return /* @__PURE__ */ jsx28(Badge, { variant: "outline", className: cn(TONE_CLASSES[resolvedTone], className), ...props, children: displayLabel });
1471
1765
  };
1472
1766
 
1473
1767
  // src/patterns/button-group/ButtonGroup.tsx
1474
- import { jsx as jsx28, jsxs as jsxs13 } from "react/jsx-runtime";
1768
+ import { jsx as jsx29, jsxs as jsxs14 } from "react/jsx-runtime";
1475
1769
  function ButtonGroup({
1476
1770
  options,
1477
1771
  value,
@@ -1481,10 +1775,10 @@ function ButtonGroup({
1481
1775
  className,
1482
1776
  ...props
1483
1777
  }) {
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) => {
1778
+ return /* @__PURE__ */ jsx29("div", { role: "group", "aria-label": props["aria-label"], className: cn("inline-flex", className), "data-testid": props["data-testid"], children: options.map((option, index) => {
1485
1779
  const selected = option.value === value;
1486
1780
  const Icon2 = option.icon;
1487
- return /* @__PURE__ */ jsxs13(
1781
+ return /* @__PURE__ */ jsxs14(
1488
1782
  Button,
1489
1783
  {
1490
1784
  type: "button",
@@ -1502,7 +1796,7 @@ function ButtonGroup({
1502
1796
  index > 0 && "-ml-px"
1503
1797
  ),
1504
1798
  children: [
1505
- Icon2 && /* @__PURE__ */ jsx28(Icon2, { className: "h-4 w-4" }),
1799
+ Icon2 && /* @__PURE__ */ jsx29(Icon2, { className: "h-4 w-4" }),
1506
1800
  option.label
1507
1801
  ]
1508
1802
  },
@@ -1514,7 +1808,7 @@ function ButtonGroup({
1514
1808
  // src/patterns/loading-spinner/LoadingSpinner.tsx
1515
1809
  import { cva as cva4 } from "class-variance-authority";
1516
1810
  import { Loader2 } from "lucide-react";
1517
- import { jsx as jsx29, jsxs as jsxs14 } from "react/jsx-runtime";
1811
+ import { jsx as jsx30, jsxs as jsxs15 } from "react/jsx-runtime";
1518
1812
  var loadingSpinnerIconVariants = cva4("animate-spin text-muted-foreground", {
1519
1813
  variants: {
1520
1814
  size: {
@@ -1532,27 +1826,27 @@ var LoadingSpinner = ({
1532
1826
  label,
1533
1827
  className,
1534
1828
  ...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
1829
+ }) => /* @__PURE__ */ jsxs15("span", { role: "status", className: cn("inline-flex items-center gap-2", className), ...props, children: [
1830
+ /* @__PURE__ */ jsx30(Loader2, { className: cn(loadingSpinnerIconVariants({ size })), "aria-hidden": "true" }),
1831
+ label ? /* @__PURE__ */ jsx30("span", { children: label }) : null
1538
1832
  ] });
1539
1833
  var LoadingOverlay = ({
1540
1834
  size = "lg",
1541
1835
  label,
1542
1836
  className,
1543
1837
  ...props
1544
- }) => /* @__PURE__ */ jsx29(
1838
+ }) => /* @__PURE__ */ jsx30(
1545
1839
  "div",
1546
1840
  {
1547
1841
  className: cn("flex h-full min-h-32 w-full items-center justify-center", className),
1548
1842
  ...props,
1549
- children: /* @__PURE__ */ jsx29(LoadingSpinner, { size, label })
1843
+ children: /* @__PURE__ */ jsx30(LoadingSpinner, { size, label })
1550
1844
  }
1551
1845
  );
1552
1846
 
1553
1847
  // src/patterns/search-bar/SearchBar.tsx
1554
1848
  import { Search, X as X5 } from "lucide-react";
1555
- import { jsx as jsx30, jsxs as jsxs15 } from "react/jsx-runtime";
1849
+ import { jsx as jsx31, jsxs as jsxs16 } from "react/jsx-runtime";
1556
1850
  function SearchBar({
1557
1851
  value,
1558
1852
  onChange,
@@ -1564,9 +1858,9 @@ function SearchBar({
1564
1858
  ...props
1565
1859
  }) {
1566
1860
  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(
1861
+ return /* @__PURE__ */ jsxs16("div", { className: cn("relative", className), children: [
1862
+ /* @__PURE__ */ jsx31("span", { className: "pointer-events-none absolute top-1/2 left-4 -translate-y-1/2 text-muted-foreground", children: isLoading ? /* @__PURE__ */ jsx31(LoadingSpinner, { size: "sm" }) : /* @__PURE__ */ jsx31(Search, { className: "h-4 w-4", "aria-hidden": "true" }) }),
1863
+ /* @__PURE__ */ jsx31(
1570
1864
  "input",
1571
1865
  {
1572
1866
  ref: inputRef,
@@ -1585,14 +1879,14 @@ function SearchBar({
1585
1879
  ...props
1586
1880
  }
1587
1881
  ),
1588
- showClear && /* @__PURE__ */ jsx30(
1882
+ showClear && /* @__PURE__ */ jsx31(
1589
1883
  "button",
1590
1884
  {
1591
1885
  type: "button",
1592
1886
  onClick: () => onClear ? onClear() : onChange(""),
1593
1887
  "aria-label": clearLabel,
1594
1888
  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" })
1889
+ children: /* @__PURE__ */ jsx31(X5, { className: "h-4 w-4", "aria-hidden": "true" })
1596
1890
  }
1597
1891
  )
1598
1892
  ] });
@@ -1607,7 +1901,7 @@ function useSidebarCollapsed() {
1607
1901
  }
1608
1902
 
1609
1903
  // src/patterns/sidebar/NavItem.tsx
1610
- import { jsx as jsx31, jsxs as jsxs16 } from "react/jsx-runtime";
1904
+ import { jsx as jsx32, jsxs as jsxs17 } from "react/jsx-runtime";
1611
1905
  function NavItem({
1612
1906
  as,
1613
1907
  icon: Icon2,
@@ -1619,7 +1913,7 @@ function NavItem({
1619
1913
  }) {
1620
1914
  const collapsed = useSidebarCollapsed();
1621
1915
  const Comp = as ?? "a";
1622
- const row = /* @__PURE__ */ jsxs16(
1916
+ const row = /* @__PURE__ */ jsxs17(
1623
1917
  Comp,
1624
1918
  {
1625
1919
  className: cn(
@@ -1631,7 +1925,7 @@ function NavItem({
1631
1925
  ),
1632
1926
  ...rest,
1633
1927
  children: [
1634
- Icon2 && /* @__PURE__ */ jsx31(
1928
+ Icon2 && /* @__PURE__ */ jsx32(
1635
1929
  Icon2,
1636
1930
  {
1637
1931
  className: cn("h-[18px] w-[18px] shrink-0", active ? "text-nav-primary" : "text-muted-foreground"),
@@ -1639,7 +1933,7 @@ function NavItem({
1639
1933
  "aria-hidden": true
1640
1934
  }
1641
1935
  ),
1642
- /* @__PURE__ */ jsx31(
1936
+ /* @__PURE__ */ jsx32(
1643
1937
  "span",
1644
1938
  {
1645
1939
  className: cn(
@@ -1654,9 +1948,9 @@ function NavItem({
1654
1948
  }
1655
1949
  );
1656
1950
  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: [
1951
+ return /* @__PURE__ */ jsxs17(Tooltip, { children: [
1952
+ /* @__PURE__ */ jsx32(TooltipTrigger, { asChild: true, children: row }),
1953
+ /* @__PURE__ */ jsxs17(TooltipContent, { side: "right", className: "flex items-center gap-1.5", children: [
1660
1954
  label,
1661
1955
  badge
1662
1956
  ] })
@@ -1665,8 +1959,8 @@ function NavItem({
1665
1959
 
1666
1960
  // src/patterns/sidebar/NavGroup.tsx
1667
1961
  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";
1962
+ import { useState as useState8 } from "react";
1963
+ import { jsx as jsx33, jsxs as jsxs18 } from "react/jsx-runtime";
1670
1964
  function NavGroup({
1671
1965
  label,
1672
1966
  defaultCollapsed = false,
@@ -1675,15 +1969,15 @@ function NavGroup({
1675
1969
  children,
1676
1970
  className
1677
1971
  }) {
1678
- const [internalCollapsed, setInternalCollapsed] = useState5(defaultCollapsed);
1972
+ const [internalCollapsed, setInternalCollapsed] = useState8(defaultCollapsed);
1679
1973
  const groupCollapsed = collapsed ?? internalCollapsed;
1680
1974
  const railCollapsed = useSidebarCollapsed();
1681
1975
  const setGroupCollapsed = (next) => {
1682
1976
  onCollapsedChange?.(next);
1683
1977
  if (collapsed === void 0) setInternalCollapsed(next);
1684
1978
  };
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(
1979
+ return /* @__PURE__ */ jsxs18("div", { className: cn("flex flex-col gap-0.5", className), children: [
1980
+ label && (railCollapsed ? /* @__PURE__ */ jsx33("div", { className: "mx-2 my-1 h-px bg-border/50", "aria-hidden": true }) : /* @__PURE__ */ jsxs18(
1687
1981
  "button",
1688
1982
  {
1689
1983
  type: "button",
@@ -1691,8 +1985,8 @@ function NavGroup({
1691
1985
  "aria-expanded": !groupCollapsed,
1692
1986
  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
1987
  children: [
1694
- /* @__PURE__ */ jsx32("span", { children: label }),
1695
- /* @__PURE__ */ jsx32(
1988
+ /* @__PURE__ */ jsx33("span", { children: label }),
1989
+ /* @__PURE__ */ jsx33(
1696
1990
  ChevronDown2,
1697
1991
  {
1698
1992
  className: cn(
@@ -1705,7 +1999,7 @@ function NavGroup({
1705
1999
  ]
1706
2000
  }
1707
2001
  )),
1708
- !groupCollapsed && /* @__PURE__ */ jsx32("div", { className: "flex flex-col gap-0.5", children })
2002
+ !groupCollapsed && /* @__PURE__ */ jsx33("div", { className: "flex flex-col gap-0.5", children })
1709
2003
  ] });
1710
2004
  }
1711
2005
 
@@ -1713,11 +2007,11 @@ function NavGroup({
1713
2007
  import { PanelLeftClose, PanelLeftOpen } from "lucide-react";
1714
2008
  import {
1715
2009
  useCallback,
1716
- useEffect as useEffect3,
1717
- useRef as useRef3,
1718
- useState as useState6
2010
+ useEffect as useEffect5,
2011
+ useRef as useRef5,
2012
+ useState as useState9
1719
2013
  } from "react";
1720
- import { jsx as jsx33, jsxs as jsxs18 } from "react/jsx-runtime";
2014
+ import { jsx as jsx34, jsxs as jsxs19 } from "react/jsx-runtime";
1721
2015
  function resolve(value, collapsed) {
1722
2016
  return typeof value === "function" ? value(collapsed) : value;
1723
2017
  }
@@ -1736,9 +2030,9 @@ function Sidebar({
1736
2030
  children,
1737
2031
  className
1738
2032
  }) {
1739
- const [internalWidth, setInternalWidth] = useState6(defaultWidth);
2033
+ const [internalWidth, setInternalWidth] = useState9(defaultWidth);
1740
2034
  const currentWidth = width ?? internalWidth;
1741
- const [isDragging, setIsDragging] = useState6(false);
2035
+ const [isDragging, setIsDragging] = useState9(false);
1742
2036
  const setWidth = useCallback(
1743
2037
  (next) => {
1744
2038
  const clamped = Math.min(maxWidth, Math.max(minWidth, next));
@@ -1747,7 +2041,7 @@ function Sidebar({
1747
2041
  },
1748
2042
  [maxWidth, minWidth, onWidthChange, width]
1749
2043
  );
1750
- const dragStartRef = useRef3(null);
2044
+ const dragStartRef = useRef5(null);
1751
2045
  const handlePointerDown = (event) => {
1752
2046
  event.currentTarget.setPointerCapture(event.pointerId);
1753
2047
  dragStartRef.current = { x: event.clientX, width: currentWidth };
@@ -1764,7 +2058,7 @@ function Sidebar({
1764
2058
  dragStartRef.current = null;
1765
2059
  setIsDragging(false);
1766
2060
  };
1767
- return /* @__PURE__ */ jsx33(SidebarContextProvider, { value: { collapsed }, children: /* @__PURE__ */ jsx33(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs18(
2061
+ return /* @__PURE__ */ jsx34(SidebarContextProvider, { value: { collapsed }, children: /* @__PURE__ */ jsx34(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs19(
1768
2062
  "aside",
1769
2063
  {
1770
2064
  style: { width: collapsed ? railWidth : currentWidth },
@@ -1774,22 +2068,22 @@ function Sidebar({
1774
2068
  className
1775
2069
  ),
1776
2070
  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(
2071
+ (header || onCollapsedChange) && /* @__PURE__ */ jsxs19("div", { className: "flex h-16 items-center gap-2 border-b border-border px-3", children: [
2072
+ header && /* @__PURE__ */ jsx34("div", { className: "min-w-0 flex-1", children: resolve(header, collapsed) }),
2073
+ onCollapsedChange && /* @__PURE__ */ jsx34(
1780
2074
  "button",
1781
2075
  {
1782
2076
  type: "button",
1783
2077
  onClick: () => onCollapsedChange(!collapsed),
1784
2078
  "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
1785
2079
  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 })
2080
+ children: collapsed ? /* @__PURE__ */ jsx34(PanelLeftOpen, { className: "h-4 w-4", "aria-hidden": true }) : /* @__PURE__ */ jsx34(PanelLeftClose, { className: "h-4 w-4", "aria-hidden": true })
1787
2081
  }
1788
2082
  )
1789
2083
  ] }),
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(
2084
+ /* @__PURE__ */ jsx34(SidebarNav, { children }),
2085
+ footer && /* @__PURE__ */ jsx34("div", { className: "border-t border-border/50 px-2 py-2", children: resolve(footer, collapsed) }),
2086
+ resizable && !collapsed && /* @__PURE__ */ jsx34(
1793
2087
  "div",
1794
2088
  {
1795
2089
  onPointerDown: handlePointerDown,
@@ -1804,9 +2098,9 @@ function Sidebar({
1804
2098
  ) }) });
1805
2099
  }
1806
2100
  function SidebarNav({ children, className, ...rest }) {
1807
- const ref = useRef3(null);
1808
- const [showFade, setShowFade] = useState6(false);
1809
- useEffect3(() => {
2101
+ const ref = useRef5(null);
2102
+ const [showFade, setShowFade] = useState9(false);
2103
+ useEffect5(() => {
1810
2104
  const el = ref.current;
1811
2105
  if (!el) return;
1812
2106
  const update = () => setShowFade(el.scrollHeight - el.scrollTop - el.clientHeight > 1);
@@ -1819,8 +2113,8 @@ function SidebarNav({ children, className, ...rest }) {
1819
2113
  observer.disconnect();
1820
2114
  };
1821
2115
  }, []);
1822
- return /* @__PURE__ */ jsxs18("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [
1823
- /* @__PURE__ */ jsx33(
2116
+ return /* @__PURE__ */ jsxs19("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [
2117
+ /* @__PURE__ */ jsx34(
1824
2118
  "div",
1825
2119
  {
1826
2120
  ref,
@@ -1829,7 +2123,7 @@ function SidebarNav({ children, className, ...rest }) {
1829
2123
  children
1830
2124
  }
1831
2125
  ),
1832
- showFade && /* @__PURE__ */ jsx33(
2126
+ showFade && /* @__PURE__ */ jsx34(
1833
2127
  "div",
1834
2128
  {
1835
2129
  className: "pointer-events-none absolute right-0 bottom-0 left-0 h-6 bg-gradient-to-t from-sidebar to-transparent",
@@ -1887,6 +2181,7 @@ export {
1887
2181
  PopoverAnchor,
1888
2182
  PopoverContent,
1889
2183
  PopoverTrigger,
2184
+ ResponsivePanel,
1890
2185
  ScrollArea,
1891
2186
  ScrollBar,
1892
2187
  SearchBar,
@@ -1934,6 +2229,7 @@ export {
1934
2229
  cn,
1935
2230
  loadingSpinnerIconVariants,
1936
2231
  sheetVariants,
2232
+ useMediaQuery,
1937
2233
  useSidebarCollapsed
1938
2234
  };
1939
2235
  //# sourceMappingURL=index.js.map