@facter/ds-core 1.33.5 → 1.33.7

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,11 +17,10 @@ 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 { createPortal } from 'react-dom';
20
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
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';
25
24
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
26
25
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
27
26
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
@@ -638,15 +637,15 @@ var SelectItem = React10.forwardRef(({ className, children, ...props }, ref) =>
638
637
  {
639
638
  ref,
640
639
  className: cn(
641
- "relative flex w-full cursor-pointer select-none items-center justify-between rounded-sm py-1.5 px-3 text-sm outline-none",
640
+ "relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
642
641
  "focus:bg-accent focus:text-accent-foreground",
643
642
  "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
644
643
  className
645
644
  ),
646
645
  ...props,
647
646
  children: [
648
- /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children }),
649
- /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center ml-2", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 text-primary" }) }) })
647
+ /* @__PURE__ */ jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
648
+ /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
650
649
  ]
651
650
  }
652
651
  ));
@@ -3380,6 +3379,22 @@ function FormInput({
3380
3379
  ) });
3381
3380
  }
3382
3381
  FormInput.displayName = "Form.Input";
3382
+ var Popover = PopoverPrimitive.Root;
3383
+ var PopoverTrigger = PopoverPrimitive.Trigger;
3384
+ var PopoverContent = React10.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
3385
+ PopoverPrimitive.Content,
3386
+ {
3387
+ ref,
3388
+ align,
3389
+ sideOffset,
3390
+ className: cn(
3391
+ "z-50 w-auto rounded-md border bg-popover p-4 text-popover-foreground shadow-lg outline-none 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=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
3392
+ className
3393
+ ),
3394
+ ...props
3395
+ }
3396
+ ) }));
3397
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
3383
3398
  function FormSelect({
3384
3399
  name,
3385
3400
  label,
@@ -3448,13 +3463,7 @@ function FormSelect({
3448
3463
  {
3449
3464
  value: option.value,
3450
3465
  disabled: option.disabled,
3451
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
3452
- 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" }) }),
3453
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3454
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium leading-tight", children: option.label }),
3455
- option.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs leading-tight text-muted-foreground", children: option.description })
3456
- ] })
3457
- ] })
3466
+ children: option.label
3458
3467
  },
3459
3468
  option.value
3460
3469
  ))
