@facter/ds-core 1.33.1 → 1.33.3

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
@@ -16,6 +16,7 @@ var DialogPrimitive = require('@radix-ui/react-dialog');
16
16
  var sonner = require('sonner');
17
17
  var SwitchPrimitives = require('@radix-ui/react-switch');
18
18
  var reactHookForm = require('react-hook-form');
19
+ var reactDom = require('react-dom');
19
20
  var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
20
21
  var AvatarPrimitive = require('@radix-ui/react-avatar');
21
22
  var DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
@@ -3518,8 +3519,11 @@ function CardSelect({
3518
3519
  const [search, setSearch] = React10__namespace.useState("");
3519
3520
  const selected = options.find((o) => o.value === value);
3520
3521
  const containerRef = React10__namespace.useRef(null);
3522
+ const dropdownRef = React10__namespace.useRef(null);
3521
3523
  const listRef = React10__namespace.useRef(null);
3522
3524
  const searchRef = React10__namespace.useRef(null);
3525
+ const [dropdownPos, setDropdownPos] = React10__namespace.useState({});
3526
+ const [listMaxHeight, setListMaxHeight] = React10__namespace.useState(300);
3523
3527
  const filteredOptions = React10__namespace.useMemo(() => {
3524
3528
  if (!searchable || onSearch || !search) return options;
3525
3529
  const q = search.toLowerCase();
@@ -3534,10 +3538,39 @@ function CardSelect({
3534
3538
  },
3535
3539
  [onSearch]
3536
3540
  );
3541
+ React10__namespace.useEffect(() => {
3542
+ if (!open || !containerRef.current) return;
3543
+ const updatePosition = () => {
3544
+ const rect = containerRef.current.getBoundingClientRect();
3545
+ const margin = 8;
3546
+ const searchBarHeight = searchable ? 41 : 0;
3547
+ const spaceBelow = window.innerHeight - rect.bottom - margin;
3548
+ const spaceAbove = rect.top - margin;
3549
+ const showAbove = spaceBelow < 150 && spaceAbove > spaceBelow;
3550
+ const availableSpace = showAbove ? spaceAbove : spaceBelow;
3551
+ const maxList = Math.max(Math.min(availableSpace - searchBarHeight - margin, 300), 100);
3552
+ setListMaxHeight(maxList);
3553
+ setDropdownPos({
3554
+ position: "fixed",
3555
+ left: rect.left,
3556
+ width: rect.width,
3557
+ zIndex: 9999,
3558
+ ...showAbove ? { bottom: window.innerHeight - rect.top + 4 } : { top: rect.bottom + 4 }
3559
+ });
3560
+ };
3561
+ updatePosition();
3562
+ window.addEventListener("scroll", updatePosition, true);
3563
+ window.addEventListener("resize", updatePosition);
3564
+ return () => {
3565
+ window.removeEventListener("scroll", updatePosition, true);
3566
+ window.removeEventListener("resize", updatePosition);
3567
+ };
3568
+ }, [open, searchable]);
3537
3569
  React10__namespace.useEffect(() => {
3538
3570
  if (!open) return;
3539
3571
  const handleClickOutside = (e) => {
3540
- if (containerRef.current && !containerRef.current.contains(e.target)) {
3572
+ const target = e.target;
3573
+ if (containerRef.current && !containerRef.current.contains(target) && (!dropdownRef.current || !dropdownRef.current.contains(target))) {
3541
3574
  setOpen(false);
3542
3575
  }
3543
3576
  };
@@ -3626,63 +3659,75 @@ function CardSelect({
3626
3659
  ]
3627
3660
  }
3628
3661
  ),
3629
- open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 top-full z-50 mt-1 w-full 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", children: [
3630
- searchable && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border", children: [
3631
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3632
- /* @__PURE__ */ jsxRuntime.jsx(
3633
- "input",
3634
- {
3635
- ref: searchRef,
3636
- type: "text",
3637
- value: search,
3638
- onChange: (e) => handleSearch(e.target.value),
3639
- placeholder: searchPlaceholder,
3640
- className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
3641
- }
3642
- )
3643
- ] }),
3644
- /* @__PURE__ */ jsxRuntime.jsx(
3662
+ open && reactDom.createPortal(
3663
+ /* @__PURE__ */ jsxRuntime.jsxs(
3645
3664
  "div",
3646
3665
  {
3647
- ref: listRef,
3648
- className: "overflow-y-auto overscroll-contain max-h-[300px]",
3649
- onScroll: handleScroll,
3650
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-border/50 p-2", children: [
3651
- filteredOptions.length === 0 && !loading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: emptyText }) : filteredOptions.map((option) => {
3652
- const isSelected = value === option.value;
3653
- const isDisabled = option.disabled || disabled;
3654
- return /* @__PURE__ */ jsxRuntime.jsxs(
3655
- "button",
3666
+ ref: dropdownRef,
3667
+ style: dropdownPos,
3668
+ 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",
3669
+ children: [
3670
+ searchable && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border", children: [
3671
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3672
+ /* @__PURE__ */ jsxRuntime.jsx(
3673
+ "input",
3656
3674
  {
3657
- type: "button",
3658
- disabled: isDisabled,
3659
- onClick: () => {
3660
- onChange(option.value);
3661
- setOpen(false);
3662
- },
3663
- className: cn(
3664
- "flex w-full items-center gap-3 p-3 text-left transition-all",
3665
- "cursor-pointer hover:bg-accent",
3666
- isSelected && "bg-primary/5",
3667
- isDisabled && "cursor-not-allowed opacity-50 hover:bg-transparent"
3668
- ),
3669
- children: [
3670
- option.icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsxRuntime.jsx(option.icon, { className: "h-3.5 w-3.5 text-primary" }) }),
3671
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
3672
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium leading-tight", children: option.label }),
3673
- option.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs leading-tight text-muted-foreground", children: option.description })
3674
- ] }),
3675
- isSelected && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3" }) })
3676
- ]
3677
- },
3678
- option.value
3679
- );
3680
- }),
3681
- loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-3", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) })
3682
- ] })
3675
+ ref: searchRef,
3676
+ type: "text",
3677
+ value: search,
3678
+ onChange: (e) => handleSearch(e.target.value),
3679
+ placeholder: searchPlaceholder,
3680
+ className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
3681
+ }
3682
+ )
3683
+ ] }),
3684
+ /* @__PURE__ */ jsxRuntime.jsx(
3685
+ "div",
3686
+ {
3687
+ ref: listRef,
3688
+ className: "overflow-y-auto overscroll-contain",
3689
+ style: { maxHeight: listMaxHeight },
3690
+ onScroll: handleScroll,
3691
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-border/50 p-2", children: [
3692
+ filteredOptions.length === 0 && !loading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: emptyText }) : filteredOptions.map((option) => {
3693
+ const isSelected = value === option.value;
3694
+ const isDisabled = option.disabled || disabled;
3695
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3696
+ "button",
3697
+ {
3698
+ type: "button",
3699
+ disabled: isDisabled,
3700
+ onClick: () => {
3701
+ onChange(option.value);
3702
+ setOpen(false);
3703
+ },
3704
+ className: cn(
3705
+ "flex w-full items-center gap-3 p-3 text-left transition-all",
3706
+ "cursor-pointer hover:bg-accent",
3707
+ isSelected && "bg-primary/5",
3708
+ isDisabled && "cursor-not-allowed opacity-50 hover:bg-transparent"
3709
+ ),
3710
+ children: [
3711
+ option.icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsxRuntime.jsx(option.icon, { className: "h-3.5 w-3.5 text-primary" }) }),
3712
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
3713
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium leading-tight", children: option.label }),
3714
+ option.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs leading-tight text-muted-foreground", children: option.description })
3715
+ ] }),
3716
+ isSelected && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3" }) })
3717
+ ]
3718
+ },
3719
+ option.value
3720
+ );
3721
+ }),
3722
+ loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-3", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) })
3723
+ ] })
3724
+ }
3725
+ )
3726
+ ]
3683
3727
  }
3684
- )
3685
- ] })
3728
+ ),
3729
+ document.body
3730
+ )
3686
3731
  ] });
3687
3732
  }
3688
3733
  function FormTextarea({