@memelabui/ui 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -999,7 +999,7 @@ function RadioGroup({
999
999
  ) });
1000
1000
  }
1001
1001
  function RadioItem({ value, disabled: itemDisabled, children, className }) {
1002
- const { value: groupValue, onChange, name, disabled: groupDisabled, groupId } = useRadioGroup();
1002
+ const { value: groupValue, onChange, name, disabled: groupDisabled } = useRadioGroup();
1003
1003
  const inputId = useId();
1004
1004
  const inputRef = useRef(null);
1005
1005
  const isDisabled = groupDisabled || itemDisabled;
@@ -1431,10 +1431,6 @@ function Tooltip({ content, delayMs = 500, placement = "top", className, childre
1431
1431
  const anchorRef = useRef(null);
1432
1432
  const [open, setOpen] = useState(false);
1433
1433
  const [pos, setPos] = useState(null);
1434
- useMemo(() => {
1435
- if (typeof content === "string") return content.trim();
1436
- return "";
1437
- }, [content]);
1438
1434
  const clearTimer = useCallback(() => {
1439
1435
  if (openTimerRef.current !== null) {
1440
1436
  window.clearTimeout(openTimerRef.current);
@@ -3470,5 +3466,793 @@ var NotificationBell = forwardRef(
3470
3466
  );
3471
3467
  }
3472
3468
  );
3469
+ var sizeClass7 = {
3470
+ xs: "text-sm font-semibold",
3471
+ sm: "text-base font-semibold",
3472
+ md: "text-lg font-bold",
3473
+ lg: "text-xl font-bold",
3474
+ xl: "text-2xl font-bold tracking-tight",
3475
+ "2xl": "text-3xl font-bold tracking-tight sm:text-4xl"
3476
+ };
3477
+ var levelToSize = {
3478
+ 1: "2xl",
3479
+ 2: "xl",
3480
+ 3: "lg",
3481
+ 4: "md",
3482
+ 5: "sm",
3483
+ 6: "xs"
3484
+ };
3485
+ var colorClass = {
3486
+ default: "text-white",
3487
+ muted: "text-white/70",
3488
+ gradient: "text-gradient"
3489
+ };
3490
+ var Heading = forwardRef(function Heading2({ level = 2, size, color = "default", className, ...props }, ref) {
3491
+ const Tag = `h${level}`;
3492
+ const effectiveSize = size ?? levelToSize[level];
3493
+ return /* @__PURE__ */ jsx(
3494
+ Tag,
3495
+ {
3496
+ ref,
3497
+ ...props,
3498
+ className: cn(sizeClass7[effectiveSize], colorClass[color], className)
3499
+ }
3500
+ );
3501
+ });
3502
+ var sizeMap2 = {
3503
+ xs: "text-xs",
3504
+ sm: "text-sm",
3505
+ md: "text-base",
3506
+ lg: "text-lg"
3507
+ };
3508
+ var colorMap = {
3509
+ default: "text-white/90",
3510
+ muted: "text-white/70",
3511
+ dimmed: "text-white/50",
3512
+ primary: "text-primary-light",
3513
+ success: "text-emerald-400",
3514
+ warning: "text-amber-400",
3515
+ danger: "text-rose-400"
3516
+ };
3517
+ var weightMap = {
3518
+ normal: "font-normal",
3519
+ medium: "font-medium",
3520
+ semibold: "font-semibold",
3521
+ bold: "font-bold"
3522
+ };
3523
+ var Text = forwardRef(function Text2({ size = "md", color = "default", weight = "normal", inline = false, truncate = false, className, ...props }, ref) {
3524
+ const Tag = inline ? "span" : "p";
3525
+ return /* @__PURE__ */ jsx(
3526
+ Tag,
3527
+ {
3528
+ ref,
3529
+ ...props,
3530
+ className: cn(
3531
+ sizeMap2[size],
3532
+ colorMap[color],
3533
+ weightMap[weight],
3534
+ truncate && "truncate",
3535
+ className
3536
+ )
3537
+ }
3538
+ );
3539
+ });
3540
+ var gapClass = {
3541
+ 0: "gap-0",
3542
+ 1: "gap-1",
3543
+ 2: "gap-2",
3544
+ 3: "gap-3",
3545
+ 4: "gap-4",
3546
+ 5: "gap-5",
3547
+ 6: "gap-6",
3548
+ 8: "gap-8",
3549
+ 10: "gap-10",
3550
+ 12: "gap-12"
3551
+ };
3552
+ var alignClass2 = {
3553
+ start: "items-start",
3554
+ center: "items-center",
3555
+ end: "items-end",
3556
+ stretch: "items-stretch",
3557
+ baseline: "items-baseline"
3558
+ };
3559
+ var justifyClass = {
3560
+ start: "justify-start",
3561
+ center: "justify-center",
3562
+ end: "justify-end",
3563
+ between: "justify-between",
3564
+ around: "justify-around",
3565
+ evenly: "justify-evenly"
3566
+ };
3567
+ var Stack = forwardRef(function Stack2({ children, direction = "vertical", gap = 4, align = "stretch", justify = "start", wrap = false, className, ...props }, ref) {
3568
+ return /* @__PURE__ */ jsx(
3569
+ "div",
3570
+ {
3571
+ ref,
3572
+ ...props,
3573
+ className: cn(
3574
+ "flex",
3575
+ direction === "vertical" ? "flex-col" : "flex-row",
3576
+ gapClass[gap],
3577
+ alignClass2[align],
3578
+ justifyClass[justify],
3579
+ wrap && "flex-wrap",
3580
+ className
3581
+ ),
3582
+ children
3583
+ }
3584
+ );
3585
+ });
3586
+ var ScrollArea = forwardRef(function ScrollArea2({ children, maxHeight, hideScrollbar = false, orientation = "vertical", className, style, ...props }, ref) {
3587
+ const overflowClass = {
3588
+ vertical: "overflow-y-auto overflow-x-hidden",
3589
+ horizontal: "overflow-x-auto overflow-y-hidden",
3590
+ both: "overflow-auto"
3591
+ }[orientation];
3592
+ return /* @__PURE__ */ jsx(
3593
+ "div",
3594
+ {
3595
+ ref,
3596
+ ...props,
3597
+ tabIndex: 0,
3598
+ className: cn(
3599
+ overflowClass,
3600
+ // Custom dark scrollbar styling
3601
+ "[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5",
3602
+ "[&::-webkit-scrollbar-track]:bg-transparent",
3603
+ "[&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-white/15 hover:[&::-webkit-scrollbar-thumb]:bg-white/25",
3604
+ hideScrollbar && "no-scrollbar",
3605
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/30 focus-visible:ring-inset",
3606
+ className
3607
+ ),
3608
+ style: {
3609
+ maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight,
3610
+ ...style
3611
+ },
3612
+ children
3613
+ }
3614
+ );
3615
+ });
3616
+ var defaultSeparator = /* @__PURE__ */ jsx(
3617
+ "svg",
3618
+ {
3619
+ className: "w-3.5 h-3.5 text-white/30 flex-shrink-0",
3620
+ viewBox: "0 0 16 16",
3621
+ fill: "none",
3622
+ stroke: "currentColor",
3623
+ strokeWidth: "2",
3624
+ strokeLinecap: "round",
3625
+ "aria-hidden": "true",
3626
+ children: /* @__PURE__ */ jsx("path", { d: "M6 4l4 4-4 4" })
3627
+ }
3628
+ );
3629
+ function Breadcrumbs({ items, separator = defaultSeparator, className }) {
3630
+ if (items.length === 0) return null;
3631
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: cn("flex items-center", className), children: /* @__PURE__ */ jsx("ol", { className: "flex items-center gap-1.5 text-sm", children: items.map((item, index) => {
3632
+ const isLast = index === items.length - 1;
3633
+ return /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1.5", children: [
3634
+ index > 0 && separator,
3635
+ isLast ? /* @__PURE__ */ jsx("span", { className: "text-white font-medium", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsx(
3636
+ "a",
3637
+ {
3638
+ href: item.href,
3639
+ onClick: item.onClick,
3640
+ className: "text-white/50 hover:text-white/80 transition-colors",
3641
+ children: item.label
3642
+ }
3643
+ ) : item.onClick ? /* @__PURE__ */ jsx(
3644
+ "button",
3645
+ {
3646
+ type: "button",
3647
+ onClick: item.onClick,
3648
+ className: "text-white/50 hover:text-white/80 transition-colors",
3649
+ children: item.label
3650
+ }
3651
+ ) : /* @__PURE__ */ jsx("span", { className: "text-white/50", children: item.label })
3652
+ ] }, index);
3653
+ }) }) });
3654
+ }
3655
+ function Popover({
3656
+ content,
3657
+ children,
3658
+ placement = "bottom",
3659
+ closeOnClickOutside = true,
3660
+ closeOnEsc = true,
3661
+ open: controlledOpen,
3662
+ onOpenChange,
3663
+ offset = 8,
3664
+ className
3665
+ }) {
3666
+ const popoverId = useId();
3667
+ const anchorRef = useRef(null);
3668
+ const popoverRef = useRef(null);
3669
+ const [internalOpen, setInternalOpen] = useState(false);
3670
+ const [pos, setPos] = useState(null);
3671
+ const isControlled = controlledOpen !== void 0;
3672
+ const isOpen = isControlled ? controlledOpen : internalOpen;
3673
+ const setOpen = useCallback(
3674
+ (value) => {
3675
+ if (!isControlled) setInternalOpen(value);
3676
+ onOpenChange?.(value);
3677
+ },
3678
+ [isControlled, onOpenChange]
3679
+ );
3680
+ const toggle = useCallback(() => setOpen(!isOpen), [isOpen, setOpen]);
3681
+ const close = useCallback(() => setOpen(false), [setOpen]);
3682
+ const updatePosition = useCallback(() => {
3683
+ const el = anchorRef.current;
3684
+ if (!el) return;
3685
+ const r = el.getBoundingClientRect();
3686
+ let left;
3687
+ let top;
3688
+ let effPlacement = placement;
3689
+ if (placement === "bottom" || placement === "top") {
3690
+ left = r.left + r.width / 2;
3691
+ if (placement === "bottom") {
3692
+ top = r.bottom + offset;
3693
+ if (top + 200 > window.innerHeight && r.top - offset > 200) {
3694
+ effPlacement = "top";
3695
+ top = r.top - offset;
3696
+ }
3697
+ } else {
3698
+ top = r.top - offset;
3699
+ if (top < 8) {
3700
+ effPlacement = "bottom";
3701
+ top = r.bottom + offset;
3702
+ }
3703
+ }
3704
+ } else {
3705
+ top = r.top + r.height / 2;
3706
+ if (placement === "right") {
3707
+ left = r.right + offset;
3708
+ } else {
3709
+ left = r.left - offset;
3710
+ }
3711
+ }
3712
+ setPos({ left: Math.round(left), top: Math.round(top), placement: effPlacement });
3713
+ }, [placement, offset]);
3714
+ useEffect(() => {
3715
+ if (!isOpen) return;
3716
+ updatePosition();
3717
+ window.addEventListener("scroll", updatePosition, true);
3718
+ window.addEventListener("resize", updatePosition);
3719
+ return () => {
3720
+ window.removeEventListener("scroll", updatePosition, true);
3721
+ window.removeEventListener("resize", updatePosition);
3722
+ };
3723
+ }, [isOpen, updatePosition]);
3724
+ useEffect(() => {
3725
+ if (!isOpen || !closeOnClickOutside) return;
3726
+ const handleClick = (e) => {
3727
+ const target = e.target;
3728
+ if (anchorRef.current?.contains(target) || popoverRef.current?.contains(target)) {
3729
+ return;
3730
+ }
3731
+ close();
3732
+ };
3733
+ document.addEventListener("mousedown", handleClick);
3734
+ return () => document.removeEventListener("mousedown", handleClick);
3735
+ }, [isOpen, closeOnClickOutside, close]);
3736
+ useEffect(() => {
3737
+ if (!isOpen || !closeOnEsc) return;
3738
+ const handleKey = (e) => {
3739
+ if (e.key === "Escape") {
3740
+ e.preventDefault();
3741
+ close();
3742
+ anchorRef.current?.focus();
3743
+ }
3744
+ };
3745
+ document.addEventListener("keydown", handleKey);
3746
+ return () => document.removeEventListener("keydown", handleKey);
3747
+ }, [isOpen, closeOnEsc, close]);
3748
+ if (!isValidElement(children)) return children;
3749
+ const child = cloneElement(children, {
3750
+ ref: (node) => {
3751
+ anchorRef.current = node;
3752
+ const childProps = children.props;
3753
+ const prevRef = childProps.ref;
3754
+ if (typeof prevRef === "function") prevRef(node);
3755
+ else if (prevRef && typeof prevRef === "object") prevRef.current = node;
3756
+ },
3757
+ onClick: (e) => {
3758
+ const childProps = children.props;
3759
+ if (typeof childProps.onClick === "function") childProps.onClick(e);
3760
+ toggle();
3761
+ },
3762
+ "aria-expanded": isOpen,
3763
+ "aria-haspopup": "dialog",
3764
+ "aria-controls": isOpen ? popoverId : void 0
3765
+ });
3766
+ const getTransform = () => {
3767
+ if (!pos) return "translate(-9999px, -9999px)";
3768
+ switch (pos.placement) {
3769
+ case "top":
3770
+ return "translate(-50%, -100%)";
3771
+ case "bottom":
3772
+ return "translate(-50%, 0%)";
3773
+ case "left":
3774
+ return "translate(-100%, -50%)";
3775
+ case "right":
3776
+ return "translate(0%, -50%)";
3777
+ }
3778
+ };
3779
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3780
+ child,
3781
+ isOpen && typeof document !== "undefined" ? createPortal(
3782
+ /* @__PURE__ */ jsx(
3783
+ "div",
3784
+ {
3785
+ ref: popoverRef,
3786
+ id: popoverId,
3787
+ role: "dialog",
3788
+ className: cn(
3789
+ "fixed z-[9999] rounded-xl shadow-xl ring-1 ring-white/10 bg-surface-50 backdrop-blur-md p-4",
3790
+ className
3791
+ ),
3792
+ style: {
3793
+ left: pos?.left ?? 0,
3794
+ top: pos?.top ?? 0,
3795
+ transform: getTransform()
3796
+ },
3797
+ children: content
3798
+ }
3799
+ ),
3800
+ document.body
3801
+ ) : null
3802
+ ] });
3803
+ }
3804
+ var scrollLockCount2 = 0;
3805
+ var savedOverflow2 = "";
3806
+ function lockScroll2() {
3807
+ if (typeof document === "undefined") return;
3808
+ if (scrollLockCount2 === 0) {
3809
+ savedOverflow2 = document.body.style.overflow;
3810
+ document.body.style.overflow = "hidden";
3811
+ }
3812
+ scrollLockCount2++;
3813
+ }
3814
+ function unlockScroll2() {
3815
+ if (typeof document === "undefined") return;
3816
+ scrollLockCount2 = Math.max(0, scrollLockCount2 - 1);
3817
+ if (scrollLockCount2 === 0) {
3818
+ document.body.style.overflow = savedOverflow2;
3819
+ }
3820
+ }
3821
+ var sizeClass8 = {
3822
+ left: { sm: "w-64", md: "w-80", lg: "w-96", full: "w-screen" },
3823
+ right: { sm: "w-64", md: "w-80", lg: "w-96", full: "w-screen" },
3824
+ bottom: { sm: "h-1/4", md: "h-1/3", lg: "h-1/2", full: "h-screen" }
3825
+ };
3826
+ var positionClass2 = {
3827
+ left: "inset-y-0 left-0",
3828
+ right: "inset-y-0 right-0",
3829
+ bottom: "inset-x-0 bottom-0"
3830
+ };
3831
+ var slideIn = {
3832
+ left: "translate-x-0",
3833
+ right: "translate-x-0",
3834
+ bottom: "translate-y-0"
3835
+ };
3836
+ var slideOut = {
3837
+ left: "-translate-x-full",
3838
+ right: "translate-x-full",
3839
+ bottom: "translate-y-full"
3840
+ };
3841
+ function Drawer({
3842
+ isOpen,
3843
+ onClose,
3844
+ children,
3845
+ side = "right",
3846
+ size = "md",
3847
+ ariaLabel,
3848
+ closeOnBackdrop = true,
3849
+ closeOnEsc = true,
3850
+ className
3851
+ }) {
3852
+ const panelRef = useRef(null);
3853
+ const lastActiveRef = useRef(null);
3854
+ useEffect(() => {
3855
+ if (!isOpen) return;
3856
+ lastActiveRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
3857
+ const raf = requestAnimationFrame(() => {
3858
+ const el = panelRef.current;
3859
+ if (!el) return;
3860
+ const focusables = getFocusableElements(el);
3861
+ focusSafely(focusables[0] ?? el);
3862
+ });
3863
+ return () => {
3864
+ cancelAnimationFrame(raf);
3865
+ const lastActive = lastActiveRef.current;
3866
+ lastActiveRef.current = null;
3867
+ if (lastActive?.isConnected) focusSafely(lastActive);
3868
+ };
3869
+ }, [isOpen]);
3870
+ useEffect(() => {
3871
+ if (!isOpen) return;
3872
+ lockScroll2();
3873
+ return () => unlockScroll2();
3874
+ }, [isOpen]);
3875
+ if (!isOpen) return null;
3876
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50", role: "presentation", children: [
3877
+ /* @__PURE__ */ jsx(
3878
+ "div",
3879
+ {
3880
+ className: "absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity duration-200",
3881
+ "aria-hidden": "true",
3882
+ onClick: closeOnBackdrop ? onClose : void 0
3883
+ }
3884
+ ),
3885
+ /* @__PURE__ */ jsx(
3886
+ "div",
3887
+ {
3888
+ ref: panelRef,
3889
+ role: "dialog",
3890
+ "aria-modal": "true",
3891
+ "aria-label": ariaLabel,
3892
+ tabIndex: -1,
3893
+ className: cn(
3894
+ "fixed flex flex-col bg-surface-50 shadow-2xl ring-1 ring-white/10 transition-transform duration-300 ease-out focus:outline-none",
3895
+ positionClass2[side],
3896
+ sizeClass8[side][size],
3897
+ isOpen ? slideIn[side] : slideOut[side],
3898
+ className
3899
+ ),
3900
+ onKeyDownCapture: (e) => {
3901
+ if (closeOnEsc && e.key === "Escape") {
3902
+ e.preventDefault();
3903
+ e.stopPropagation();
3904
+ onClose();
3905
+ return;
3906
+ }
3907
+ if (e.key !== "Tab") return;
3908
+ const el = panelRef.current;
3909
+ if (!el) return;
3910
+ const focusables = getFocusableElements(el);
3911
+ if (focusables.length === 0) {
3912
+ e.preventDefault();
3913
+ focusSafely(el);
3914
+ return;
3915
+ }
3916
+ const active = document.activeElement;
3917
+ const first = focusables[0];
3918
+ const last = focusables[focusables.length - 1];
3919
+ if (e.shiftKey) {
3920
+ if (active === first) {
3921
+ e.preventDefault();
3922
+ focusSafely(last);
3923
+ }
3924
+ } else {
3925
+ if (active === last) {
3926
+ e.preventDefault();
3927
+ focusSafely(first);
3928
+ }
3929
+ }
3930
+ },
3931
+ children
3932
+ }
3933
+ )
3934
+ ] });
3935
+ }
3936
+ var defaultFilter = (opt, q) => opt.label.toLowerCase().includes(q.toLowerCase());
3937
+ var Combobox = forwardRef(function Combobox2({
3938
+ options,
3939
+ value,
3940
+ onChange,
3941
+ placeholder,
3942
+ label,
3943
+ error,
3944
+ allowCustom = false,
3945
+ filterFn = defaultFilter,
3946
+ emptyContent,
3947
+ disabled,
3948
+ className,
3949
+ id: externalId
3950
+ }, ref) {
3951
+ const generatedId = useId();
3952
+ const inputId = externalId || generatedId;
3953
+ const listboxId = `${inputId}-listbox`;
3954
+ const [query, setQuery] = useState("");
3955
+ const [open, setOpen] = useState(false);
3956
+ const [activeIndex, setActiveIndex] = useState(-1);
3957
+ const inputRef = useRef(null);
3958
+ const listRef = useRef(null);
3959
+ const containerRef = useRef(null);
3960
+ const [listPos, setListPos] = useState(null);
3961
+ useEffect(() => {
3962
+ if (value !== void 0) {
3963
+ const opt = options.find((o) => o.value === value);
3964
+ setQuery(opt ? opt.label : value);
3965
+ }
3966
+ }, [value, options]);
3967
+ const filtered = useMemo(() => {
3968
+ if (!query) return options;
3969
+ return options.filter((opt) => filterFn(opt, query));
3970
+ }, [options, query, filterFn]);
3971
+ const enabledFiltered = useMemo(
3972
+ () => filtered.filter((o) => !o.disabled),
3973
+ [filtered]
3974
+ );
3975
+ const updatePosition = useCallback(() => {
3976
+ const el = containerRef.current;
3977
+ if (!el) return;
3978
+ const r = el.getBoundingClientRect();
3979
+ setListPos({
3980
+ left: r.left,
3981
+ top: r.bottom + 4,
3982
+ width: r.width
3983
+ });
3984
+ }, []);
3985
+ useEffect(() => {
3986
+ if (!open) return;
3987
+ updatePosition();
3988
+ window.addEventListener("scroll", updatePosition, true);
3989
+ window.addEventListener("resize", updatePosition);
3990
+ return () => {
3991
+ window.removeEventListener("scroll", updatePosition, true);
3992
+ window.removeEventListener("resize", updatePosition);
3993
+ };
3994
+ }, [open, updatePosition]);
3995
+ useEffect(() => {
3996
+ if (!open) return;
3997
+ const handleClick = (e) => {
3998
+ const target = e.target;
3999
+ if (containerRef.current?.contains(target) || listRef.current?.contains(target)) return;
4000
+ setOpen(false);
4001
+ };
4002
+ document.addEventListener("mousedown", handleClick);
4003
+ return () => document.removeEventListener("mousedown", handleClick);
4004
+ }, [open]);
4005
+ const selectOption = useCallback(
4006
+ (opt) => {
4007
+ setQuery(opt.label);
4008
+ onChange?.(opt.value);
4009
+ setOpen(false);
4010
+ setActiveIndex(-1);
4011
+ inputRef.current?.focus();
4012
+ },
4013
+ [onChange]
4014
+ );
4015
+ const handleInputChange = (e) => {
4016
+ const v = e.target.value;
4017
+ setQuery(v);
4018
+ setOpen(true);
4019
+ setActiveIndex(-1);
4020
+ if (allowCustom) onChange?.(v);
4021
+ };
4022
+ const handleKeyDown = (e) => {
4023
+ if (e.key === "ArrowDown") {
4024
+ e.preventDefault();
4025
+ if (!open) {
4026
+ setOpen(true);
4027
+ return;
4028
+ }
4029
+ setActiveIndex((i) => {
4030
+ const next = i + 1;
4031
+ return next >= enabledFiltered.length ? 0 : next;
4032
+ });
4033
+ } else if (e.key === "ArrowUp") {
4034
+ e.preventDefault();
4035
+ if (!open) {
4036
+ setOpen(true);
4037
+ return;
4038
+ }
4039
+ setActiveIndex((i) => {
4040
+ const prev = i - 1;
4041
+ return prev < 0 ? enabledFiltered.length - 1 : prev;
4042
+ });
4043
+ } else if (e.key === "Enter") {
4044
+ e.preventDefault();
4045
+ if (open && activeIndex >= 0 && enabledFiltered[activeIndex]) {
4046
+ selectOption(enabledFiltered[activeIndex]);
4047
+ }
4048
+ } else if (e.key === "Escape") {
4049
+ if (open) {
4050
+ e.preventDefault();
4051
+ setOpen(false);
4052
+ setActiveIndex(-1);
4053
+ }
4054
+ }
4055
+ };
4056
+ useEffect(() => {
4057
+ if (activeIndex < 0 || !listRef.current) return;
4058
+ const items = listRef.current.querySelectorAll('[role="option"]:not([aria-disabled="true"])');
4059
+ const item = items[activeIndex];
4060
+ if (item && typeof item.scrollIntoView === "function") {
4061
+ item.scrollIntoView({ block: "nearest" });
4062
+ }
4063
+ }, [activeIndex]);
4064
+ const activeOptionId = activeIndex >= 0 ? `${inputId}-opt-${activeIndex}` : void 0;
4065
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full", className), children: [
4066
+ label && /* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "block text-sm text-white/70 mb-1.5", children: label }),
4067
+ /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "relative", children: [
4068
+ /* @__PURE__ */ jsx(
4069
+ "input",
4070
+ {
4071
+ ref: (node) => {
4072
+ inputRef.current = node;
4073
+ if (typeof ref === "function") ref(node);
4074
+ else if (ref) ref.current = node;
4075
+ },
4076
+ id: inputId,
4077
+ type: "text",
4078
+ role: "combobox",
4079
+ "aria-expanded": open,
4080
+ "aria-controls": listboxId,
4081
+ "aria-activedescendant": activeOptionId,
4082
+ "aria-autocomplete": "list",
4083
+ autoComplete: "off",
4084
+ disabled,
4085
+ placeholder,
4086
+ value: query,
4087
+ onChange: handleInputChange,
4088
+ onFocus: () => setOpen(true),
4089
+ onKeyDown: handleKeyDown,
4090
+ className: cn(
4091
+ "w-full rounded-xl px-3 py-2.5 text-sm bg-white/10 text-white shadow-sm outline-none placeholder-white/30 focus-visible:ring-2 focus-visible:ring-primary/40 transition-shadow",
4092
+ error && "ring-1 ring-rose-500/50",
4093
+ disabled && "opacity-50 cursor-not-allowed"
4094
+ )
4095
+ }
4096
+ ),
4097
+ /* @__PURE__ */ jsx(
4098
+ "button",
4099
+ {
4100
+ type: "button",
4101
+ tabIndex: -1,
4102
+ "aria-hidden": "true",
4103
+ onClick: () => {
4104
+ if (!disabled) {
4105
+ setOpen(!open);
4106
+ inputRef.current?.focus();
4107
+ }
4108
+ },
4109
+ className: "absolute right-2 top-1/2 -translate-y-1/2 text-white/40 hover:text-white/60 p-1",
4110
+ children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx("path", { d: "M4 6l4 4 4-4" }) })
4111
+ }
4112
+ )
4113
+ ] }),
4114
+ error && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-rose-400", children: error }),
4115
+ open && typeof document !== "undefined" ? createPortal(
4116
+ /* @__PURE__ */ jsx(
4117
+ "ul",
4118
+ {
4119
+ ref: listRef,
4120
+ id: listboxId,
4121
+ role: "listbox",
4122
+ className: "fixed z-[9999] max-h-60 overflow-auto rounded-xl bg-surface-50 shadow-xl ring-1 ring-white/10 py-1 backdrop-blur-md",
4123
+ style: {
4124
+ left: listPos?.left ?? 0,
4125
+ top: listPos?.top ?? 0,
4126
+ width: listPos?.width ?? 0
4127
+ },
4128
+ children: filtered.length === 0 ? /* @__PURE__ */ jsx("li", { className: "px-3 py-2 text-sm text-white/40", children: emptyContent ?? "No results" }) : filtered.map((opt) => {
4129
+ const enabledIndex = enabledFiltered.indexOf(opt);
4130
+ const isActive = enabledIndex === activeIndex;
4131
+ return /* @__PURE__ */ jsx(
4132
+ "li",
4133
+ {
4134
+ id: isActive ? activeOptionId : void 0,
4135
+ role: "option",
4136
+ "aria-selected": opt.value === value,
4137
+ "aria-disabled": opt.disabled || void 0,
4138
+ className: cn(
4139
+ "px-3 py-2 text-sm cursor-pointer transition-colors",
4140
+ isActive && "bg-white/10",
4141
+ opt.value === value && "text-primary-light",
4142
+ opt.disabled && "opacity-40 cursor-not-allowed",
4143
+ !opt.disabled && !isActive && "text-white hover:bg-white/5"
4144
+ ),
4145
+ onMouseDown: (e) => {
4146
+ e.preventDefault();
4147
+ if (!opt.disabled) selectOption(opt);
4148
+ },
4149
+ onMouseEnter: () => {
4150
+ if (!opt.disabled) setActiveIndex(enabledIndex);
4151
+ },
4152
+ children: opt.label
4153
+ },
4154
+ opt.value
4155
+ );
4156
+ })
4157
+ }
4158
+ ),
4159
+ document.body
4160
+ ) : null
4161
+ ] });
4162
+ });
4163
+ var presetStyles = {
4164
+ fade: {
4165
+ enter: "opacity-100",
4166
+ exit: "opacity-0"
4167
+ },
4168
+ "fade-up": {
4169
+ enter: "opacity-100 translate-y-0",
4170
+ exit: "opacity-0 translate-y-2"
4171
+ },
4172
+ "fade-down": {
4173
+ enter: "opacity-100 translate-y-0",
4174
+ exit: "opacity-0 -translate-y-2"
4175
+ },
4176
+ scale: {
4177
+ enter: "opacity-100 scale-100",
4178
+ exit: "opacity-0 scale-95"
4179
+ },
4180
+ "slide-right": {
4181
+ enter: "translate-x-0",
4182
+ exit: "translate-x-full"
4183
+ },
4184
+ "slide-left": {
4185
+ enter: "translate-x-0",
4186
+ exit: "-translate-x-full"
4187
+ }
4188
+ };
4189
+ function Transition({
4190
+ show,
4191
+ children,
4192
+ preset = "fade",
4193
+ duration = 200,
4194
+ unmountOnHide = true,
4195
+ className
4196
+ }) {
4197
+ const [mounted, setMounted] = useState(show);
4198
+ const [entering, setEntering] = useState(false);
4199
+ const timerRef = useRef(null);
4200
+ useEffect(() => {
4201
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
4202
+ if (show) {
4203
+ setMounted(true);
4204
+ requestAnimationFrame(() => {
4205
+ requestAnimationFrame(() => setEntering(true));
4206
+ });
4207
+ } else {
4208
+ setEntering(false);
4209
+ if (unmountOnHide) {
4210
+ timerRef.current = setTimeout(() => {
4211
+ setMounted(false);
4212
+ timerRef.current = null;
4213
+ }, duration);
4214
+ }
4215
+ }
4216
+ return () => {
4217
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
4218
+ };
4219
+ }, [show, duration, unmountOnHide]);
4220
+ if (!mounted) return null;
4221
+ const styles = presetStyles[preset];
4222
+ return /* @__PURE__ */ jsx(
4223
+ "div",
4224
+ {
4225
+ className: cn(
4226
+ "transition-all",
4227
+ entering ? styles.enter : styles.exit,
4228
+ className
4229
+ ),
4230
+ style: { transitionDuration: `${duration}ms` },
4231
+ "aria-hidden": !show,
4232
+ children
4233
+ }
4234
+ );
4235
+ }
4236
+ function VisuallyHidden({ children, as: Tag = "span", style, ...props }) {
4237
+ return /* @__PURE__ */ jsx(
4238
+ Tag,
4239
+ {
4240
+ ...props,
4241
+ style: {
4242
+ position: "absolute",
4243
+ width: 1,
4244
+ height: 1,
4245
+ padding: 0,
4246
+ margin: -1,
4247
+ overflow: "hidden",
4248
+ clip: "rect(0,0,0,0)",
4249
+ whiteSpace: "nowrap",
4250
+ borderWidth: 0,
4251
+ ...style
4252
+ },
4253
+ children
4254
+ }
4255
+ );
4256
+ }
3473
4257
 
