@diwauhris/ui 1.7.19 → 1.7.20

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
@@ -3957,16 +3957,40 @@ function Menu({ trigger, items, ariaLabel = "Menu", align = "right", open: contr
3957
3957
  const [panelStyle, setPanelStyle] = (0, react.useState)({});
3958
3958
  (0, react.useEffect)(() => {
3959
3959
  if (!open || !triggerRef.current) return;
3960
- const rect = triggerRef.current.getBoundingClientRect();
3960
+ const GAP = 4;
3961
+ const MARGIN = 8;
3961
3962
  const PANEL_MIN_WIDTH = 176;
3962
- setPanelStyle({
3963
- position: "fixed",
3964
- top: rect.bottom + 4,
3965
- left: align === "left" ? rect.left : Math.max(0, rect.right - PANEL_MIN_WIDTH),
3966
- zIndex: 9999,
3967
- minWidth: Math.max(rect.width, PANEL_MIN_WIDTH)
3968
- });
3969
- }, [open, align]);
3963
+ const ROW_HEIGHT = 36;
3964
+ const HEADER_HEIGHT = 8;
3965
+ const reposition = () => {
3966
+ const trigger = triggerRef.current;
3967
+ if (!trigger) return;
3968
+ const rect = trigger.getBoundingClientRect();
3969
+ const panelHeight = panelRef.current?.offsetHeight ?? items.length * ROW_HEIGHT + HEADER_HEIGHT;
3970
+ const spaceBelow = window.innerHeight - rect.bottom;
3971
+ const flipUp = spaceBelow < panelHeight + GAP + MARGIN && rect.top > spaceBelow;
3972
+ setPanelStyle({
3973
+ position: "fixed",
3974
+ ...flipUp ? { bottom: Math.max(MARGIN, window.innerHeight - rect.top + GAP) } : { top: rect.bottom + GAP },
3975
+ left: align === "left" ? rect.left : Math.max(MARGIN, rect.right - PANEL_MIN_WIDTH),
3976
+ zIndex: 9999,
3977
+ minWidth: Math.max(rect.width, PANEL_MIN_WIDTH)
3978
+ });
3979
+ };
3980
+ reposition();
3981
+ const raf = window.requestAnimationFrame(reposition);
3982
+ window.addEventListener("scroll", reposition, true);
3983
+ window.addEventListener("resize", reposition);
3984
+ return () => {
3985
+ window.cancelAnimationFrame(raf);
3986
+ window.removeEventListener("scroll", reposition, true);
3987
+ window.removeEventListener("resize", reposition);
3988
+ };
3989
+ }, [
3990
+ open,
3991
+ align,
3992
+ items.length
3993
+ ]);
3970
3994
  (0, react.useEffect)(() => {
3971
3995
  if (!open) return;
3972
3996
  const handlePointerDown = (e) => {
package/lib/index.mjs CHANGED
@@ -3933,16 +3933,40 @@ function Menu({ trigger, items, ariaLabel = "Menu", align = "right", open: contr
3933
3933
  const [panelStyle, setPanelStyle] = useState({});
3934
3934
  useEffect(() => {
3935
3935
  if (!open || !triggerRef.current) return;
3936
- const rect = triggerRef.current.getBoundingClientRect();
3936
+ const GAP = 4;
3937
+ const MARGIN = 8;
3937
3938
  const PANEL_MIN_WIDTH = 176;
3938
- setPanelStyle({
3939
- position: "fixed",
3940
- top: rect.bottom + 4,
3941
- left: align === "left" ? rect.left : Math.max(0, rect.right - PANEL_MIN_WIDTH),
3942
- zIndex: 9999,
3943
- minWidth: Math.max(rect.width, PANEL_MIN_WIDTH)
3944
- });
3945
- }, [open, align]);
3939
+ const ROW_HEIGHT = 36;
3940
+ const HEADER_HEIGHT = 8;
3941
+ const reposition = () => {
3942
+ const trigger = triggerRef.current;
3943
+ if (!trigger) return;
3944
+ const rect = trigger.getBoundingClientRect();
3945
+ const panelHeight = panelRef.current?.offsetHeight ?? items.length * ROW_HEIGHT + HEADER_HEIGHT;
3946
+ const spaceBelow = window.innerHeight - rect.bottom;
3947
+ const flipUp = spaceBelow < panelHeight + GAP + MARGIN && rect.top > spaceBelow;
3948
+ setPanelStyle({
3949
+ position: "fixed",
3950
+ ...flipUp ? { bottom: Math.max(MARGIN, window.innerHeight - rect.top + GAP) } : { top: rect.bottom + GAP },
3951
+ left: align === "left" ? rect.left : Math.max(MARGIN, rect.right - PANEL_MIN_WIDTH),
3952
+ zIndex: 9999,
3953
+ minWidth: Math.max(rect.width, PANEL_MIN_WIDTH)
3954
+ });
3955
+ };
3956
+ reposition();
3957
+ const raf = window.requestAnimationFrame(reposition);
3958
+ window.addEventListener("scroll", reposition, true);
3959
+ window.addEventListener("resize", reposition);
3960
+ return () => {
3961
+ window.cancelAnimationFrame(raf);
3962
+ window.removeEventListener("scroll", reposition, true);
3963
+ window.removeEventListener("resize", reposition);
3964
+ };
3965
+ }, [
3966
+ open,
3967
+ align,
3968
+ items.length
3969
+ ]);
3946
3970
  useEffect(() => {
3947
3971
  if (!open) return;
3948
3972
  const handlePointerDown = (e) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@diwauhris/ui",
3
3
  "private": false,
4
- "version": "1.7.19",
4
+ "version": "1.7.20",
5
5
  "type": "module",
6
6
  "description": "DIWA UHRIS UI component library — React + Tailwind CSS",
7
7
  "keywords": [