From ece2b8572a57581a199f58bd78ab3e0ef5fe797a Mon Sep 17 00:00:00 2001 From: Robin Date: Fri, 25 Feb 2022 12:49:57 -0500 Subject: [PATCH] Fix edge case in context menu chevron positioning (#7899) * Fix edge case in context menu chevron positioning Signed-off-by: Robin Townsend * Expand context menu positioning regression tests Signed-off-by: Robin Townsend --- src/components/structures/ContextMenu.tsx | 4 +- .../views/context_menus/ContextMenu-test.tsx | 107 +++++++++++++++--- 2 files changed, 93 insertions(+), 18 deletions(-) diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index bbdcae2eeb..1730ec2396 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -271,7 +271,7 @@ export default class ContextMenu extends React.PureComponent { windowHeight - contextMenuRect.height - WINDOW_PADDING, ); if (chevronOffset.top !== undefined) { - chevronOffset.top = props.chevronOffset + props.bottom - position.bottom; + chevronOffset.top = props.chevronOffset + position.bottom - props.bottom; } } if (position.left !== undefined) { @@ -288,7 +288,7 @@ export default class ContextMenu extends React.PureComponent { windowWidth - contextMenuRect.width - WINDOW_PADDING, ); if (chevronOffset.left !== undefined) { - chevronOffset.left = props.chevronOffset + props.right - position.right; + chevronOffset.left = props.chevronOffset + position.right - props.right; } } } diff --git a/test/components/views/context_menus/ContextMenu-test.tsx b/test/components/views/context_menus/ContextMenu-test.tsx index 0b34b7dfd4..29a041f0f0 100644 --- a/test/components/views/context_menus/ContextMenu-test.tsx +++ b/test/components/views/context_menus/ContextMenu-test.tsx @@ -34,26 +34,101 @@ describe("", () => { height: menuSize, }); - const targetY = windowSize - menuSize + 50; const targetChevronOffset = 25; - const wrapper = mount( - , - ); - const chevron = wrapper.find(".mx_ContextualMenu_chevron_right"); + describe("near top edge of window", () => { + const targetY = -50; - const actualY = parseInt(wrapper.getDOMNode().style.getPropertyValue("top")); - const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("top")); + const wrapper = mount( + , + ); + const chevron = wrapper.find(".mx_ContextualMenu_chevron_left"); - it("stays within the window", () => { - expect(actualY + menuSize).toBeLessThanOrEqual(windowSize); + const actualY = windowSize - parseInt(wrapper.getDOMNode().style.getPropertyValue("bottom")) - menuSize; + const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("top")); + + it("stays within the window", () => { + expect(actualY).toBeGreaterThanOrEqual(0); + }); + it("positions the chevron correctly", () => { + expect(actualChevronOffset).toEqual(targetChevronOffset + targetY - actualY); + }); }); - it("positions the chevron correctly", () => { - expect(actualChevronOffset).toEqual(targetChevronOffset + targetY - actualY); + + describe("near right edge of window", () => { + const targetX = windowSize - menuSize + 50; + + const wrapper = mount( + , + ); + const chevron = wrapper.find(".mx_ContextualMenu_chevron_top"); + + const actualX = parseInt(wrapper.getDOMNode().style.getPropertyValue("left")); + const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("left")); + + it("stays within the window", () => { + expect(actualX + menuSize).toBeLessThanOrEqual(windowSize); + }); + it("positions the chevron correctly", () => { + expect(actualChevronOffset).toEqual(targetChevronOffset + targetX - actualX); + }); + }); + + describe("near bottom edge of window", () => { + const targetY = windowSize - menuSize + 50; + + const wrapper = mount( + , + ); + const chevron = wrapper.find(".mx_ContextualMenu_chevron_right"); + + const actualY = parseInt(wrapper.getDOMNode().style.getPropertyValue("top")); + const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("top")); + + it("stays within the window", () => { + expect(actualY + menuSize).toBeLessThanOrEqual(windowSize); + }); + it("positions the chevron correctly", () => { + expect(actualChevronOffset).toEqual(targetChevronOffset + targetY - actualY); + }); + }); + + describe("near left edge of window", () => { + const targetX = -50; + + const wrapper = mount( + , + ); + const chevron = wrapper.find(".mx_ContextualMenu_chevron_bottom"); + + const actualX = windowSize - parseInt(wrapper.getDOMNode().style.getPropertyValue("right")) - menuSize; + const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("left")); + + it("stays within the window", () => { + expect(actualX).toBeGreaterThanOrEqual(0); + }); + it("positions the chevron correctly", () => { + expect(actualChevronOffset).toEqual(targetChevronOffset + targetX - actualX); + }); }); });