@facter/ds-core 1.33.10 → 1.33.11

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
@@ -17,10 +17,11 @@ import { toast as toast$1, Toaster as Toaster$1 } from 'sonner';
17
17
  import * as SwitchPrimitives from '@radix-ui/react-switch';
18
18
  import { FormProvider, useFormContext, Controller } from 'react-hook-form';
19
19
  export { FormProvider, useFormContext } from 'react-hook-form';
20
- import * as PopoverPrimitive2 from '@radix-ui/react-popover';
20
+ import { createPortal } from 'react-dom';
21
21
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
22
22
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
23
23
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
24
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
24
25
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
25
26
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
26
27
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
@@ -3447,7 +3448,13 @@ function FormSelect({
3447
3448
  {
3448
3449
  value: option.value,
3449
3450
  disabled: option.disabled,
3450
- children: option.label
3451
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3452
+ option.icon && /* @__PURE__ */ jsx(option.icon, { className: "h-4 w-4 text-muted-foreground" }),
3453
+ /* @__PURE__ */ jsxs("div", { children: [
3454
+ /* @__PURE__ */ jsx("span", { children: option.label }),
3455
+ option.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground ml-2", children: option.description })
3456
+ ] })
3457
+ ] })
3451
3458
  },
3452
3459
  option.value
3453
3460
  ))
