From 53f4b8ced3d6cb0193f4c42fcbc7dc28fc5a49e6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 7 Apr 2025 22:05:31 +1000 Subject: [PATCH 1/4] Update ContextMenu.react.js --- .../ContextMenu/ContextMenu.react.js | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/components/ContextMenu/ContextMenu.react.js b/src/components/ContextMenu/ContextMenu.react.js index fdd309c6e4..0b36a7c1c5 100644 --- a/src/components/ContextMenu/ContextMenu.react.js +++ b/src/components/ContextMenu/ContextMenu.react.js @@ -9,20 +9,36 @@ import PropTypes from 'lib/PropTypes'; import React, { useState, useEffect, useRef } from 'react'; import styles from 'components/ContextMenu/ContextMenu.scss'; -const getPositionToFitVisibleScreen = ref => { +const getPositionToFitVisibleScreen = (ref, offset = 0) => { if (ref.current) { const elBox = ref.current.getBoundingClientRect(); - const y = elBox.y + elBox.height < window.innerHeight ? 0 : 0 - elBox.y + 100; + let y = 0; + + const footerHeight = 50; + const lowerLimit = window.innerHeight - footerHeight; + const upperLimit = 0; + + if (elBox.bottom > lowerLimit) { + y = lowerLimit - elBox.bottom; + } else if (elBox.top < upperLimit) { + y = upperLimit - elBox.top; + } + + // Apply offset only if it doesn't push the element offscreen again + const projectedTop = elBox.top + y + offset; + const projectedBottom = projectedTop + elBox.height; + + if (projectedTop >= upperLimit && projectedBottom <= lowerLimit) { + y += offset; + } - // If there's a previous element show current next to it. - // Try on right side first, then on left if there's no place. const prevEl = ref.current.previousSibling; if (prevEl) { const prevElBox = prevEl.getBoundingClientRect(); const showOnRight = prevElBox.x + prevElBox.width + elBox.width < window.innerWidth; return { x: showOnRight ? prevElBox.width : -elBox.width, - y, + y }; } @@ -35,14 +51,14 @@ const MenuSection = ({ level, items, path, setPath, hide }) => { const [position, setPosition] = useState(); useEffect(() => { - const newPosition = getPositionToFitVisibleScreen(sectionRef); + const newPosition = getPositionToFitVisibleScreen(sectionRef, path[level] * 30); newPosition && setPosition(newPosition); }, [sectionRef]); const style = position ? { left: position.x, - top: position.y + path[level] * 30, + top: position.y, maxHeight: '80vh', overflowY: 'scroll', opacity: 1, From 18d5c975077fe891e3962e710d79193baf74d71c Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 9 Apr 2025 20:50:38 +1000 Subject: [PATCH 2/4] Update ContextMenu.react.js --- .../ContextMenu/ContextMenu.react.js | 49 ++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/components/ContextMenu/ContextMenu.react.js b/src/components/ContextMenu/ContextMenu.react.js index 0b36a7c1c5..b5f03cfa36 100644 --- a/src/components/ContextMenu/ContextMenu.react.js +++ b/src/components/ContextMenu/ContextMenu.react.js @@ -9,7 +9,7 @@ import PropTypes from 'lib/PropTypes'; import React, { useState, useEffect, useRef } from 'react'; import styles from 'components/ContextMenu/ContextMenu.scss'; -const getPositionToFitVisibleScreen = (ref, offset = 0) => { +const getPositionToFitVisibleScreen = (ref, offset = 0, mainItemCount = 0, subItemCount = 0) => { if (ref.current) { const elBox = ref.current.getBoundingClientRect(); let y = 0; @@ -24,17 +24,24 @@ const getPositionToFitVisibleScreen = (ref, offset = 0) => { y = upperLimit - elBox.top; } - // Apply offset only if it doesn't push the element offscreen again const projectedTop = elBox.top + y + offset; const projectedBottom = projectedTop + elBox.height; - if (projectedTop >= upperLimit && projectedBottom <= lowerLimit) { + const shouldApplyOffset = subItemCount > mainItemCount; + if (shouldApplyOffset && projectedTop >= upperLimit && projectedBottom <= lowerLimit) { y += offset; } const prevEl = ref.current.previousSibling; if (prevEl) { const prevElBox = prevEl.getBoundingClientRect(); + const prevElStyle = window.getComputedStyle(prevEl); + const prevElTop = parseInt(prevElStyle.top, 10); + + if (!shouldApplyOffset) { + y = prevElTop + offset; + } + const showOnRight = prevElBox.x + prevElBox.width + elBox.width < window.innerWidth; return { x: showOnRight ? prevElBox.width : -elBox.width, @@ -46,23 +53,28 @@ const getPositionToFitVisibleScreen = (ref, offset = 0) => { } }; -const MenuSection = ({ level, items, path, setPath, hide }) => { +const MenuSection = ({ level, items, path, setPath, hide, parentItemCount = 0 }) => { const sectionRef = useRef(null); const [position, setPosition] = useState(); useEffect(() => { - const newPosition = getPositionToFitVisibleScreen(sectionRef, path[level] * 30); + const newPosition = getPositionToFitVisibleScreen( + sectionRef, + path[level] * 30, + parentItemCount, + items.length + ); newPosition && setPosition(newPosition); }, [sectionRef]); const style = position ? { - left: position.x, - top: position.y, - maxHeight: '80vh', - overflowY: 'scroll', - opacity: 1, - } + left: position.x, + top: position.y, + maxHeight: '80vh', + overflowY: 'scroll', + opacity: 1, + } : {}; return ( @@ -108,6 +120,8 @@ const MenuSection = ({ level, items, path, setPath, hide }) => { const ContextMenu = ({ x, y, items }) => { const [path, setPath] = useState([0]); const [visible, setVisible] = useState(true); + const menuRef = useRef(null); + useEffect(() => { setVisible(true); }, [items]); @@ -117,10 +131,6 @@ const ContextMenu = ({ x, y, items }) => { setPath([0]); }; - //#region Closing menu after clicking outside it - - const menuRef = useRef(null); - function handleClickOutside(event) { if (menuRef.current && !menuRef.current.contains(event.target)) { hide(); @@ -134,8 +144,6 @@ const ContextMenu = ({ x, y, items }) => { }; }); - //#endregion - if (!visible) { return null; } @@ -158,14 +166,19 @@ const ContextMenu = ({ x, y, items }) => { }} > {path.map((position, level) => { + const itemsForLevel = getItemsFromLevel(level); + const parentItemCount = + level === 0 ? items.length : getItemsFromLevel(level - 1).length; + return ( ); })} From a66522faefc1dd1c36fa8a2ad2cf55a5e5f6e78a Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Thu, 10 Apr 2025 02:09:58 +0100 Subject: [PATCH 3/4] lint --- src/components/ContextMenu/ContextMenu.react.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/ContextMenu/ContextMenu.react.js b/src/components/ContextMenu/ContextMenu.react.js index b5f03cfa36..9f26d1b8d8 100644 --- a/src/components/ContextMenu/ContextMenu.react.js +++ b/src/components/ContextMenu/ContextMenu.react.js @@ -69,12 +69,12 @@ const MenuSection = ({ level, items, path, setPath, hide, parentItemCount = 0 }) const style = position ? { - left: position.x, - top: position.y, - maxHeight: '80vh', - overflowY: 'scroll', - opacity: 1, - } + left: position.x, + top: position.y, + maxHeight: '80vh', + overflowY: 'scroll', + opacity: 1, + } : {}; return ( From e220b16558ad9aea30c7b793ddda7f10edf31a2b Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 25 Apr 2025 21:05:52 +1000 Subject: [PATCH 4/4] Update ContextMenu.react.js --- src/components/ContextMenu/ContextMenu.react.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/ContextMenu/ContextMenu.react.js b/src/components/ContextMenu/ContextMenu.react.js index 9f26d1b8d8..4099159be7 100644 --- a/src/components/ContextMenu/ContextMenu.react.js +++ b/src/components/ContextMenu/ContextMenu.react.js @@ -107,6 +107,10 @@ const MenuSection = ({ level, items, path, setPath, hide, parentItemCount = 0 }) item.callback && item.callback(); hide(); }} + onMouseEnter={() => { + const newPath = path.slice(0, level + 1); + setPath(newPath); + }} > {item.text} {item.subtext && - {item.subtext}}