3474
- export { ActiveFilterPills, Alert, Avatar, Badge, Button, Card, Checkbox, CollapsibleSection, ColorInput, ConfirmDialog, CooldownRing, CopyField, DashboardLayout, Divider, DotIndicator, DropZone, Dropdown, DropdownItem, DropdownMenu, DropdownSeparator, DropdownTrigger, EmptyState, FormField, IconButton, Input, Modal, MutationOverlay, Navbar, NotificationBell, PageShell, Pagination, Pill, ProgressBar, ProgressButton, RadioGroup, RadioItem, SearchInput, SectionCard, Select, Sidebar, Skeleton, Slider, Spinner, StageProgress, StatCard, Stepper, Tab, TabList, TabPanel, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TagInput, Textarea, ToastProvider, Toggle, Tooltip, cn, colors, focusSafely, getFocusableElements, useClipboard, useDebounce, useDisclosure, useHotkeys, useIntersectionObserver, useMediaQuery, useSharedNow, useToast };
4258
+ export { ActiveFilterPills, Alert, Avatar, Badge, Breadcrumbs, Button, Card, Checkbox, CollapsibleSection, ColorInput, Combobox, ConfirmDialog, CooldownRing, CopyField, DashboardLayout, Divider, DotIndicator, Drawer, DropZone, Dropdown, DropdownItem, DropdownMenu, DropdownSeparator, DropdownTrigger, EmptyState, FormField, Heading, IconButton, Input, Modal, MutationOverlay, Navbar, NotificationBell, PageShell, Pagination, Pill, Popover, ProgressBar, ProgressButton, RadioGroup, RadioItem, ScrollArea, SearchInput, SectionCard, Select, Sidebar, Skeleton, Slider, Spinner, Stack, StageProgress, StatCard, Stepper, Tab, TabList, TabPanel, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TagInput, Text, Textarea, ToastProvider, Toggle, Tooltip, Transition, VisuallyHidden, cn, colors, focusSafely, getFocusableElements, useClipboard, useDebounce, useDisclosure, useHotkeys, useIntersectionObserver, useMediaQuery, useSharedNow, useToast };