@@ -3487,12 +3496,8 @@ function CardSelect({
3487
3496
  const [open, setOpen] = React10.useState(false);
3488
3497
  const [search, setSearch] = React10.useState("");
3489
3498
  const selected = options.find((o) => o.value === value);
3490
- const containerRef = React10.useRef(null);
3491
- const dropdownRef = React10.useRef(null);
3492
3499
  const listRef = React10.useRef(null);
3493
3500
  const searchRef = React10.useRef(null);
3494
- const [dropdownPos, setDropdownPos] = React10.useState({});
3495
- const [listMaxHeight, setListMaxHeight] = React10.useState(300);
3496
3501
  const filteredOptions = React10.useMemo(() => {
3497
3502
  if (!searchable || onSearch || !search) return options;
3498
3503
  const q = search.toLowerCase();
@@ -3507,81 +3512,16 @@ function CardSelect({
3507
3512
  },
3508
3513
  [onSearch]
3509
3514
  );
3510
- React10.useEffect(() => {
3511
- if (!open || !containerRef.current) return;
3512
- const updatePosition = () => {
3513
- const rect = containerRef.current.getBoundingClientRect();
3514
- const margin = 8;
3515
- const searchBarHeight = searchable ? 41 : 0;
3516
- const spaceBelow = window.innerHeight - rect.bottom - margin;
3517
- const spaceAbove = rect.top - margin;
3518
- const showAbove = spaceBelow < 150 && spaceAbove > spaceBelow;
3519
- const availableSpace = showAbove ? spaceAbove : spaceBelow;
3520
- const maxList = Math.max(Math.min(availableSpace - searchBarHeight - margin, 300), 100);
3521
- setListMaxHeight(maxList);
3522
- setDropdownPos({
3523
- position: "fixed",
3524
- left: rect.left,
3525
- width: rect.width,
3526
- zIndex: 9999,
3527
- ...showAbove ? { bottom: window.innerHeight - rect.top + 4 } : { top: rect.bottom + 4 }
3528
- });
3529
- };
3530
- updatePosition();
3531
- window.addEventListener("scroll", updatePosition, true);
3532
- window.addEventListener("resize", updatePosition);
3533
- return () => {
3534
- window.removeEventListener("scroll", updatePosition, true);
3535
- window.removeEventListener("resize", updatePosition);
3536
- };
3537
- }, [open, searchable]);
3538
- React10.useEffect(() => {
3539
- if (!open) return;
3540
- const handleClickOutside = (e) => {
3541
- const target = e.target;
3542
- if (containerRef.current && !containerRef.current.contains(target) && (!dropdownRef.current || !dropdownRef.current.contains(target))) {
3543
- setOpen(false);
3515
+ const handleOpenChange = React10.useCallback(
3516
+ (nextOpen) => {
3517
+ setOpen(nextOpen);
3518
+ if (!nextOpen) {
3519
+ setSearch("");
3520
+ if (onSearch) onSearch("");
3544
3521
  }
3545
- };
3546
- document.addEventListener("mousedown", handleClickOutside);
3547
- return () => document.removeEventListener("mousedown", handleClickOutside);
3548
- }, [open]);
3549
- React10.useEffect(() => {
3550
- if (!open) return;
3551
- const handleEscape = (e) => {
3552
- if (e.key === "Escape") setOpen(false);
3553
- };
3554
- document.addEventListener("keydown", handleEscape);
3555
- return () => document.removeEventListener("keydown", handleEscape);
3556
- }, [open]);
3557
- React10.useEffect(() => {
3558
- if (!open) {
3559
- setSearch("");
3560
- if (onSearch) onSearch("");
3561
- }
3562
- }, [open, onSearch]);
3563
- React10.useEffect(() => {
3564
- if (open && searchable) {
3565
- setTimeout(() => searchRef.current?.focus(), 0);
3566
- }
3567
- }, [open, searchable]);
3568
- React10.useEffect(() => {
3569
- const el = listRef.current;
3570
- if (!el || !open) return;
3571
- const handleWheel = (e) => {
3572
- const { scrollTop, scrollHeight, clientHeight } = el;
3573
- const isScrollable = scrollHeight > clientHeight;
3574
- if (!isScrollable) return;
3575
- e.preventDefault();
3576
- e.stopPropagation();
3577
- el.scrollTop = Math.max(
3578
- 0,
3579
- Math.min(scrollTop + e.deltaY, scrollHeight - clientHeight)
3580
- );
3581
- };
3582
- el.addEventListener("wheel", handleWheel, { passive: false, capture: true });
3583
- return () => el.removeEventListener("wheel", handleWheel, { capture: true });
3584
- }, [open, filteredOptions]);
3522
+ },
3523
+ [onSearch]
3524
+ );
3585
3525
  const handleScroll = React10.useCallback(() => {
3586
3526
  if (!onLoadMore || !hasMore || loading) return;
3587
3527
  const el = listRef.current;
@@ -3591,112 +3531,116 @@ function CardSelect({
3591
3531
  onLoadMore();
3592
3532
  }
3593
3533
  }, [onLoadMore, hasMore, loading]);
3594
- return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "relative", children: [
3534
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
3535
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3536
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
3537
+ "button",
3538
+ {
3539
+ type: "button",
3540
+ disabled,
3541
+ className: cn(
3542
+ "flex w-full items-center justify-between rounded-md border-2 bg-background px-3 text-sm transition-colors",
3543
+ "focus:outline-none focus:border-primary",
3544
+ "disabled:cursor-not-allowed disabled:opacity-50",
3545
+ label ? "h-12 pt-4 pb-2" : "h-9 py-2",
3546
+ error ? "border-red-500" : "border-border",
3547
+ open && !error && "border-primary"
3548
+ ),
3549
+ children: [
3550
+ selected ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate", children: [
3551
+ selected.icon && /* @__PURE__ */ jsx(selected.icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3552
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: selected.label })
3553
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }),
3554
+ /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 opacity-50 transition-transform", open && "rotate-180") })
3555
+ ]
3556
+ }
3557
+ ) }),
3558
+ label && /* @__PURE__ */ jsxs(
3559
+ "label",
3560
+ {
3561
+ className: cn(
3562
+ "absolute left-3 top-[-6px] text-xs font-medium bg-background px-1 pointer-events-none",
3563
+ error ? "text-red-500" : "text-foreground"
3564
+ ),
3565
+ children: [
3566
+ label,
3567
+ required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-0.5", children: "*" })
3568
+ ]
3569
+ }
3570
+ )
3571
+ ] }),
3595
3572
  /* @__PURE__ */ jsxs(
3596
- "button",
3573
+ PopoverContent,
3597
3574
  {
3598
- type: "button",
3599
- disabled,
3600
- onClick: () => setOpen((prev) => !prev),
3601
- className: cn(
3602
- "flex w-full items-center justify-between rounded-md border-2 bg-background px-3 text-sm transition-colors",
3603
- "focus:outline-none focus:border-primary",
3604
- "disabled:cursor-not-allowed disabled:opacity-50",
3605
- label ? "h-12 pt-4 pb-2" : "h-9 py-2",
3606
- error ? "border-red-500" : "border-border",
3607
- open && !error && "border-primary"
3608
- ),
3609
- children: [
3610
- selected ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate", children: [
3611
- selected.icon && /* @__PURE__ */ jsx(selected.icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3612
- /* @__PURE__ */ jsx("span", { className: "truncate", children: selected.label })
3613
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }),
3614
- /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 opacity-50 transition-transform", open && "rotate-180") })
3615
- ]
3616
- }
3617
- ),
3618
- label && /* @__PURE__ */ jsxs(
3619
- "label",
3620
- {
3621
- className: cn(
3622
- "absolute left-3 top-[-6px] text-xs font-medium bg-background px-1 pointer-events-none",
3623
- error ? "text-red-500" : "text-foreground"
3624
- ),
3575
+ align: "start",
3576
+ sideOffset: 4,
3577
+ className: "p-0 overflow-hidden",
3578
+ style: { width: "var(--radix-popover-trigger-width)" },
3579
+ onOpenAutoFocus: (e) => {
3580
+ e.preventDefault();
3581
+ if (searchable) {
3582
+ searchRef.current?.focus();
3583
+ }
3584
+ },
3625
3585
  children: [
3626
- label,
3627
- required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-0.5", children: "*" })
3628
- ]
3629
- }
3630
- ),
3631
- open && createPortal(
3632
- /* @__PURE__ */ jsxs(
3633
- "div",
3634
- {
3635
- ref: dropdownRef,
3636
- style: dropdownPos,
3637
- 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",
3638
- children: [
3639
- searchable && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border", children: [
3640
- /* @__PURE__ */ jsx(Search, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3641
- /* @__PURE__ */ jsx(
3642
- "input",
3643
- {
3644
- ref: searchRef,
3645
- type: "text",
3646
- value: search,
3647
- onChange: (e) => handleSearch(e.target.value),
3648
- placeholder: searchPlaceholder,
3649
- className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
3650
- }
3651
- )
3652
- ] }),
3586
+ searchable && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border", children: [
3587
+ /* @__PURE__ */ jsx(Search, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3653
3588
  /* @__PURE__ */ jsx(
3654
- "div",
3589
+ "input",
3655
3590
  {
3656
- ref: listRef,
3657
- className: "overflow-y-auto overscroll-contain",
3658
- style: { maxHeight: listMaxHeight },
3659
- onScroll: handleScroll,
3660
- "data-scroll-lock-scrollable": true,
3661
- children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-border/50 p-2", children: [
3662
- filteredOptions.length === 0 && !loading ? /* @__PURE__ */ jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: emptyText }) : filteredOptions.map((option) => {
3663
- const isSelected = value === option.value;
3664
- const isDisabled = option.disabled || disabled;
3665
- return /* @__PURE__ */ jsxs(
3666
- "button",
3667
- {
3668
- type: "button",
3669
- disabled: isDisabled,
3670
- onClick: () => {
3671
- onChange(option.value);
3672
- setOpen(false);
3673
- },
3674
- className: cn(
3675
- "flex w-full items-center gap-3 p-3 text-left transition-all",
3676
- "cursor-pointer hover:bg-accent",
3677
- isSelected && "bg-primary/5",
3678
- isDisabled && "cursor-not-allowed opacity-50 hover:bg-transparent"
3679
- ),
3680
- children: [
3681
- 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" }) }),
3682
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3683
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium leading-tight", children: option.label }),
3684
- option.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs leading-tight text-muted-foreground", children: option.description })
3685
- ] }),
3686
- 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" }) })
3687
- ]
3688
- },
3689
- option.value
3690
- );
3691
- }),
3692
- 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" }) })
3693
- ] })
3591
+ ref: searchRef,
3592
+ type: "text",
3593
+ value: search,
3594
+ onChange: (e) => handleSearch(e.target.value),
3595
+ placeholder: searchPlaceholder,
3596
+ className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
3694
3597
  }
