Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit ece2b85

Browse files
authored
Fix edge case in context menu chevron positioning (#7899)
* Fix edge case in context menu chevron positioning Signed-off-by: Robin Townsend <[email protected]> * Expand context menu positioning regression tests Signed-off-by: Robin Townsend <[email protected]>
1 parent 3e4e7ef commit ece2b85

File tree

2 files changed

+95
-20
lines changed

2 files changed

+95
-20
lines changed

src/components/structures/ContextMenu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
271271
windowHeight - contextMenuRect.height - WINDOW_PADDING,
272272
);
273273
if (chevronOffset.top !== undefined) {
274-
chevronOffset.top = props.chevronOffset + props.bottom - position.bottom;
274+
chevronOffset.top = props.chevronOffset + position.bottom - props.bottom;
275275
}
276276
}
277277
if (position.left !== undefined) {
@@ -288,7 +288,7 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
288288
windowWidth - contextMenuRect.width - WINDOW_PADDING,
289289
);
290290
if (chevronOffset.left !== undefined) {
291-
chevronOffset.left = props.chevronOffset + props.right - position.right;
291+
chevronOffset.left = props.chevronOffset + position.right - props.right;
292292
}
293293
}
294294
}

test/components/views/context_menus/ContextMenu-test.tsx

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,101 @@ describe("<ContextMenu />", () => {
3434
height: menuSize,
3535
});
3636

37-
const targetY = windowSize - menuSize + 50;
3837
const targetChevronOffset = 25;
3938

40-
const wrapper = mount(
41-
<ContextMenu
42-
top={targetY}
43-
left={0}
44-
chevronFace={ChevronFace.Right}
45-
chevronOffset={targetChevronOffset}
46-
/>,
47-
);
48-
const chevron = wrapper.find(".mx_ContextualMenu_chevron_right");
49-
50-
const actualY = parseInt(wrapper.getDOMNode().style.getPropertyValue("top"));
51-
const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("top"));
52-
53-
it("stays within the window", () => {
54-
expect(actualY + menuSize).toBeLessThanOrEqual(windowSize);
39+
describe("near top edge of window", () => {
40+
const targetY = -50;
41+
42+
const wrapper = mount(
43+
<ContextMenu
44+
bottom={windowSize - targetY - menuSize}
45+
right={menuSize}
46+
chevronFace={ChevronFace.Left}
47+
chevronOffset={targetChevronOffset}
48+
/>,
49+
);
50+
const chevron = wrapper.find(".mx_ContextualMenu_chevron_left");
51+
52+
const actualY = windowSize - parseInt(wrapper.getDOMNode().style.getPropertyValue("bottom")) - menuSize;
53+
const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("top"));
54+
55+
it("stays within the window", () => {
56+
expect(actualY).toBeGreaterThanOrEqual(0);
57+
});
58+
it("positions the chevron correctly", () => {
59+
expect(actualChevronOffset).toEqual(targetChevronOffset + targetY - actualY);
60+
});
5561
});
56-
it("positions the chevron correctly", () => {
57-
expect(actualChevronOffset).toEqual(targetChevronOffset + targetY - actualY);
62+
63+
describe("near right edge of window", () => {
64+
const targetX = windowSize - menuSize + 50;
65+
66+
const wrapper = mount(
67+
<ContextMenu
68+
bottom={0}
69+
left={targetX}
70+
chevronFace={ChevronFace.Top}
71+
chevronOffset={targetChevronOffset}
72+
/>,
73+
);
74+
const chevron = wrapper.find(".mx_ContextualMenu_chevron_top");
75+
76+
const actualX = parseInt(wrapper.getDOMNode().style.getPropertyValue("left"));
77+
const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("left"));
78+
79+
it("stays within the window", () => {
80+
expect(actualX + menuSize).toBeLessThanOrEqual(windowSize);
81+
});
82+
it("positions the chevron correctly", () => {
83+
expect(actualChevronOffset).toEqual(targetChevronOffset + targetX - actualX);
84+
});
85+
});
86+
87+
describe("near bottom edge of window", () => {
88+
const targetY = windowSize - menuSize + 50;
89+
90+
const wrapper = mount(
91+
<ContextMenu
92+
top={targetY}
93+
left={0}
94+
chevronFace={ChevronFace.Right}
95+
chevronOffset={targetChevronOffset}
96+
/>,
97+
);
98+
const chevron = wrapper.find(".mx_ContextualMenu_chevron_right");
99+
100+
const actualY = parseInt(wrapper.getDOMNode().style.getPropertyValue("top"));
101+
const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("top"));
102+
103+
it("stays within the window", () => {
104+
expect(actualY + menuSize).toBeLessThanOrEqual(windowSize);
105+
});
106+
it("positions the chevron correctly", () => {
107+
expect(actualChevronOffset).toEqual(targetChevronOffset + targetY - actualY);
108+
});
109+
});
110+
111+
describe("near left edge of window", () => {
112+
const targetX = -50;
113+
114+
const wrapper = mount(
115+
<ContextMenu
116+
top={0}
117+
right={windowSize - targetX - menuSize}
118+
chevronFace={ChevronFace.Bottom}
119+
chevronOffset={targetChevronOffset}
120+
/>,
121+
);
122+
const chevron = wrapper.find(".mx_ContextualMenu_chevron_bottom");
123+
124+
const actualX = windowSize - parseInt(wrapper.getDOMNode().style.getPropertyValue("right")) - menuSize;
125+
const actualChevronOffset = parseInt(chevron.getDOMNode().style.getPropertyValue("left"));
126+
127+
it("stays within the window", () => {
128+
expect(actualX).toBeGreaterThanOrEqual(0);
129+
});
130+
it("positions the chevron correctly", () => {
131+
expect(actualChevronOffset).toEqual(targetChevronOffset + targetX - actualX);
132+
});
58133
});
59134
});

0 commit comments

Comments
 (0)