@ataraui/ataraui-react 0.3.0 → 0.5.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.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
- import React3 from 'react';
3
+ import React13 from 'react';
4
4
  import { cva } from 'class-variance-authority';
5
- import { jsxs, jsx } from 'react/jsx-runtime';
5
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
+ import { createPortal } from 'react-dom';
6
7
 
7
8
  // src/utils/cn.ts
8
9
  function cn(...inputs) {
@@ -88,7 +89,7 @@ var buttonVariants = cva(
88
89
  }
89
90
  }
90
91
  );
91
- var Button = React3.forwardRef(
92
+ var Button = React13.forwardRef(
92
93
  ({ className, variant, size, isLoading, children, disabled, ...props }, ref) => /* @__PURE__ */ jsxs(
93
94
  "button",
94
95
  {
@@ -127,7 +128,7 @@ var inputVariants = cva(
127
128
  }
128
129
  }
129
130
  );
130
- var Input = React3.forwardRef(
131
+ var Input = React13.forwardRef(
131
132
  ({ className, label, error, hint, id, inputSize, ...props }, ref) => {
132
133
  const inputId = id != null ? id : label == null ? void 0 : label.toLowerCase().replace(/\s+/g, "-");
133
134
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 w-full", children: [
@@ -194,7 +195,7 @@ var cardVariants = cva(
194
195
  }
195
196
  }
196
197
  );
197
- var Card = React3.forwardRef(
198
+ var Card = React13.forwardRef(
198
199
  ({ className, variant, padding, ...props }, ref) => /* @__PURE__ */ jsx(
199
200
  "div",
200
201
  {
@@ -205,23 +206,23 @@ var Card = React3.forwardRef(
205
206
  )
206
207
  );
207
208
  Card.displayName = "Card";
208
- var CardHeader = React3.forwardRef(
209
+ var CardHeader = React13.forwardRef(
209
210
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col gap-1.5 mb-4", className), ...props })
210
211
  );
211
212
  CardHeader.displayName = "CardHeader";
212
- var CardTitle = React3.forwardRef(
213
+ var CardTitle = React13.forwardRef(
213
214
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("h3", { ref, className: cn("text-lg font-semibold text-(--color-neutral-900)", className), ...props })
214
215
  );
215
216
  CardTitle.displayName = "CardTitle";
216
- var CardDescription = React3.forwardRef(
217
+ var CardDescription = React13.forwardRef(
217
218
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-(--color-neutral-500)", className), ...props })
218
219
  );
219
220
  CardDescription.displayName = "CardDescription";
220
- var CardContent = React3.forwardRef(
221
+ var CardContent = React13.forwardRef(
221
222
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("text-sm text-(--color-neutral-700)", className), ...props })
222
223
  );
223
224
  CardContent.displayName = "CardContent";
224
- var CardFooter = React3.forwardRef(
225
+ var CardFooter = React13.forwardRef(
225
226
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center gap-2 mt-4", className), ...props })
226
227
  );
227
228
  CardFooter.displayName = "CardFooter";
@@ -242,9 +243,9 @@ var avatarVariants = cva(
242
243
  }
243
244
  }
244
245
  );
245
- var Avatar = React3.forwardRef(
246
+ var Avatar = React13.forwardRef(
246
247
  ({ className, size, src, alt, fallback, ...props }, ref) => {
247
- const [imgError, setImgError] = React3.useState(false);
248
+ const [imgError, setImgError] = React13.useState(false);
248
249
  const initials = fallback == null ? void 0 : fallback.split(" ").map((word) => word[0]).slice(0, 2).join("").toUpperCase();
249
250
  return /* @__PURE__ */ jsx(
250
251
  "span",
@@ -288,7 +289,7 @@ var separatorVariants = cva(
288
289
  }
289
290
  }
290
291
  );
291
- var Separator = React3.forwardRef(
292
+ var Separator = React13.forwardRef(
292
293
  ({ className, orientation, label, ...props }, ref) => {
293
294
  if (label && orientation !== "vertical") {
294
295
  return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex items-center gap-3", className), ...props, children: [
@@ -327,7 +328,7 @@ var spinnerVariants = cva(
327
328
  }
328
329
  }
329
330
  );
330
- var Spinner = React3.forwardRef(
331
+ var Spinner = React13.forwardRef(
331
332
  ({ className, size, label, ...props }, ref) => /* @__PURE__ */ jsxs("span", { ref, role: "status", className: cn("inline-flex flex-col items-center gap-2", className), ...props, children: [
332
333
  /* @__PURE__ */ jsx("span", { className: cn(spinnerVariants({ size })) }),
333
334
  label && /* @__PURE__ */ jsx("span", { className: "text-sm text-(--color-neutral-500)", children: label }),
@@ -355,7 +356,7 @@ var selectVariants = cva(
355
356
  }
356
357
  }
357
358
  );
358
- var Select = React3.forwardRef(
359
+ var Select = React13.forwardRef(
359
360
  ({ className, label, error, hint, placeholder, options, selectSize, id, children, ...props }, ref) => {
360
361
  const selectId = id != null ? id : label == null ? void 0 : label.toLowerCase().replace(/\s+/g, "-");
361
362
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 w-full", children: [
@@ -395,7 +396,7 @@ var Select = React3.forwardRef(
395
396
  }
396
397
  );
397
398
  Select.displayName = "Select";
398
- var Checkbox = React3.forwardRef(
399
+ var Checkbox = React13.forwardRef(
399
400
  ({ className, label, description, error, id, disabled, ...props }, ref) => {
400
401
  const checkboxId = id != null ? id : label == null ? void 0 : label.toLowerCase().replace(/\s+/g, "-");
401
402
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
@@ -514,10 +515,10 @@ var RadioGroup = ({
514
515
  ] });
515
516
  };
516
517
  RadioGroup.displayName = "RadioGroup";
517
- var Switch = React3.forwardRef(
518
+ var Switch = React13.forwardRef(
518
519
  ({ className, label, description, error, id, disabled, checked, defaultChecked, onChange, ...props }, ref) => {
519
520
  const switchId = id != null ? id : `switch-${Math.random().toString(36).slice(2, 9)}`;
520
- const [internalChecked, setInternalChecked] = React3.useState(
521
+ const [internalChecked, setInternalChecked] = React13.useState(
521
522
  defaultChecked != null ? defaultChecked : false
522
523
  );
523
524
  const isControlled = checked !== void 0;
@@ -586,7 +587,812 @@ var Switch = React3.forwardRef(
586
587
  }
587
588
  );
588
589
  Switch.displayName = "Switch";
590
+ var modalVariants = cva(
591
+ "relative bg-white rounded-(--radius-xl) shadow-lg w-full mx-4 transition-all",
592
+ {
593
+ variants: {
594
+ size: {
595
+ sm: "max-w-sm",
596
+ md: "max-w-md",
597
+ lg: "max-w-lg",
598
+ xl: "max-w-xl",
599
+ full: "max-w-full mx-4"
600
+ }
601
+ },
602
+ defaultVariants: {
603
+ size: "md"
604
+ }
605
+ }
606
+ );
607
+ var Modal = ({
608
+ open,
609
+ onClose,
610
+ children,
611
+ size,
612
+ className,
613
+ closeOnOverlayClick = true
614
+ }) => {
615
+ React13.useEffect(() => {
616
+ if (open) {
617
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
618
+ document.body.style.overflow = "hidden";
619
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
620
+ } else {
621
+ document.body.style.overflow = "";
622
+ document.body.style.paddingRight = "";
623
+ }
624
+ return () => {
625
+ document.body.style.overflow = "";
626
+ document.body.style.paddingRight = "";
627
+ };
628
+ }, [open]);
629
+ React13.useEffect(() => {
630
+ const handleKey = (e) => {
631
+ if (e.key === "Escape") onClose();
632
+ };
633
+ if (open) document.addEventListener("keydown", handleKey);
634
+ return () => document.removeEventListener("keydown", handleKey);
635
+ }, [open, onClose]);
636
+ if (!open) return null;
637
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
638
+ /* @__PURE__ */ jsx(
639
+ "div",
640
+ {
641
+ className: "absolute inset-0 bg-black/50",
642
+ onClick: closeOnOverlayClick ? onClose : void 0
643
+ }
644
+ ),
645
+ /* @__PURE__ */ jsx("div", { className: cn(modalVariants({ size }), className), children })
646
+ ] });
647
+ };
648
+ Modal.displayName = "Modal";
649
+ var ModalHeader = ({
650
+ className,
651
+ children,
652
+ onClose,
653
+ ...props
654
+ }) => /* @__PURE__ */ jsxs(
655
+ "div",
656
+ {
657
+ className: cn("flex items-start justify-between p-6 pb-4", className),
658
+ ...props,
659
+ children: [
660
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children }),
661
+ onClose && /* @__PURE__ */ jsx(
662
+ "button",
663
+ {
664
+ type: "button",
665
+ onClick: onClose,
666
+ className: "ml-4 shrink-0 rounded-(--radius-md) p-1 text-(--color-neutral-400) hover:bg-(--color-neutral-100) hover:text-(--color-neutral-700) transition-colors",
667
+ children: /* @__PURE__ */ jsx(
668
+ "svg",
669
+ {
670
+ xmlns: "http://www.w3.org/2000/svg",
671
+ className: "h-4 w-4",
672
+ viewBox: "0 0 24 24",
673
+ fill: "none",
674
+ stroke: "currentColor",
675
+ strokeWidth: "2",
676
+ strokeLinecap: "round",
677
+ strokeLinejoin: "round",
678
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" })
679
+ }
680
+ )
681
+ }
682
+ )
683
+ ]
684
+ }
685
+ );
686
+ ModalHeader.displayName = "ModalHeader";
687
+ var ModalTitle = ({
688
+ className,
689
+ ...props
690
+ }) => /* @__PURE__ */ jsx(
691
+ "h2",
692
+ {
693
+ className: cn(
694
+ "text-lg font-semibold text-(--color-neutral-900)",
695
+ className
696
+ ),
697
+ ...props
698
+ }
699
+ );
700
+ ModalTitle.displayName = "ModalTitle";
701
+ var ModalDescription = ({ className, ...props }) => /* @__PURE__ */ jsx(
702
+ "p",
703
+ {
704
+ className: cn("text-sm text-(--color-neutral-500)", className),
705
+ ...props
706
+ }
707
+ );
708
+ ModalDescription.displayName = "ModalDescription";
709
+ var ModalBody = ({
710
+ className,
711
+ ...props
712
+ }) => /* @__PURE__ */ jsx(
713
+ "div",
714
+ {
715
+ className: cn("px-6 py-2 text-sm text-(--color-neutral-700)", className),
716
+ ...props
717
+ }
718
+ );
719
+ ModalBody.displayName = "ModalBody";
720
+ var ModalFooter = ({
721
+ className,
722
+ ...props
723
+ }) => /* @__PURE__ */ jsx(
724
+ "div",
725
+ {
726
+ className: cn("flex items-center justify-end gap-2 p-6 pt-4", className),
727
+ ...props
728
+ }
729
+ );
730
+ ModalFooter.displayName = "ModalFooter";
731
+ var drawerVariants = cva(
732
+ "fixed z-50 bg-white shadow-xl transition-transform duration-300 ease-in-out",
733
+ {
734
+ variants: {
735
+ side: {
736
+ left: "inset-y-0 left-0 h-full",
737
+ right: "inset-y-0 right-0 h-full",
738
+ top: "inset-x-0 top-0 w-full",
739
+ bottom: "inset-x-0 bottom-0 w-full"
740
+ }
741
+ },
742
+ defaultVariants: {
743
+ side: "right"
744
+ }
745
+ }
746
+ );
747
+ var sizeStyle = {
748
+ sm: { width: "20rem" },
749
+ md: { width: "24rem" },
750
+ lg: { width: "32rem" },
751
+ full: { width: "100%" }
752
+ };
753
+ var translateMap = {
754
+ left: { closed: "translateX(-100%)", open: "translateX(0)" },
755
+ right: { closed: "translateX(100%)", open: "translateX(0)" },
756
+ top: { closed: "translateY(-100%)", open: "translateY(0)" },
757
+ bottom: { closed: "translateY(100%)", open: "translateY(0)" }
758
+ };
759
+ var Drawer = ({
760
+ open,
761
+ onClose,
762
+ children,
763
+ side = "right",
764
+ size = "md",
765
+ className,
766
+ closeOnOverlayClick = true
767
+ }) => {
768
+ React13.useEffect(() => {
769
+ if (open) {
770
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
771
+ document.body.style.overflow = "hidden";
772
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
773
+ } else {
774
+ document.body.style.overflow = "";
775
+ document.body.style.paddingRight = "";
776
+ }
777
+ return () => {
778
+ document.body.style.overflow = "";
779
+ document.body.style.paddingRight = "";
780
+ };
781
+ }, [open]);
782
+ React13.useEffect(() => {
783
+ const handleKey = (e) => {
784
+ if (e.key === "Escape") onClose();
785
+ };
786
+ if (open) document.addEventListener("keydown", handleKey);
787
+ return () => document.removeEventListener("keydown", handleKey);
788
+ }, [open, onClose]);
789
+ const resolvedSide = side != null ? side : "right";
790
+ const transform = open ? translateMap[resolvedSide].open : translateMap[resolvedSide].closed;
791
+ const isHorizontal = resolvedSide === "left" || resolvedSide === "right";
792
+ return /* @__PURE__ */ jsxs("div", { className: cn("fixed inset-0 z-50", !open && "pointer-events-none"), children: [
793
+ /* @__PURE__ */ jsx(
794
+ "div",
795
+ {
796
+ className: cn(
797
+ "absolute inset-0 bg-black/50 transition-opacity duration-300",
798
+ open ? "opacity-100" : "opacity-0"
799
+ ),
800
+ onClick: closeOnOverlayClick ? onClose : void 0
801
+ }
802
+ ),
803
+ /* @__PURE__ */ jsx(
804
+ "div",
805
+ {
806
+ className: cn(drawerVariants({ side }), className),
807
+ style: {
808
+ transform,
809
+ ...isHorizontal ? sizeStyle[size] : { height: "auto", maxHeight: "80vh" }
810
+ },
811
+ children
812
+ }
813
+ )
814
+ ] });
815
+ };
816
+ Drawer.displayName = "Drawer";
817
+ var DrawerHeader = ({
818
+ className,
819
+ children,
820
+ onClose,
821
+ ...props
822
+ }) => /* @__PURE__ */ jsxs(
823
+ "div",
824
+ {
825
+ className: cn("flex items-start justify-between p-6 pb-4 border-b border-(--color-neutral-200)", className),
826
+ ...props,
827
+ children: [
828
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children }),
829
+ onClose && /* @__PURE__ */ jsx(
830
+ "button",
831
+ {
832
+ type: "button",
833
+ onClick: onClose,
834
+ className: "ml-4 shrink-0 rounded-(--radius-md) p-1 text-(--color-neutral-400) hover:bg-(--color-neutral-100) hover:text-(--color-neutral-700) transition-colors",
835
+ children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
836
+ }
837
+ )
838
+ ]
839
+ }
840
+ );
841
+ DrawerHeader.displayName = "DrawerHeader";
842
+ var DrawerTitle = ({
843
+ className,
844
+ ...props
845
+ }) => /* @__PURE__ */ jsx(
846
+ "h2",
847
+ {
848
+ className: cn("text-lg font-semibold text-(--color-neutral-900)", className),
849
+ ...props
850
+ }
851
+ );
852
+ DrawerTitle.displayName = "DrawerTitle";
853
+ var DrawerDescription = ({
854
+ className,
855
+ ...props
856
+ }) => /* @__PURE__ */ jsx(
857
+ "p",
858
+ {
859
+ className: cn("text-sm text-(--color-neutral-500)", className),
860
+ ...props
861
+ }
862
+ );
863
+ DrawerDescription.displayName = "DrawerDescription";
864
+ var DrawerBody = ({
865
+ className,
866
+ ...props
867
+ }) => /* @__PURE__ */ jsx(
868
+ "div",
869
+ {
870
+ className: cn("flex-1 overflow-y-auto p-6 text-sm text-(--color-neutral-700)", className),
871
+ ...props
872
+ }
873
+ );
874
+ DrawerBody.displayName = "DrawerBody";
875
+ var DrawerFooter = ({
876
+ className,
877
+ ...props
878
+ }) => /* @__PURE__ */ jsx(
879
+ "div",
880
+ {
881
+ className: cn("flex items-center justify-end gap-2 p-6 pt-4 border-t border-(--color-neutral-200)", className),
882
+ ...props
883
+ }
884
+ );
885
+ DrawerFooter.displayName = "DrawerFooter";
886
+ var Tooltip = ({
887
+ content,
888
+ children,
889
+ side = "top",
890
+ delay = 300,
891
+ className
892
+ }) => {
893
+ var _a, _b;
894
+ const [visible, setVisible] = React13.useState(false);
895
+ const [coords, setCoords] = React13.useState(null);
896
+ const triggerRef = React13.useRef(null);
897
+ const tooltipRef = React13.useRef(null);
898
+ const timerRef = React13.useRef(null);
899
+ const computeCoords = React13.useCallback(() => {
900
+ if (!triggerRef.current || !tooltipRef.current) return;
901
+ const t = triggerRef.current.getBoundingClientRect();
902
+ const tt = tooltipRef.current.getBoundingClientRect();
903
+ const offset = 8;
904
+ switch (side) {
905
+ case "top":
906
+ setCoords({
907
+ top: t.top - tt.height - offset,
908
+ left: t.left + t.width / 2 - tt.width / 2
909
+ });
910
+ break;
911
+ case "bottom":
912
+ setCoords({
913
+ top: t.bottom + offset,
914
+ left: t.left + t.width / 2 - tt.width / 2
915
+ });
916
+ break;
917
+ case "left":
918
+ setCoords({
919
+ top: t.top + t.height / 2 - tt.height / 2,
920
+ left: t.left - tt.width - offset
921
+ });
922
+ break;
923
+ case "right":
924
+ setCoords({
925
+ top: t.top + t.height / 2 - tt.height / 2,
926
+ left: t.right + offset
927
+ });
928
+ break;
929
+ }
930
+ }, [side]);
931
+ React13.useLayoutEffect(() => {
932
+ if (!visible) return;
933
+ computeCoords();
934
+ }, [computeCoords, content, visible]);
935
+ React13.useEffect(() => {
936
+ if (!visible) return;
937
+ window.addEventListener("resize", computeCoords);
938
+ window.addEventListener("scroll", computeCoords, true);
939
+ return () => {
940
+ window.removeEventListener("resize", computeCoords);
941
+ window.removeEventListener("scroll", computeCoords, true);
942
+ };
943
+ }, [computeCoords, visible]);
944
+ const show = () => {
945
+ if (timerRef.current) clearTimeout(timerRef.current);
946
+ timerRef.current = setTimeout(() => {
947
+ setCoords(null);
948
+ setVisible(true);
949
+ }, delay);
950
+ };
951
+ const hide = () => {
952
+ if (timerRef.current) clearTimeout(timerRef.current);
953
+ setVisible(false);
954
+ setCoords(null);
955
+ };
956
+ React13.useEffect(() => {
957
+ return () => {
958
+ if (timerRef.current) clearTimeout(timerRef.current);
959
+ };
960
+ }, []);
961
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
962
+ /* @__PURE__ */ jsx(
963
+ "div",
964
+ {
965
+ ref: triggerRef,
966
+ className: "inline-flex",
967
+ onMouseEnter: show,
968
+ onMouseLeave: hide,
969
+ onFocus: show,
970
+ onBlur: hide,
971
+ children
972
+ }
973
+ ),
974
+ visible && /* @__PURE__ */ jsx(
975
+ "div",
976
+ {
977
+ ref: tooltipRef,
978
+ role: "tooltip",
979
+ className: cn(
980
+ "fixed z-50 px-2.5 py-1.5 text-xs font-medium text-white rounded-(--radius-md) shadow-md pointer-events-none whitespace-nowrap transition-opacity",
981
+ coords ? "opacity-100" : "opacity-0",
982
+ className
983
+ ),
984
+ style: {
985
+ top: (_a = coords == null ? void 0 : coords.top) != null ? _a : 0,
986
+ left: (_b = coords == null ? void 0 : coords.left) != null ? _b : 0,
987
+ backgroundColor: "var(--color-neutral-900)"
988
+ },
989
+ children: content
990
+ }
991
+ )
992
+ ] });
993
+ };
994
+ Tooltip.displayName = "Tooltip";
995
+ var Popover = ({
996
+ content,
997
+ children,
998
+ side = "bottom",
999
+ align = "center",
1000
+ open,
1001
+ defaultOpen = false,
1002
+ onOpenChange,
1003
+ className,
1004
+ closeOnOutsideClick = true
1005
+ }) => {
1006
+ var _a, _b;
1007
+ const [uncontrolledOpen, setUncontrolledOpen] = React13.useState(defaultOpen);
1008
+ const [coords, setCoords] = React13.useState(null);
1009
+ const [mounted, setMounted] = React13.useState(false);
1010
+ const triggerRef = React13.useRef(null);
1011
+ const popoverRef = React13.useRef(null);
1012
+ const isControlled = open !== void 0;
1013
+ const isOpen = isControlled ? open : uncontrolledOpen;
1014
+ const setOpen = React13.useCallback((nextOpen) => {
1015
+ if (!isControlled) setUncontrolledOpen(nextOpen);
1016
+ onOpenChange == null ? void 0 : onOpenChange(nextOpen);
1017
+ }, [isControlled, onOpenChange]);
1018
+ const close = React13.useCallback(() => setOpen(false), [setOpen]);
1019
+ const openPopover = React13.useCallback(() => setOpen(true), [setOpen]);
1020
+ const controls = React13.useMemo(() => ({
1021
+ close,
1022
+ open: openPopover,
1023
+ setOpen
1024
+ }), [close, openPopover, setOpen]);
1025
+ const computeCoords = React13.useCallback(() => {
1026
+ if (!triggerRef.current || !popoverRef.current) return;
1027
+ const trigger = triggerRef.current.getBoundingClientRect();
1028
+ const popover2 = popoverRef.current.getBoundingClientRect();
1029
+ const offset = 8;
1030
+ let top = 0;
1031
+ let left = 0;
1032
+ if (side === "top") top = trigger.top - popover2.height - offset;
1033
+ if (side === "bottom") top = trigger.bottom + offset;
1034
+ if (side === "left") left = trigger.left - popover2.width - offset;
1035
+ if (side === "right") left = trigger.right + offset;
1036
+ if (side === "top" || side === "bottom") {
1037
+ if (align === "start") left = trigger.left;
1038
+ if (align === "center") left = trigger.left + trigger.width / 2 - popover2.width / 2;
1039
+ if (align === "end") left = trigger.right - popover2.width;
1040
+ }
1041
+ if (side === "left" || side === "right") {
1042
+ if (align === "start") top = trigger.top;
1043
+ if (align === "center") top = trigger.top + trigger.height / 2 - popover2.height / 2;
1044
+ if (align === "end") top = trigger.bottom - popover2.height;
1045
+ }
1046
+ setCoords({
1047
+ top: Math.max(8, Math.min(top, window.innerHeight - popover2.height - 8)),
1048
+ left: Math.max(8, Math.min(left, window.innerWidth - popover2.width - 8))
1049
+ });
1050
+ }, [align, side]);
1051
+ React13.useEffect(() => {
1052
+ setMounted(true);
1053
+ }, []);
1054
+ React13.useLayoutEffect(() => {
1055
+ if (!isOpen) return;
1056
+ computeCoords();
1057
+ }, [computeCoords, content, isOpen]);
1058
+ React13.useEffect(() => {
1059
+ if (!isOpen) return;
1060
+ const handleKeyDown = (event) => {
1061
+ if (event.key === "Escape") close();
1062
+ };
1063
+ const handlePointerDown = (event) => {
1064
+ var _a2, _b2;
1065
+ const target = event.target;
1066
+ const clickedTrigger = (_a2 = triggerRef.current) == null ? void 0 : _a2.contains(target);
1067
+ const clickedPopover = (_b2 = popoverRef.current) == null ? void 0 : _b2.contains(target);
1068
+ if (!clickedTrigger && !clickedPopover) close();
1069
+ };
1070
+ document.addEventListener("keydown", handleKeyDown);
1071
+ if (closeOnOutsideClick) document.addEventListener("pointerdown", handlePointerDown);
1072
+ window.addEventListener("resize", computeCoords);
1073
+ window.addEventListener("scroll", computeCoords, true);
1074
+ return () => {
1075
+ document.removeEventListener("keydown", handleKeyDown);
1076
+ document.removeEventListener("pointerdown", handlePointerDown);
1077
+ window.removeEventListener("resize", computeCoords);
1078
+ window.removeEventListener("scroll", computeCoords, true);
1079
+ };
1080
+ }, [close, closeOnOutsideClick, computeCoords, isOpen]);
1081
+ const popover = isOpen ? /* @__PURE__ */ jsx(
1082
+ "div",
1083
+ {
1084
+ ref: popoverRef,
1085
+ role: "dialog",
1086
+ className: cn(
1087
+ "fixed z-50 min-w-48 rounded-(--radius-lg) border border-(--color-neutral-200) bg-white p-4 text-sm text-(--color-neutral-700) shadow-lg outline-none transition-opacity",
1088
+ coords ? "opacity-100" : "opacity-0",
1089
+ className
1090
+ ),
1091
+ style: {
1092
+ top: (_a = coords == null ? void 0 : coords.top) != null ? _a : 0,
1093
+ left: (_b = coords == null ? void 0 : coords.left) != null ? _b : 0
1094
+ },
1095
+ children: typeof content === "function" ? content(controls) : content
1096
+ }
1097
+ ) : null;
1098
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1099
+ /* @__PURE__ */ jsx(
1100
+ "div",
1101
+ {
1102
+ ref: triggerRef,
1103
+ className: "inline-flex",
1104
+ "aria-expanded": isOpen,
1105
+ onClick: () => setOpen(!isOpen),
1106
+ children
1107
+ }
1108
+ ),
1109
+ mounted && popover ? createPortal(popover, document.body) : null
1110
+ ] });
1111
+ };
1112
+ Popover.displayName = "Popover";
1113
+ var ToastContext = React13.createContext(null);
1114
+ var counter = 0;
1115
+ var genId = () => `toast-${++counter}`;
1116
+ var ToastProvider = ({ children }) => {
1117
+ const [toasts, setToasts] = React13.useState([]);
1118
+ const toast = React13.useCallback((input) => {
1119
+ const id = genId();
1120
+ setToasts((prev) => [...prev, { ...input, id }]);
1121
+ return id;
1122
+ }, []);
1123
+ const dismiss = React13.useCallback((id) => {
1124
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1125
+ }, []);
1126
+ const dismissAll = React13.useCallback(() => {
1127
+ setToasts([]);
1128
+ }, []);
1129
+ return /* @__PURE__ */ jsx(ToastContext.Provider, { value: { toasts, toast, dismiss, dismissAll }, children });
1130
+ };
1131
+ var useToast = () => {
1132
+ const ctx = React13.useContext(ToastContext);
1133
+ if (!ctx) throw new Error("useToast must be used within a ToastProvider");
1134
+ return ctx;
1135
+ };
1136
+ var toastVariants = cva(
1137
+ "pointer-events-auto relative flex w-80 max-w-[calc(100vw-2rem)] items-start gap-3 overflow-hidden rounded-(--radius-lg) border p-4 pr-8 shadow-lg",
1138
+ {
1139
+ variants: {
1140
+ variant: {
1141
+ default: "border-(--color-neutral-200) bg-white text-(--color-neutral-800)",
1142
+ success: "border-green-200 bg-green-50 text-green-900",
1143
+ warning: "border-yellow-200 bg-yellow-50 text-yellow-900",
1144
+ destructive: "border-red-200 bg-red-50 text-red-900"
1145
+ }
1146
+ },
1147
+ defaultVariants: { variant: "default" }
1148
+ }
1149
+ );
1150
+ var positionClasses = {
1151
+ "top-left": "top-4 left-4 items-start",
1152
+ "top-center": "top-4 left-1/2 -translate-x-1/2 items-center",
1153
+ "top-right": "top-4 right-4 items-end",
1154
+ "bottom-left": "bottom-4 left-4 items-start",
1155
+ "bottom-center": "bottom-4 left-1/2 -translate-x-1/2 items-center",
1156
+ "bottom-right": "bottom-4 right-4 items-end"
1157
+ };
1158
+ var SingleToast = ({ toast, onDismiss, defaultDuration }) => {
1159
+ var _a, _b;
1160
+ const duration = (_a = toast.duration) != null ? _a : defaultDuration;
1161
+ React13.useEffect(() => {
1162
+ if (duration <= 0) return;
1163
+ const timer = setTimeout(() => onDismiss(toast.id), duration);
1164
+ return () => clearTimeout(timer);
1165
+ }, [duration, onDismiss, toast.id]);
1166
+ return /* @__PURE__ */ jsxs(
1167
+ "div",
1168
+ {
1169
+ role: "status",
1170
+ "aria-live": "polite",
1171
+ className: toastVariants({ variant: (_b = toast.variant) != null ? _b : "default" }),
1172
+ children: [
1173
+ toast.icon && /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 [&>svg]:size-4", children: toast.icon }),
1174
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1", children: [
1175
+ toast.title && /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold leading-none", children: toast.title }),
1176
+ toast.description && /* @__PURE__ */ jsx("p", { className: "text-xs opacity-80", children: toast.description }),
1177
+ toast.action && /* @__PURE__ */ jsx(
1178
+ "button",
1179
+ {
1180
+ type: "button",
1181
+ onClick: () => {
1182
+ toast.action.onClick();
1183
+ onDismiss(toast.id);
1184
+ },
1185
+ className: "mt-1.5 text-xs font-medium underline underline-offset-2 hover:no-underline focus:outline-none",
1186
+ children: toast.action.label
1187
+ }
1188
+ )
1189
+ ] }),
1190
+ /* @__PURE__ */ jsx(
1191
+ "button",
1192
+ {
1193
+ type: "button",
1194
+ "aria-label": "Dismiss",
1195
+ onClick: () => onDismiss(toast.id),
1196
+ className: "absolute right-2 top-2 rounded opacity-50 transition-opacity hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-(--color-primary-500)",
1197
+ children: /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1198
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
1199
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
1200
+ ] })
1201
+ }
1202
+ )
1203
+ ]
1204
+ }
1205
+ );
1206
+ };
1207
+ var Toaster = ({
1208
+ position = "bottom-right",
1209
+ defaultDuration = 4e3,
1210
+ className
1211
+ }) => {
1212
+ const { toasts, dismiss } = useToast();
1213
+ const [mounted, setMounted] = React13.useState(false);
1214
+ React13.useEffect(() => {
1215
+ setMounted(true);
1216
+ }, []);
1217
+ if (!mounted) return null;
1218
+ return createPortal(
1219
+ /* @__PURE__ */ jsx(
1220
+ "div",
1221
+ {
1222
+ "aria-label": "Notifications",
1223
+ className: cn(
1224
+ "fixed z-[100] flex flex-col gap-2 pointer-events-none",
1225
+ positionClasses[position],
1226
+ className
1227
+ ),
1228
+ children: toasts.map((t) => /* @__PURE__ */ jsx(
1229
+ SingleToast,
1230
+ {
1231
+ toast: t,
1232
+ onDismiss: dismiss,
1233
+ defaultDuration
1234
+ },
1235
+ t.id
1236
+ ))
1237
+ }
1238
+ ),
1239
+ document.body
1240
+ );
1241
+ };
1242
+ Toaster.displayName = "Toaster";
1243
+ ToastProvider.displayName = "ToastProvider";
1244
+ var alertVariants = cva(
1245
+ "relative flex w-full gap-3 rounded-(--radius-lg) border p-4 text-sm",
1246
+ {
1247
+ variants: {
1248
+ variant: {
1249
+ default: "border-(--color-neutral-200) bg-(--color-neutral-50) text-(--color-neutral-700)",
1250
+ success: "border-green-200 bg-green-50 text-green-800",
1251
+ warning: "border-yellow-200 bg-yellow-50 text-yellow-800",
1252
+ destructive: "border-red-200 bg-red-50 text-red-800"
1253
+ }
1254
+ },
1255
+ defaultVariants: { variant: "default" }
1256
+ }
1257
+ );
1258
+ var Alert = ({
1259
+ variant,
1260
+ icon,
1261
+ onClose,
1262
+ className,
1263
+ children,
1264
+ ...props
1265
+ }) => {
1266
+ return /* @__PURE__ */ jsxs(
1267
+ "div",
1268
+ {
1269
+ role: "alert",
1270
+ className: cn(alertVariants({ variant }), className),
1271
+ ...props,
1272
+ children: [
1273
+ icon && /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 [&>svg]:size-4", children: icon }),
1274
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children }),
1275
+ onClose && /* @__PURE__ */ jsx(
1276
+ "button",
1277
+ {
1278
+ type: "button",
1279
+ "aria-label": "Dismiss",
1280
+ onClick: onClose,
1281
+ className: "ml-auto shrink-0 self-start rounded opacity-60 transition-opacity hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-(--color-primary-500)",
1282
+ children: /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1283
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
1284
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
1285
+ ] })
1286
+ }
1287
+ )
1288
+ ]
1289
+ }
1290
+ );
1291
+ };
1292
+ Alert.displayName = "Alert";
1293
+ var AlertTitle = ({
1294
+ className,
1295
+ children,
1296
+ ...props
1297
+ }) => /* @__PURE__ */ jsx("p", { className: cn("font-semibold leading-none tracking-tight", className), ...props, children });
1298
+ AlertTitle.displayName = "AlertTitle";
1299
+ var AlertDescription = ({
1300
+ className,
1301
+ children,
1302
+ ...props
1303
+ }) => /* @__PURE__ */ jsx("p", { className: cn("mt-1 text-[0.8rem] opacity-80", className), ...props, children });
1304
+ AlertDescription.displayName = "AlertDescription";
1305
+ var progressVariants = cva(
1306
+ "w-full overflow-hidden rounded-full bg-(--color-neutral-200)",
1307
+ {
1308
+ variants: {
1309
+ size: {
1310
+ sm: "h-1",
1311
+ md: "h-2",
1312
+ lg: "h-3"
1313
+ }
1314
+ },
1315
+ defaultVariants: { size: "md" }
1316
+ }
1317
+ );
1318
+ var Progress = ({
1319
+ value,
1320
+ size,
1321
+ label,
1322
+ showLabel = false,
1323
+ className,
1324
+ ...props
1325
+ }) => {
1326
+ const isIndeterminate = value === void 0 || value === null;
1327
+ return /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
1328
+ (label || showLabel) && /* @__PURE__ */ jsxs("div", { className: "mb-1.5 flex items-center justify-between text-xs text-(--color-neutral-600)", children: [
1329
+ label && /* @__PURE__ */ jsx("span", { children: label }),
1330
+ showLabel && !isIndeterminate && /* @__PURE__ */ jsxs("span", { className: "ml-auto font-medium", children: [
1331
+ Math.round(value),
1332
+ "%"
1333
+ ] })
1334
+ ] }),
1335
+ /* @__PURE__ */ jsx(
1336
+ "div",
1337
+ {
1338
+ role: "progressbar",
1339
+ "aria-valuemin": 0,
1340
+ "aria-valuemax": 100,
1341
+ "aria-valuenow": isIndeterminate ? void 0 : value,
1342
+ className: cn(progressVariants({ size }), className),
1343
+ ...props,
1344
+ children: /* @__PURE__ */ jsx(
1345
+ "div",
1346
+ {
1347
+ className: cn(
1348
+ "h-full rounded-full bg-(--color-primary-500) transition-all duration-300 ease-in-out",
1349
+ isIndeterminate && "w-1/3 animate-[indeterminate_1.5s_ease-in-out_infinite]"
1350
+ ),
1351
+ style: isIndeterminate ? void 0 : { width: `${Math.min(100, Math.max(0, value))}%` }
1352
+ }
1353
+ )
1354
+ }
1355
+ )
1356
+ ] });
1357
+ };
1358
+ Progress.displayName = "Progress";
1359
+ var skeletonVariants = cva(
1360
+ "animate-pulse bg-(--color-neutral-200)",
1361
+ {
1362
+ variants: {
1363
+ variant: {
1364
+ text: "h-4 w-full rounded",
1365
+ circle: "rounded-full",
1366
+ rect: "rounded-(--radius-md)"
1367
+ }
1368
+ },
1369
+ defaultVariants: { variant: "rect" }
1370
+ }
1371
+ );
1372
+ var Skeleton = ({
1373
+ variant,
1374
+ width,
1375
+ height,
1376
+ className,
1377
+ style,
1378
+ ...props
1379
+ }) => {
1380
+ return /* @__PURE__ */ jsx(
1381
+ "div",
1382
+ {
1383
+ "aria-hidden": "true",
1384
+ className: cn(skeletonVariants({ variant }), className),
1385
+ style: {
1386
+ width: typeof width === "number" ? `${width}px` : width,
1387
+ height: typeof height === "number" ? `${height}px` : height,
1388
+ ...style
1389
+ },
1390
+ ...props
1391
+ }
1392
+ );
1393
+ };
1394
+ Skeleton.displayName = "Skeleton";
589
1395
 
590
- export { Avatar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Input, RadioGroup, Select, Separator, Spinner, Switch, avatarVariants, badgeVariants, buttonVariants, cardVariants, cn, colors, fontSize, inputVariants, radius, selectVariants, separatorVariants, spinnerVariants };
1396
+ export { Alert, AlertDescription, AlertTitle, Avatar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Drawer, DrawerBody, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, Input, Modal, ModalBody, ModalDescription, ModalFooter, ModalHeader, ModalTitle, Popover, Progress, RadioGroup, Select, Separator, Skeleton, Spinner, Switch, ToastProvider, Toaster, Tooltip, alertVariants, avatarVariants, badgeVariants, buttonVariants, cardVariants, cn, colors, drawerVariants, fontSize, inputVariants, modalVariants, progressVariants, radius, selectVariants, separatorVariants, skeletonVariants, spinnerVariants, toastVariants, useToast };
591
1397
  //# sourceMappingURL=index.mjs.map
592
1398
  //# sourceMappingURL=index.mjs.map