@@ -3480,8 +3487,11 @@ function CardSelect({
3480
3487
  const [open, setOpen] = React10.useState(false);
3481
3488
  const [search, setSearch] = React10.useState("");
3482
3489
  const selected = options.find((o) => o.value === value);
3490
+ const containerRef = React10.useRef(null);
3491
+ const dropdownRef = React10.useRef(null);
3483
3492
  const listRef = React10.useRef(null);
3484
3493
  const searchRef = React10.useRef(null);
3494
+ const [dropdownPos, setDropdownPos] = React10.useState({});
3485
3495
  const filteredOptions = React10.useMemo(() => {
3486
3496
  if (!searchable || onSearch || !search) return options;
3487
3497
  const q = search.toLowerCase();
@@ -3496,16 +3506,76 @@ function CardSelect({
3496
3506
  },
3497
3507
  [onSearch]
3498
3508
  );
3499
- const handleOpenChange = React10.useCallback(
3500
- (nextOpen) => {
3501
- setOpen(nextOpen);
3502
- if (!nextOpen) {
3503
- setSearch("");
3504
- if (onSearch) onSearch("");
3509
+ React10.useEffect(() => {
3510
+ if (!open || !containerRef.current) return;
3511
+ const updatePosition = () => {
3512
+ const rect = containerRef.current.getBoundingClientRect();
3513
+ const spaceBelow = window.innerHeight - rect.bottom;
3514
+ const estimatedHeight = 340;
3515
+ const showAbove = spaceBelow < estimatedHeight && rect.top > spaceBelow;
3516
+ setDropdownPos({
3517
+ position: "fixed",
3518
+ left: rect.left,
3519
+ width: rect.width,
3520
+ zIndex: 9999,
3521
+ ...showAbove ? { bottom: window.innerHeight - rect.top + 4 } : { top: rect.bottom + 4 }
3522
+ });
3523
+ };
3524
+ updatePosition();
3525
+ window.addEventListener("scroll", updatePosition, true);
3526
+ window.addEventListener("resize", updatePosition);
3527
+ return () => {
3528
+ window.removeEventListener("scroll", updatePosition, true);
3529
+ window.removeEventListener("resize", updatePosition);
3530
+ };
3531
+ }, [open]);
3532
+ React10.useEffect(() => {
3533
+ if (!open) return;
3534
+ const handleClickOutside = (e) => {
3535
+ const target = e.target;
3536
+ if (containerRef.current && !containerRef.current.contains(target) && (!dropdownRef.current || !dropdownRef.current.contains(target))) {
3537
+ setOpen(false);
3505
3538
  }
3506
- },
3507
- [onSearch]
3508
- );
3539
+ };
3540
+ document.addEventListener("mousedown", handleClickOutside);
3541
+ return () => document.removeEventListener("mousedown", handleClickOutside);
3542
+ }, [open]);
3543
+ React10.useEffect(() => {
3544
+ if (!open) return;
3545
+ const handleEscape = (e) => {
3546
+ if (e.key === "Escape") setOpen(false);
3547
+ };
3548
+ document.addEventListener("keydown", handleEscape);
3549
+ return () => document.removeEventListener("keydown", handleEscape);
3550
+ }, [open]);
3551
+ React10.useEffect(() => {
3552
+ if (!open) {
3553
+ setSearch("");
3554
+ if (onSearch) onSearch("");
3555
+ }
3556
+ }, [open, onSearch]);
3557
+ React10.useEffect(() => {
3558
+ if (open && searchable) {
3559
+ setTimeout(() => searchRef.current?.focus(), 0);
3560
+ }
3561
+ }, [open, searchable]);
3562
+ React10.useEffect(() => {
3563
+ const el = listRef.current;
3564
+ if (!el || !open) return;
3565
+ const handleWheel = (e) => {
3566
+ const { scrollTop, scrollHeight, clientHeight } = el;
3567
+ const isScrollable = scrollHeight > clientHeight;
3568
+ if (!isScrollable) return;
3569
+ e.preventDefault();
3570
+ e.stopPropagation();
3571
+ el.scrollTop = Math.max(
3572
+ 0,
3573
+ Math.min(scrollTop + e.deltaY, scrollHeight - clientHeight)
3574
+ );
3575
+ };
3576
+ el.addEventListener("wheel", handleWheel, { passive: false, capture: true });
3577
+ return () => el.removeEventListener("wheel", handleWheel, { capture: true });
3578
+ }, [open, filteredOptions]);
3509
3579
  const handleScroll = React10.useCallback(() => {
3510
3580
  if (!onLoadMore || !hasMore || loading) return;
3511
3581
  const el = listRef.current;
@@ -3515,119 +3585,110 @@ function CardSelect({
3515
3585
  onLoadMore();
3516
3586
  }
3517
3587
  }, [onLoadMore, hasMore, loading]);
3518
- return /* @__PURE__ */ jsxs(PopoverPrimitive2.Root, { open, onOpenChange: handleOpenChange, children: [
3519
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3520
- /* @__PURE__ */ jsx(PopoverPrimitive2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
3521
- "button",
3522
- {
3523
- type: "button",
3524
- disabled,
3525
- className: cn(
3526
- "flex w-full items-center justify-between rounded-md border-2 bg-background px-3 text-sm transition-colors",
3527
- "focus:outline-none focus:border-primary",
3528
- "disabled:cursor-not-allowed disabled:opacity-50",
3529
- label ? "h-12 pt-4 pb-2" : "h-9 py-2",
3530
- error ? "border-red-500" : "border-border",
3531
- open && !error && "border-primary"
3532
- ),
3533
- children: [
3534
- selected ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate", children: [
3535
- selected.icon && /* @__PURE__ */ jsx(selected.icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3536
- /* @__PURE__ */ jsx("span", { className: "truncate", children: selected.label })
3537
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }),
3538
- /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 opacity-50 transition-transform", open && "rotate-180") })
3539
- ]
3540
- }
3541
- ) }),
3542
- label && /* @__PURE__ */ jsxs(
3543
- "label",
3544
- {
3545
- className: cn(
3546
- "absolute left-3 top-[-6px] text-xs font-medium bg-background px-1 pointer-events-none",
3547
- error ? "text-red-500" : "text-foreground"
3548
- ),
3549
- children: [
3550
- label,
3551
- required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-0.5", children: "*" })
3552
- ]
3553
- }
3554
- )
3555
- ] }),
3588
+ return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "relative", children: [
3556
3589
  /* @__PURE__ */ jsxs(
3557
- PopoverPrimitive2.Content,
3590
+ "button",
3558
3591
  {
3559
- align: "start",
3560
- sideOffset: 4,
3592
+ type: "button",
3593
+ disabled,
3594
+ onClick: () => setOpen((prev) => !prev),
3561
3595
  className: cn(
3562
- "z-50 rounded-md border bg-popover text-popover-foreground shadow-lg p-0 overflow-hidden",
3563
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2"
3596
+ "flex w-full items-center justify-between rounded-md border-2 bg-background px-3 text-sm transition-colors",
3597
+ "focus:outline-none focus:border-primary",
3598
+ "disabled:cursor-not-allowed disabled:opacity-50",
3599
+ label ? "h-12 pt-4 pb-2" : "h-9 py-2",
3600
+ error ? "border-red-500" : "border-border",
3601
+ open && !error && "border-primary"
3602
+ ),
3603
+ children: [
3604
+ selected ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate", children: [
3605
+ selected.icon && /* @__PURE__ */ jsx(selected.icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3606
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: selected.label })
3607
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }),
3608
+ /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 opacity-50 transition-transform", open && "rotate-180") })
3609
+ ]
3610
+ }
3611
+ ),
3612
+ label && /* @__PURE__ */ jsxs(
3613
+ "label",
3614
+ {
3615
+ className: cn(
3616
+ "absolute left-3 top-[-6px] text-xs font-medium bg-background px-1 pointer-events-none",
3617
+ error ? "text-red-500" : "text-foreground"
3564
3618
  ),
3565
- style: { width: "var(--radix-popover-trigger-width)" },
3566
- onOpenAutoFocus: (e) => {
3567
- e.preventDefault();
3568
- if (searchable) {
3569
- searchRef.current?.focus();
3570
- }
3571
- },
3572
3619
  children: [
3573
- searchable && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border", children: [
3574
- /* @__PURE__ */ jsx(Search, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3620
+ label,
3621
+ required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-0.5", children: "*" })
3622
+ ]
3623
+ }
3624
+ ),
3625
+ open && createPortal(
3626
+ /* @__PURE__ */ jsxs(
3627
+ "div",
3628
+ {
3629
+ ref: dropdownRef,
3630
+ style: dropdownPos,
3631
+ className: "rounded-md border border-border bg-popover shadow-md overflow-hidden animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-150",
3632
+ children: [
3633
+ searchable && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border", children: [
3634
+ /* @__PURE__ */ jsx(Search, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3635
+ /* @__PURE__ */ jsx(
3636
+ "input",
3637
+ {
3638
+ ref: searchRef,
3639
+ type: "text",
3640
+ value: search,
3641
+ onChange: (e) => handleSearch(e.target.value),
3642
+ placeholder: searchPlaceholder,
3643
+ className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
3644
+ }
3645
+ )
3646
+ ] }),
3575
3647
  /* @__PURE__ */ jsx(
3576
- "input",
3648
+ "div",
3577
3649
  {
3578
- ref: searchRef,
3579
- type: "text",
3580
- value: search,
3581
- onChange: (e) => handleSearch(e.target.value),
3582
- placeholder: searchPlaceholder,
3583
- className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
3650
+ ref: listRef,
3651
+ className: "overflow-y-auto overscroll-contain max-h-[300px]",
3652
+ onScroll: handleScroll,
3653
+ children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-border/50 p-2", children: [
3654
+ filteredOptions.length === 0 && !loading ? /* @__PURE__ */ jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: emptyText }) : filteredOptions.map((option) => {
3655
+ const isSelected = value === option.value;
3656
+ const isDisabled = option.disabled || disabled;
3657
+ return /* @__PURE__ */ jsxs(
3658
+ "button",
3659
+ {
3660
+ type: "button",
3661
+ disabled: isDisabled,
3662
+ onClick: () => {
3663
+ onChange(option.value);
3664
+ setOpen(false);
3665
+ },
3666
+ className: cn(
3667
+ "flex w-full items-center gap-3 p-3 text-left transition-all",
3668
+ "cursor-pointer hover:bg-accent",
3669
+ isSelected && "bg-primary/5",
3670
+ isDisabled && "cursor-not-allowed opacity-50 hover:bg-transparent"
3671
+ ),
3672
+ children: [
3673
+ option.icon && /* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsx(option.icon, { className: "h-3.5 w-3.5 text-primary" }) }),
3674
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3675
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium leading-tight", children: option.label }),
3676
+ option.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs leading-tight text-muted-foreground", children: option.description })
3677
+ ] }),
3678
+ isSelected && /* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground", children: /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) })
3679
+ ]
3680
+ },
3681
+ option.value
3682
+ );
3683
+ }),
3684
+ loading && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-3", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) })
3685
+ ] })
3584
3686
  }
3585
3687
  )
3586
- ] }),
3587
- /* @__PURE__ */ jsx(
3588
- "div",
3589
- {
3590
- ref: listRef,
3591
- className: "overflow-y-auto overscroll-contain",
3592
- style: { maxHeight: "min(300px, var(--radix-popover-content-available-height, 300px))" },
3593
- onScroll: handleScroll,
3594
- children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-border/50 p-2", children: [
3595
- filteredOptions.length === 0 && !loading ? /* @__PURE__ */ jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: emptyText }) : filteredOptions.map((option) => {
3596
- const isSelected = value === option.value;
3597
- const isDisabled = option.disabled || disabled;
3598
- return /* @__PURE__ */ jsxs(
3599
- "button",
3600
- {
3601
- type: "button",
3602
- disabled: isDisabled,
3603
- onClick: () => {
3604
- onChange(option.value);
3605
- handleOpenChange(false);
3606
- },
3607
- className: cn(
3608
- "flex w-full items-center gap-3 p-3 text-left transition-all",
3609
- "cursor-pointer hover:bg-accent",
3610
- isSelected && "bg-primary/5",
3611
- isDisabled && "cursor-not-allowed opacity-50 hover:bg-transparent"
3612
- ),
3613
- children: [
3614
- option.icon && /* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsx(option.icon, { className: "h-3.5 w-3.5 text-primary" }) }),
3615
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3616
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium leading-tight", children: option.label }),
3617
- option.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs leading-tight text-muted-foreground", children: option.description })
3618
- ] }),
3619
- isSelected && /* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground", children: /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) })
3620
- ]
3621
- },
3622
- option.value
3623
- );
3624
- }),
3625
- loading && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-3", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) })
3626
- ] })
3627
- }
3628
- )
3629
- ]
3630
- }
3688
+ ]
3689
+ }
3690
+ ),
3691
+ document.body
3631
3692
  )
3632
3693
  ] });
3633
3694
  }
@@ -4192,10 +4253,10 @@ var DropdownMenuShortcut = ({
4192
4253
  );
4193
4254
  };
4194
4255
  DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
4195
- var Popover = PopoverPrimitive2.Root;
4196
- var PopoverTrigger = PopoverPrimitive2.Trigger;
4197
- var PopoverContent = React10.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive2.Portal, { children: /* @__PURE__ */ jsx(
4198
- PopoverPrimitive2.Content,
4256
+ var Popover = PopoverPrimitive.Root;
4257
+ var PopoverTrigger = PopoverPrimitive.Trigger;
4258
+ var PopoverContent = React10.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
4259
+ PopoverPrimitive.Content,
4199
4260
  {
4200
4261
  ref,
4201
4262
  align,
@@ -4207,7 +4268,7 @@ var PopoverContent = React10.forwardRef(({ className, align = "center", sideOffs
4207
4268
  ...props
4208
4269
  }
4209
4270
  ) }));
4210
- PopoverContent.displayName = PopoverPrimitive2.Content.displayName;
4271
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
4211
4272
  var TooltipProvider = TooltipPrimitive.Provider;
4212
4273
  var TooltipRoot = TooltipPrimitive.Root;
4213
4274
  var TooltipTrigger = TooltipPrimitive.Trigger;