3695
3598
  )
3696
- ]
3697
- }
3698
- ),
3699
- document.body
3599
+ ] }),
3600
+ /* @__PURE__ */ jsx(
3601
+ "div",
3602
+ {
3603
+ ref: listRef,
3604
+ className: "overflow-y-auto overscroll-contain",
3605
+ style: { maxHeight: "min(300px, var(--radix-popover-content-available-height, 300px))" },
3606
+ onScroll: handleScroll,
3607
+ children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-border/50 p-2", children: [
3608
+ filteredOptions.length === 0 && !loading ? /* @__PURE__ */ jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: emptyText }) : filteredOptions.map((option) => {
3609
+ const isSelected = value === option.value;
3610
+ const isDisabled = option.disabled || disabled;
3611
+ return /* @__PURE__ */ jsxs(
3612
+ "button",
3613
+ {
3614
+ type: "button",
3615
+ disabled: isDisabled,
3616
+ onClick: () => {
3617
+ onChange(option.value);
3618
+ handleOpenChange(false);
3619
+ },
3620
+ className: cn(
3621
+ "flex w-full items-center gap-3 p-3 text-left transition-all",
3622
+ "cursor-pointer hover:bg-accent",
3623
+ isSelected && "bg-primary/5",
3624
+ isDisabled && "cursor-not-allowed opacity-50 hover:bg-transparent"
3625
+ ),
3626
+ children: [
3627
+ 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" }) }),
3628
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3629
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium leading-tight", children: option.label }),
3630
+ option.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs leading-tight text-muted-foreground", children: option.description })
3631
+ ] }),
3632
+ 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" }) })
3633
+ ]
3634
+ },
3635
+ option.value
3636
+ );
3637
+ }),
3638
+ 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" }) })
3639
+ ] })
3640
+ }
3641
+ )
3642
+ ]
3643
+ }
3700
3644
  )
3701
3645
  ] });
3702
3646
  }
@@ -4261,22 +4205,6 @@ var DropdownMenuShortcut = ({
4261
4205
  );
4262
4206
  };
4263
4207
  DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
4264
- var Popover = PopoverPrimitive.Root;
4265
- var PopoverTrigger = PopoverPrimitive.Trigger;
4266
- var PopoverContent = React10.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
4267
- PopoverPrimitive.Content,
4268
- {
4269
- ref,
4270
- align,
4271
- sideOffset,
4272
- className: cn(
4273
- "z-50 w-auto rounded-md border bg-popover p-4 text-popover-foreground shadow-lg outline-none 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=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
4274
- className
4275
- ),
4276
- ...props
4277
- }
4278
- ) }));
4279
- PopoverContent.displayName = PopoverPrimitive.Content.displayName;
4280
4208
  var TooltipProvider = TooltipPrimitive.Provider;
4281
4209
  var TooltipRoot = TooltipPrimitive.Root;
4282
4210
  var TooltipTrigger = TooltipPrimitive.Trigger;