@diwauhris/ui 1.7.38 → 1.7.39

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/assets/ui.css CHANGED
@@ -1328,6 +1328,10 @@
1328
1328
  max-width: 96px;
1329
1329
  }
1330
1330
 
1331
+ .max-w-\[calc\(100vw-16px\)\] {
1332
+ max-width: calc(100vw - 16px);
1333
+ }
1334
+
1331
1335
  .max-w-lg {
1332
1336
  max-width: 32rem;
1333
1337
  }
package/lib/index.cjs CHANGED
@@ -3989,26 +3989,44 @@ function SidebarItem({ href, onClick, active = false, icon, badge, disabled = fa
3989
3989
  */
3990
3990
  function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassName = "", panelClassName = "" }) {
3991
3991
  const ref = (0, react.useRef)(null);
3992
+ const panelRef = (0, react.useRef)(null);
3992
3993
  const triggerRef = (0, react.useRef)(null);
3993
3994
  const panelId = `${(0, react.useId)().replace(/:/g, "")}-panel`;
3994
3995
  const [panelStyle, setPanelStyle] = (0, react.useState)({});
3996
+ const [positioned, setPositioned] = (0, react.useState)(false);
3995
3997
  (0, react.useEffect)(() => {
3996
- if (!isOpen || !triggerRef.current) return;
3998
+ if (!isOpen || !triggerRef.current) {
3999
+ setPositioned(false);
4000
+ return;
4001
+ }
4002
+ const GAP = 4;
4003
+ const MARGIN = 8;
3997
4004
  const updatePosition = () => {
3998
4005
  if (!triggerRef.current) return;
3999
4006
  const rect = triggerRef.current.getBoundingClientRect();
4007
+ const panelHeight = panelRef.current?.offsetHeight ?? 280;
4008
+ const panelWidth = panelRef.current?.offsetWidth ?? Math.max(rect.width, 180);
4009
+ const spaceBelow = window.innerHeight - rect.bottom;
4010
+ const spaceAbove = rect.top;
4011
+ const top = spaceBelow >= panelHeight + GAP + MARGIN || spaceBelow >= spaceAbove ? Math.min(rect.bottom + GAP, window.innerHeight - panelHeight - MARGIN) : Math.max(rect.top - panelHeight - GAP, MARGIN);
4012
+ const left = Math.max(MARGIN, Math.min(rect.left, window.innerWidth - panelWidth - MARGIN));
4000
4013
  setPanelStyle({
4001
4014
  position: "fixed",
4002
- top: rect.bottom + 4,
4003
- left: rect.left,
4004
- zIndex: 9999,
4015
+ top: Math.max(MARGIN, top),
4016
+ left,
4017
+ zIndex: 1e3,
4005
4018
  minWidth: Math.max(rect.width, 180)
4006
4019
  });
4007
4020
  };
4008
4021
  updatePosition();
4022
+ const raf = requestAnimationFrame(() => {
4023
+ updatePosition();
4024
+ setPositioned(true);
4025
+ });
4009
4026
  window.addEventListener("scroll", updatePosition, true);
4010
4027
  window.addEventListener("resize", updatePosition);
4011
4028
  return () => {
4029
+ cancelAnimationFrame(raf);
4012
4030
  window.removeEventListener("scroll", updatePosition, true);
4013
4031
  window.removeEventListener("resize", updatePosition);
4014
4032
  };
@@ -4017,6 +4035,8 @@ function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassNa
4017
4035
  if (!isOpen) return;
4018
4036
  const handlePointerDown = (e) => {
4019
4037
  const target = e.target;
4038
+ if (panelRef.current?.contains(target)) return;
4039
+ if (target.closest?.(".pis-datepicker-popover")) return;
4020
4040
  if (ref.current && !ref.current.contains(target)) {
4021
4041
  onClose();
4022
4042
  triggerRef.current?.focus();
@@ -4051,8 +4071,12 @@ function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassNa
4051
4071
  children: trigger
4052
4072
  }), isOpen && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4053
4073
  id: panelId,
4054
- style: panelStyle,
4055
- className: cn("max-h-[280px] overflow-y-auto", "rounded-xl border border-slate-200 bg-white shadow-lg", panelClassName),
4074
+ ref: panelRef,
4075
+ style: {
4076
+ ...panelStyle,
4077
+ visibility: positioned ? "visible" : "hidden"
4078
+ },
4079
+ className: cn("w-max max-w-[calc(100vw-16px)] max-h-[280px] overflow-y-auto", "rounded-xl border border-slate-200 bg-white shadow-lg", panelClassName),
4056
4080
  children
4057
4081
  }), document.body)]
