@diwauhris/ui 1.7.43 → 1.7.45

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/lib/index.cjs CHANGED
@@ -739,21 +739,44 @@ function CustomDropdown({ items, value, placeholder, status, disabled, renderOpt
739
739
  (0, react.useEffect)(() => {
740
740
  if (!open) return;
741
741
  const handlePointerDown = (e) => {
742
- if (containerRef.current && !containerRef.current.contains(e.target)) setOpen(false);
742
+ const target = e.target;
743
+ if (containerRef.current?.contains(target)) return;
744
+ if (listRef.current?.contains(target)) return;
745
+ setOpen(false);
743
746
  };
744
747
  document.addEventListener("mousedown", handlePointerDown);
745
748
  return () => document.removeEventListener("mousedown", handlePointerDown);
746
749
  }, [open]);
747
750
  (0, react.useEffect)(() => {
748
- if (!open || !triggerRef.current) return;
749
- const rect = triggerRef.current.getBoundingClientRect();
750
- setPanelStyle({
751
- position: "fixed",
752
- top: rect.bottom + 4,
753
- left: rect.left,
754
- zIndex: 9999,
755
- width: rect.width
756
- });
751
+ if (!open) return;
752
+ let raf = 0;
753
+ const place = () => {
754
+ const trigger = triggerRef.current;
755
+ if (!trigger) return;
756
+ const rect = trigger.getBoundingClientRect();
757
+ const MARGIN = 8;
758
+ const spaceBelow = window.innerHeight - rect.bottom - MARGIN;
759
+ const spaceAbove = rect.top - MARGIN;
760
+ const openUp = spaceBelow < 160 && spaceAbove > spaceBelow;
761
+ const maxHeight = Math.min(240, Math.max(120, openUp ? spaceAbove : spaceBelow));
762
+ const parent = trigger.closest("[role=\"dialog\"]") ?? document.body;
763
+ const isBody = parent === document.body;
764
+ const pr = isBody ? null : parent.getBoundingClientRect();
765
+ const left = rect.left - (pr?.left ?? 0) + parent.scrollLeft;
766
+ const topBelow = rect.bottom - (pr?.top ?? 0) + parent.scrollTop + 4;
767
+ const bottomAbove = (isBody ? window.innerHeight : parent.clientHeight) - (rect.top - (pr?.top ?? 0) + parent.scrollTop) + 4;
768
+ setPanelStyle({
769
+ position: "absolute",
770
+ top: openUp ? void 0 : topBelow,
771
+ bottom: openUp ? bottomAbove : void 0,
772
+ left,
773
+ zIndex: 9999,
774
+ width: rect.width,
775
+ maxHeight
776
+ });
777
+ };
778
+ raf = requestAnimationFrame(place);
779
+ return () => cancelAnimationFrame(raf);
757
780
  }, [open]);
758
781
  const handleSelect = (0, react.useCallback)((opt) => {
759
782
  if (opt.disabled) return;
@@ -820,6 +843,7 @@ function CustomDropdown({ items, value, placeholder, status, disabled, renderOpt
820
843
  }
821
844
  };
822
845
  const effectiveTriggerId = id ?? triggerId;
846
+ const portalTarget = triggerRef.current?.closest("[role=\"dialog\"]") ?? (typeof document !== "undefined" ? document.body : null);
823
847
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
824
848
  className: "relative",
825
849
  ref: containerRef,
@@ -854,8 +878,12 @@ function CustomDropdown({ items, value, placeholder, status, disabled, renderOpt
854
878
  id: listboxId,
855
879
  role: "listbox",
856
880
  "aria-labelledby": effectiveTriggerId,
857
- style: panelStyle,
858
- className: "overflow-y-auto max-h-60 rounded-xl border border-slate-200 bg-white py-1 shadow-xl",
881
+ "data-pis-floating": "",
882
+ style: {
883
+ ...panelStyle,
884
+ pointerEvents: "auto"
885
+ },
886
+ className: "overflow-y-auto rounded-xl border border-slate-200 bg-white py-1 shadow-xl",
859
887
  children: flatItems.map((fi, i) => {
860
888
  if (fi.type === "group") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
861
889
  role: "presentation",
@@ -883,7 +911,7 @@ function CustomDropdown({ items, value, placeholder, status, disabled, renderOpt
883
911
  children: renderOption(opt)
884
912
  }, opt.value);
885
913
  })
886
- }), document.body)
914
+ }), portalTarget)
887
915
  ]
888
916
  });
889
917
  }
