@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.d.ts +79 -1
- package/dist/index.js +433 -137
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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) =>
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
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] =
|
|
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
|
|
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] =
|
|
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
|
|
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__ */
|
|
868
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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
|
|
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] =
|
|
950
|
-
const [search, setSearch] =
|
|
951
|
-
const [activeIndex, setActiveIndex] =
|
|
952
|
-
const inputRef =
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1040
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1047
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1064
|
-
/* @__PURE__ */
|
|
1065
|
-
clearable && !loading && selectedValues.length > 0 ? /* @__PURE__ */
|
|
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__ */
|
|
1374
|
+
children: /* @__PURE__ */ jsx25(X3, { className: "h-3.5 w-3.5" })
|
|
1081
1375
|
}
|
|
1082
1376
|
) : null,
|
|
1083
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1096
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1122
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
1159
|
-
import { jsx as
|
|
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] =
|
|
1178
|
-
const [search, setSearch] =
|
|
1179
|
-
const [activeIndex, setActiveIndex] =
|
|
1180
|
-
const inputRef =
|
|
1181
|
-
const fieldRef =
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1569
|
+
/* @__PURE__ */ jsx26("span", { className: "truncate", children: option.label })
|
|
1276
1570
|
]
|
|
1277
1571
|
},
|
|
1278
1572
|
option.value
|
|
1279
1573
|
);
|
|
1280
1574
|
}
|
|
1281
|
-
return /* @__PURE__ */
|
|
1282
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1306
|
-
!disabled && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1363
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1407
|
-
warning: /* @__PURE__ */
|
|
1408
|
-
info: /* @__PURE__ */
|
|
1409
|
-
success: /* @__PURE__ */
|
|
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__ */
|
|
1414
|
-
resolvedIcon != null && /* @__PURE__ */
|
|
1415
|
-
/* @__PURE__ */
|
|
1416
|
-
title && /* @__PURE__ */
|
|
1417
|
-
/* @__PURE__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1536
|
-
/* @__PURE__ */
|
|
1537
|
-
label ? /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1568
|
-
/* @__PURE__ */
|
|
1569
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1658
|
-
/* @__PURE__ */
|
|
1659
|
-
/* @__PURE__ */
|
|
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
|
|
1669
|
-
import { jsx as
|
|
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] =
|
|
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__ */
|
|
1686
|
-
label && (railCollapsed ? /* @__PURE__ */
|
|
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__ */
|
|
1695
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
1717
|
-
useRef as
|
|
1718
|
-
useState as
|
|
2010
|
+
useEffect as useEffect5,
|
|
2011
|
+
useRef as useRef5,
|
|
2012
|
+
useState as useState9
|
|
1719
2013
|
} from "react";
|
|
1720
|
-
import { jsx as
|
|
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] =
|
|
2033
|
+
const [internalWidth, setInternalWidth] = useState9(defaultWidth);
|
|
1740
2034
|
const currentWidth = width ?? internalWidth;
|
|
1741
|
-
const [isDragging, setIsDragging] =
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
1778
|
-
header && /* @__PURE__ */
|
|
1779
|
-
onCollapsedChange && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1791
|
-
footer && /* @__PURE__ */
|
|
1792
|
-
resizable && !collapsed && /* @__PURE__ */
|
|
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 =
|
|
1808
|
-
const [showFade, setShowFade] =
|
|
1809
|
-
|
|
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__ */
|
|
1823
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|