4058
4082
  });
package/lib/index.mjs CHANGED
@@ -3965,26 +3965,44 @@ function SidebarItem({ href, onClick, active = false, icon, badge, disabled = fa
3965
3965
  */
3966
3966
  function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassName = "", panelClassName = "" }) {
3967
3967
  const ref = useRef(null);
3968
+ const panelRef = useRef(null);
3968
3969
  const triggerRef = useRef(null);
3969
3970
  const panelId = `${useId().replace(/:/g, "")}-panel`;
3970
3971
  const [panelStyle, setPanelStyle] = useState({});
3972
+ const [positioned, setPositioned] = useState(false);
3971
3973
  useEffect(() => {
3972
- if (!isOpen || !triggerRef.current) return;
3974
+ if (!isOpen || !triggerRef.current) {
3975
+ setPositioned(false);
3976
+ return;
3977
+ }
3978
+ const GAP = 4;
3979
+ const MARGIN = 8;
3973
3980
  const updatePosition = () => {
3974
3981
  if (!triggerRef.current) return;
3975
3982
  const rect = triggerRef.current.getBoundingClientRect();
3983
+ const panelHeight = panelRef.current?.offsetHeight ?? 280;
3984
+ const panelWidth = panelRef.current?.offsetWidth ?? Math.max(rect.width, 180);
3985
+ const spaceBelow = window.innerHeight - rect.bottom;
3986
+ const spaceAbove = rect.top;
3987
+ const top = spaceBelow >= panelHeight + GAP + MARGIN || spaceBelow >= spaceAbove ? Math.min(rect.bottom + GAP, window.innerHeight - panelHeight - MARGIN) : Math.max(rect.top - panelHeight - GAP, MARGIN);
3988
+ const left = Math.max(MARGIN, Math.min(rect.left, window.innerWidth - panelWidth - MARGIN));
3976
3989
  setPanelStyle({
3977
3990
  position: "fixed",
3978
- top: rect.bottom + 4,
3979
- left: rect.left,
3980
- zIndex: 9999,
3991
+ top: Math.max(MARGIN, top),
3992
+ left,
3993
+ zIndex: 1e3,
3981
3994
  minWidth: Math.max(rect.width, 180)
3982
3995
  });
3983
3996
  };
3984
3997
  updatePosition();
3998
+ const raf = requestAnimationFrame(() => {
3999
+ updatePosition();
4000
+ setPositioned(true);
4001
+ });
3985
4002
  window.addEventListener("scroll", updatePosition, true);
3986
4003
  window.addEventListener("resize", updatePosition);
3987
4004
  return () => {
4005
+ cancelAnimationFrame(raf);
3988
4006
  window.removeEventListener("scroll", updatePosition, true);
3989
4007
  window.removeEventListener("resize", updatePosition);
3990
4008
  };
@@ -3993,6 +4011,8 @@ function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassNa
3993
4011
  if (!isOpen) return;
3994
4012
  const handlePointerDown = (e) => {
3995
4013
  const target = e.target;
4014
+ if (panelRef.current?.contains(target)) return;
4015
+ if (target.closest?.(".pis-datepicker-popover")) return;
3996
4016
  if (ref.current && !ref.current.contains(target)) {
3997
4017
  onClose();
3998
4018
  triggerRef.current?.focus();
@@ -4027,8 +4047,12 @@ function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassNa
4027
4047
  children: trigger
4028
4048
  }), isOpen && createPortal(/* @__PURE__ */ jsx("div", {
4029
4049
  id: panelId,
4030
- style: panelStyle,
4031
- className: cn("max-h-[280px] overflow-y-auto", "rounded-xl border border-slate-200 bg-white shadow-lg", panelClassName),
4050
+ ref: panelRef,
4051
+ style: {
4052
+ ...panelStyle,
4053
+ visibility: positioned ? "visible" : "hidden"
4054
+ },
4055
+ className: cn("w-max max-w-[calc(100vw-16px)] max-h-[280px] overflow-y-auto", "rounded-xl border border-slate-200 bg-white shadow-lg", panelClassName),
4032
4056
  children
4033
4057
  }), document.body)]
4034
4058
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@diwauhris/ui",
3
3
  "private": false,
4
- "version": "1.7.38",
4
+ "version": "1.7.39",
5
5
  "type": "module",
6
6
  "description": "DIWA UHRIS UI component library — React + Tailwind CSS",
7
7
  "keywords": [