package/lib/index.mjs CHANGED
@@ -715,21 +715,44 @@ function CustomDropdown({ items, value, placeholder, status, disabled, renderOpt
715
715
  useEffect(() => {
716
716
  if (!open) return;
717
717
  const handlePointerDown = (e) => {
718
- if (containerRef.current && !containerRef.current.contains(e.target)) setOpen(false);
718
+ const target = e.target;
719
+ if (containerRef.current?.contains(target)) return;
720
+ if (listRef.current?.contains(target)) return;
721
+ setOpen(false);
719
722
  };
720
723
  document.addEventListener("mousedown", handlePointerDown);
721
724
  return () => document.removeEventListener("mousedown", handlePointerDown);
722
725
  }, [open]);
723
726
  useEffect(() => {
724
- if (!open || !triggerRef.current) return;
725
- const rect = triggerRef.current.getBoundingClientRect();
726
- setPanelStyle({
727
- position: "fixed",
728
- top: rect.bottom + 4,
729
- left: rect.left,
730
- zIndex: 9999,
731
- width: rect.width
732
- });
727
+ if (!open) return;
728
+ let raf = 0;
729
+ const place = () => {
730
+ const trigger = triggerRef.current;
731
+ if (!trigger) return;
732
+ const rect = trigger.getBoundingClientRect();
733
+ const MARGIN = 8;
734
+ const spaceBelow = window.innerHeight - rect.bottom - MARGIN;
735
+ const spaceAbove = rect.top - MARGIN;
736
+ const openUp = spaceBelow < 160 && spaceAbove > spaceBelow;
737
+ const maxHeight = Math.min(240, Math.max(120, openUp ? spaceAbove : spaceBelow));
738
+ const parent = trigger.closest("[role=\"dialog\"]") ?? document.body;
739
+ const isBody = parent === document.body;
740
+ const pr = isBody ? null : parent.getBoundingClientRect();
741
+ const left = rect.left - (pr?.left ?? 0) + parent.scrollLeft;
742
+ const topBelow = rect.bottom - (pr?.top ?? 0) + parent.scrollTop + 4;
743
+ const bottomAbove = (isBody ? window.innerHeight : parent.clientHeight) - (rect.top - (pr?.top ?? 0) + parent.scrollTop) + 4;
744
+ setPanelStyle({
745
+ position: "absolute",
746
+ top: openUp ? void 0 : topBelow,
747
+ bottom: openUp ? bottomAbove : void 0,
748
+ left,
749
+ zIndex: 9999,
750
+ width: rect.width,
751
+ maxHeight
752
+ });
753
+ };
754
+ raf = requestAnimationFrame(place);
755
+ return () => cancelAnimationFrame(raf);
733
756
  }, [open]);
734
757
  const handleSelect = useCallback((opt) => {
735
758
  if (opt.disabled) return;
@@ -796,6 +819,7 @@ function CustomDropdown({ items, value, placeholder, status, disabled, renderOpt
796
819
  }
797
820
  };
798
821
  const effectiveTriggerId = id ?? triggerId;
822
+ const portalTarget = triggerRef.current?.closest("[role=\"dialog\"]") ?? (typeof document !== "undefined" ? document.body : null);
799
823
  return /* @__PURE__ */ jsxs("div", {
800
824
  className: "relative",
801
825
  ref: containerRef,
@@ -830,8 +854,12 @@ function CustomDropdown({ items, value, placeholder, status, disabled, renderOpt
830
854
  id: listboxId,
831
855
  role: "listbox",
832
856
  "aria-labelledby": effectiveTriggerId,
833
- style: panelStyle,
834
- className: "overflow-y-auto max-h-60 rounded-xl border border-slate-200 bg-white py-1 shadow-xl",
857
+ "data-pis-floating": "",
858
+ style: {
859
+ ...panelStyle,
860
+ pointerEvents: "auto"
861
+ },
862
+ className: "overflow-y-auto rounded-xl border border-slate-200 bg-white py-1 shadow-xl",
835
863
  children: flatItems.map((fi, i) => {
836
864
  if (fi.type === "group") return /* @__PURE__ */ jsx("li", {
837
865
  role: "presentation",
@@ -859,7 +887,7 @@ function CustomDropdown({ items, value, placeholder, status, disabled, renderOpt
859
887
  children: renderOption(opt)
860
888
  }, opt.value);
861
889
  })
862
- }), document.body)
890
+ }), portalTarget)
863
891
  ]
864
892
  });
865
893
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@diwauhris/ui",
3
3
  "private": false,
4
- "version": "1.7.43",
4
+ "version": "1.7.45",
5
5
  "type": "module",
6
6
  "description": "DIWA UHRIS UI component library — React + Tailwind CSS",
7
7
  "keywords": [