@diwauhris/ui 1.7.37 → 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,24 +3989,54 @@ 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;
3997
- const rect = triggerRef.current.getBoundingClientRect();
3998
- setPanelStyle({
3999
- position: "fixed",
4000
- top: rect.bottom + 4,
4001
- left: rect.left,
4002
- zIndex: 9999,
4003
- minWidth: Math.max(rect.width, 180)
3998
+ if (!isOpen || !triggerRef.current) {
3999
+ setPositioned(false);
4000
+ return;
4001
+ }
4002
+ const GAP = 4;
4003
+ const MARGIN = 8;
4004
+ const updatePosition = () => {
4005
+ if (!triggerRef.current) return;
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));
4013
+ setPanelStyle({
4014
+ position: "fixed",
4015
+ top: Math.max(MARGIN, top),
4016
+ left,
4017
+ zIndex: 1e3,
4018
+ minWidth: Math.max(rect.width, 180)
4019
+ });
4020
+ };
4021
+ updatePosition();
4022
+ const raf = requestAnimationFrame(() => {
4023
+ updatePosition();
4024
+ setPositioned(true);
4004
4025
  });
4026
+ window.addEventListener("scroll", updatePosition, true);
4027
+ window.addEventListener("resize", updatePosition);
4028
+ return () => {
4029
+ cancelAnimationFrame(raf);
4030
+ window.removeEventListener("scroll", updatePosition, true);
4031
+ window.removeEventListener("resize", updatePosition);
4032
+ };
4005
4033
  }, [isOpen]);
4006
4034
  (0, react.useEffect)(() => {
4007
4035
  if (!isOpen) return;
4008
4036
  const handlePointerDown = (e) => {
4009
4037
  const target = e.target;
4038
+ if (panelRef.current?.contains(target)) return;
4039
+ if (target.closest?.(".pis-datepicker-popover")) return;
4010
4040
  if (ref.current && !ref.current.contains(target)) {
4011
4041
  onClose();
4012
4042
  triggerRef.current?.focus();
@@ -4041,8 +4071,12 @@ function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassNa
4041
4071
  children: trigger
4042
4072
  }), isOpen && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4043
4073
  id: panelId,
4044
- style: panelStyle,
4045
- 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),
4046
4080
  children
4047
4081
  }), document.body)]
4048
4082
  });
package/lib/index.mjs CHANGED
@@ -3965,24 +3965,54 @@ 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;
3973
- const rect = triggerRef.current.getBoundingClientRect();
3974
- setPanelStyle({
3975
- position: "fixed",
3976
- top: rect.bottom + 4,
3977
- left: rect.left,
3978
- zIndex: 9999,
3979
- minWidth: Math.max(rect.width, 180)
3974
+ if (!isOpen || !triggerRef.current) {
3975
+ setPositioned(false);
3976
+ return;
3977
+ }
3978
+ const GAP = 4;
3979
+ const MARGIN = 8;
3980
+ const updatePosition = () => {
3981
+ if (!triggerRef.current) return;
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));
3989
+ setPanelStyle({
3990
+ position: "fixed",
3991
+ top: Math.max(MARGIN, top),
3992
+ left,
3993
+ zIndex: 1e3,
3994
+ minWidth: Math.max(rect.width, 180)
3995
+ });
3996
+ };
3997
+ updatePosition();
3998
+ const raf = requestAnimationFrame(() => {
3999
+ updatePosition();
4000
+ setPositioned(true);
3980
4001
  });
4002
+ window.addEventListener("scroll", updatePosition, true);
4003
+ window.addEventListener("resize", updatePosition);
4004
+ return () => {
4005
+ cancelAnimationFrame(raf);
4006
+ window.removeEventListener("scroll", updatePosition, true);
4007
+ window.removeEventListener("resize", updatePosition);
4008
+ };
3981
4009
  }, [isOpen]);
3982
4010
  useEffect(() => {
3983
4011
  if (!isOpen) return;
3984
4012
  const handlePointerDown = (e) => {
3985
4013
  const target = e.target;
4014
+ if (panelRef.current?.contains(target)) return;
4015
+ if (target.closest?.(".pis-datepicker-popover")) return;
3986
4016
  if (ref.current && !ref.current.contains(target)) {
3987
4017
  onClose();
3988
4018
  triggerRef.current?.focus();
@@ -4017,8 +4047,12 @@ function Dropdown({ trigger, isOpen, onToggle, onClose, children, triggerClassNa
4017
4047
  children: trigger
4018
4048
  }), isOpen && createPortal(/* @__PURE__ */ jsx("div", {
4019
4049
  id: panelId,
4020
- style: panelStyle,
4021
- 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),
4022
4056
  children
4023
4057
  }), document.body)]
4024
4058
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@diwauhris/ui",
3
3
  "private": false,
4
- "version": "1.7.37",
4
+ "version": "1.7.39",
5
5
  "type": "module",
6
6
  "description": "DIWA UHRIS UI component library — React + Tailwind CSS",
7
7
  "keywords": [