@ataraui/ataraui-react 0.2.0 → 0.4.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 }),
@@ -335,7 +336,781 @@ var Spinner = React3.forwardRef(
335
336
  ] })
336
337
  );
337
338
  Spinner.displayName = "Spinner";
339
+ var selectVariants = cva(
340
+ "w-full appearance-none bg-white border rounded-(--radius-md) px-3 py-2 text-sm transition-colors cursor-pointer focus:outline-none focus:ring-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-(--color-neutral-50)",
341
+ {
342
+ variants: {
343
+ state: {
344
+ default: "border-(--color-neutral-300) text-(--color-neutral-900) focus:border-(--color-primary-500) focus:ring-(--color-primary-500)/20",
345
+ error: "border-(--color-danger-500) text-(--color-neutral-900) focus:border-(--color-danger-500) focus:ring-(--color-danger-500)/20"
346
+ },
347
+ selectSize: {
348
+ sm: "h-8 text-xs pr-8",
349
+ md: "h-10 text-sm pr-8",
350
+ lg: "h-12 text-base pr-10"
351
+ }
352
+ },
353
+ defaultVariants: {
354
+ state: "default",
355
+ selectSize: "md"
356
+ }
357
+ }
358
+ );
359
+ var Select = React13.forwardRef(
360
+ ({ className, label, error, hint, placeholder, options, selectSize, id, children, ...props }, ref) => {
361
+ const selectId = id != null ? id : label == null ? void 0 : label.toLowerCase().replace(/\s+/g, "-");
362
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 w-full", children: [
363
+ label && /* @__PURE__ */ jsx("label", { htmlFor: selectId, className: "text-sm font-medium text-(--color-neutral-700)", children: label }),
364
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
365
+ /* @__PURE__ */ jsxs(
366
+ "select",
367
+ {
368
+ ref,
369
+ id: selectId,
370
+ className: cn(selectVariants({ state: error ? "error" : "default", selectSize }), className),
371
+ ...props,
372
+ children: [
373
+ placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
374
+ options ? options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, disabled: opt.disabled, children: opt.label }, opt.value)) : children
375
+ ]
376
+ }
377
+ ),
378
+ /* @__PURE__ */ jsx(
379
+ "svg",
380
+ {
381
+ className: "pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-(--color-neutral-400)",
382
+ xmlns: "http://www.w3.org/2000/svg",
383
+ viewBox: "0 0 24 24",
384
+ fill: "none",
385
+ stroke: "currentColor",
386
+ strokeWidth: "2",
387
+ strokeLinecap: "round",
388
+ strokeLinejoin: "round",
389
+ children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" })
390
+ }
391
+ )
392
+ ] }),
393
+ hint && !error && /* @__PURE__ */ jsx("p", { className: "text-xs text-(--color-neutral-500)", children: hint }),
394
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-(--color-danger-500)", children: error })
395
+ ] });
396
+ }
397
+ );
398
+ Select.displayName = "Select";
399
+ var Checkbox = React13.forwardRef(
400
+ ({ className, label, description, error, id, disabled, ...props }, ref) => {
401
+ const checkboxId = id != null ? id : label == null ? void 0 : label.toLowerCase().replace(/\s+/g, "-");
402
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
403
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2.5", children: [
404
+ /* @__PURE__ */ jsx(
405
+ "input",
406
+ {
407
+ ref,
408
+ type: "checkbox",
409
+ id: checkboxId,
410
+ disabled,
411
+ className: cn(
412
+ "h-4 w-4 shrink-0 mt-0.5 rounded-(--radius-sm) border cursor-pointer transition-colors appearance-none",
413
+ "border-(--color-neutral-300) bg-white",
414
+ "checked:bg-(--color-primary-500) checked:border-(--color-primary-500)",
415
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-primary-500)/20",
416
+ "disabled:cursor-not-allowed disabled:opacity-50",
417
+ error && "border-(--color-danger-500)",
418
+ className
419
+ ),
420
+ style: {
421
+ backgroundImage: `url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")`,
422
+ backgroundRepeat: "no-repeat",
423
+ backgroundPosition: "center"
424
+ },
425
+ ...props
426
+ }
427
+ ),
428
+ (label || description) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
429
+ label && /* @__PURE__ */ jsx(
430
+ "label",
431
+ {
432
+ htmlFor: checkboxId,
433
+ className: cn(
434
+ "text-sm font-medium cursor-pointer text-(--color-neutral-900)",
435
+ disabled && "cursor-not-allowed opacity-50"
436
+ ),
437
+ children: label
438
+ }
439
+ ),
440
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-(--color-neutral-500)", children: description })
441
+ ] })
442
+ ] }),
443
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-(--color-danger-500) ml-6", children: error })
444
+ ] });
445
+ }
446
+ );
447
+ Checkbox.displayName = "Checkbox";
448
+ var RadioGroup = ({
449
+ options,
450
+ value,
451
+ onChange,
452
+ name,
453
+ label,
454
+ error,
455
+ hint,
456
+ orientation = "vertical"
457
+ }) => {
458
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
459
+ label && /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-(--color-neutral-700)", children: label }),
460
+ /* @__PURE__ */ jsx(
461
+ "div",
462
+ {
463
+ className: cn(
464
+ "flex gap-3",
465
+ orientation === "vertical" ? "flex-col" : "flex-row flex-wrap"
466
+ ),
467
+ children: options.map((option) => {
468
+ const optionId = `${name}-${option.value}`;
469
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2.5", children: [
470
+ /* @__PURE__ */ jsx(
471
+ "input",
472
+ {
473
+ type: "radio",
474
+ id: optionId,
475
+ name,
476
+ value: option.value,
477
+ checked: value === option.value,
478
+ disabled: option.disabled,
479
+ onChange: () => onChange == null ? void 0 : onChange(option.value),
480
+ className: cn(
481
+ "h-4 w-4 shrink-0 mt-0.5 cursor-pointer appearance-none rounded-full border-2 transition-colors",
482
+ "border-(--color-neutral-300) bg-white",
483
+ "checked:border-(--color-primary-500) checked:bg-(--color-primary-500)",
484
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-primary-500)/20",
485
+ "disabled:cursor-not-allowed disabled:opacity-50",
486
+ error && "border-(--color-danger-500)"
487
+ ),
488
+ style: {
489
+ backgroundImage: value === option.value ? `url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")` : "none",
490
+ backgroundRepeat: "no-repeat",
491
+ backgroundPosition: "center"
492
+ }
493
+ }
494
+ ),
495
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
496
+ /* @__PURE__ */ jsx(
497
+ "label",
498
+ {
499
+ htmlFor: optionId,
500
+ className: cn(
501
+ "text-sm font-medium cursor-pointer text-(--color-neutral-900)",
502
+ option.disabled && "cursor-not-allowed opacity-50"
503
+ ),
504
+ children: option.label
505
+ }
506
+ ),
507
+ option.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-(--color-neutral-500)", children: option.description })
508
+ ] })
509
+ ] }, option.value);
510
+ })
511
+ }
512
+ ),
513
+ hint && !error && /* @__PURE__ */ jsx("p", { className: "text-xs text-(--color-neutral-500)", children: hint }),
514
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-(--color-danger-500)", children: error })
515
+ ] });
516
+ };
517
+ RadioGroup.displayName = "RadioGroup";
518
+ var Switch = React13.forwardRef(
519
+ ({ className, label, description, error, id, disabled, checked, defaultChecked, onChange, ...props }, ref) => {
520
+ const switchId = id != null ? id : `switch-${Math.random().toString(36).slice(2, 9)}`;
521
+ const [internalChecked, setInternalChecked] = React13.useState(
522
+ defaultChecked != null ? defaultChecked : false
523
+ );
524
+ const isControlled = checked !== void 0;
525
+ const isChecked = isControlled ? checked : internalChecked;
526
+ const handleChange = (e) => {
527
+ if (!isControlled) setInternalChecked(e.target.checked);
528
+ onChange == null ? void 0 : onChange(e);
529
+ };
530
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
531
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
532
+ /* @__PURE__ */ jsxs("div", { className: "relative inline-flex shrink-0 mt-0.5", children: [
533
+ /* @__PURE__ */ jsx(
534
+ "input",
535
+ {
536
+ ref,
537
+ type: "checkbox",
538
+ role: "switch",
539
+ id: switchId,
540
+ disabled,
541
+ checked: isChecked,
542
+ onChange: handleChange,
543
+ className: "sr-only peer",
544
+ ...props
545
+ }
546
+ ),
547
+ /* @__PURE__ */ jsx(
548
+ "label",
549
+ {
550
+ htmlFor: switchId,
551
+ className: cn(
552
+ "relative flex h-5 w-9 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
553
+ "bg-(--color-neutral-200) peer-checked:bg-(--color-primary-500)",
554
+ "peer-focus-visible:ring-2 peer-focus-visible:ring-(--color-primary-500)/20",
555
+ "peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
556
+ error && "ring-2 ring-(--color-danger-500)/20",
557
+ className
558
+ ),
559
+ children: /* @__PURE__ */ jsx(
560
+ "span",
561
+ {
562
+ className: "pointer-events-none block h-3.5 w-3.5 rounded-full bg-white shadow transition-transform",
563
+ style: {
564
+ transform: isChecked ? "translateX(18px)" : "translateX(2px)"
565
+ }
566
+ }
567
+ )
568
+ }
569
+ )
570
+ ] }),
571
+ (label || description) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
572
+ label && /* @__PURE__ */ jsx(
573
+ "span",
574
+ {
575
+ className: cn(
576
+ "text-sm font-medium text-(--color-neutral-900)",
577
+ disabled && "opacity-50"
578
+ ),
579
+ children: label
580
+ }
581
+ ),
582
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-(--color-neutral-500)", children: description })
583
+ ] })
584
+ ] }),
585
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-(--color-danger-500) ml-12", children: error })
586
+ ] });
587
+ }
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";
338
1113
 
339
- export { Avatar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Input, Separator, Spinner, avatarVariants, badgeVariants, buttonVariants, cardVariants, cn, colors, fontSize, inputVariants, radius, separatorVariants, spinnerVariants };
1114
+ export { Avatar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Drawer, DrawerBody, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, Input, Modal, ModalBody, ModalDescription, ModalFooter, ModalHeader, ModalTitle, Popover, RadioGroup, Select, Separator, Spinner, Switch, Tooltip, avatarVariants, badgeVariants, buttonVariants, cardVariants, cn, colors, drawerVariants, fontSize, inputVariants, modalVariants, radius, selectVariants, separatorVariants, spinnerVariants };
340
1115
  //# sourceMappingURL=index.mjs.map
341
1116
  //# sourceMappingURL=index.mjs.map