Skip to content

Commit 4d596f2

Browse files
tt-hongweb-padawan
authored andcommitted
fix: ensure nested submenu is aligned properly (#265)
1 parent 0ae2dda commit 4d596f2

File tree

4 files changed

+23
-11
lines changed

4 files changed

+23
-11
lines changed

src/vaadin-context-menu.html

+19-6
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@
614614
const {xMax, yMax, left, top, width} = overlay.getBoundaries();
615615
// Reuse saved x and y event values, in order to this method be used async
616616
// in the `vaadin-overlay-change` which guarantees that overlay is ready
617-
const x = this.__x || left;
617+
let x = this.__x || left;
618618
const y = this.__y || top;
619619

620620
// Select one overlay corner and move to the event x/y position.
@@ -625,11 +625,11 @@
625625
// Align to the parent menu overlay, if any.
626626
const parent = overlay.parentOverlay;
627627
let alignedToParent = false;
628+
let parentContentRect;
628629
if (parent) {
629-
const parentContentRect = parent.$.overlay.getBoundingClientRect();
630+
parentContentRect = parent.$.overlay.getBoundingClientRect();
630631
if (parent.hasAttribute('right-aligned')) {
631632
const parentStyle = getComputedStyle(parent);
632-
633633
const getPadding = (el, direction) => {
634634
return parseFloat(getComputedStyle(el.$.content)['padding' + direction]);
635635
};
@@ -639,16 +639,29 @@
639639
// Preserve right-aligned, if possible.
640640
if ((wdthVport - (right - padding)) > width) {
641641
overlay.setAttribute('right-aligned', '');
642-
style.right = right - padding + 'px';
642+
style.right = right + 'px';
643643
alignedToParent = true;
644644
}
645+
} else if (x < parentContentRect.x) {
646+
// Check if sub menu opens on the left side and the parent menu is not right aligned.
647+
// If so, use actual width of the submenu content instead of the parent menu content.
648+
x = x - (width - parentContentRect.width);
645649
}
646650
}
647651

648652
if (!alignedToParent) {
649-
if (x < wdthVport / 2 || x < xMax) {
653+
// Sub-menu is displayed in the right side of root menu
654+
if ((x < wdthVport / 2 || x < xMax) && !parent) {
650655
style.left = x + 'px';
651-
} else {
656+
} else if ((parent && (wdthVport - parentContentRect.width - parentContentRect.left
657+
>= parentContentRect.width))) { // Sub-menu is displayed in the right side of root menu If it is nested menu
658+
style.left = parentContentRect.left + parentContentRect.width + 'px';
659+
} else if (parent) { // Sub-menu is displayed in the left side of root menu If it is nested menu
660+
style.right = 'auto';
661+
style.left = Math.max(overlay.getBoundingClientRect().left,
662+
parentContentRect.left - overlay.getBoundingClientRect().width) + 'px';
663+
overlay.setAttribute('right-aligned', '');
664+
} else { // Sub-menu is displayed in the left side of root menu
652665
style.right = Math.max(0, (wdthVport - x)) + 'px';
653666
overlay.setAttribute('right-aligned', '');
654667
}

test/items.html

+4-5
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
open(menuComponents()[0]);
124124
rootItemRect = menuComponents()[0].getBoundingClientRect();
125125
const subItemRect = menuComponents(subMenu)[0].getBoundingClientRect();
126-
expect(subItemRect.right).to.be.below(rootItemRect.left + rootItemRect.width / 2);
126+
expect(subItemRect.right).to.be.below(rootItemRect.left);
127127
});
128128

129129
it('should open the subMenu on the top if root menu is bottom-aligned', done => {
@@ -151,13 +151,12 @@
151151
rootOverlay.style.removeProperty('left');
152152
rootOverlay.style.right = rootItemRect.width + 'px';
153153
rootOverlay.setAttribute('right-aligned', '');
154-
const padding = parseFloat(getComputedStyle(rootOverlay.$.content).paddingLeft) * 2;
155154
open(rootItem);
156155
await nextRender(subMenu);
157156
expect(subMenu.$.overlay.hasAttribute('right-aligned')).to.be.true;
158157
const rootMenuRect = rootOverlay.$.content.getBoundingClientRect();
159158
const subMenuRect = subMenu.$.overlay.$.content.getBoundingClientRect();
160-
expect(subMenuRect.right).to.be.closeTo(rootMenuRect.left + padding, 1);
159+
expect(subMenuRect.right).to.be.closeTo(rootMenuRect.left, 2);
161160
});
162161

163162
it('should open the second subMenu on the right again if not enough space', async() => {
@@ -180,7 +179,7 @@
180179
expect(subMenu.$.overlay.hasAttribute('right-aligned')).to.be.true;
181180
const rootMenuRect = rootOverlay.$.content.getBoundingClientRect();
182181
const subMenuRect = subMenu.$.overlay.$.content.getBoundingClientRect();
183-
expect(subMenuRect.right).to.be.closeTo(rootMenuRect.left + padding, 1);
182+
expect(subMenuRect.right).to.be.closeTo(rootMenuRect.left, 1);
184183

185184
/* second sub-menu left-aligned */
186185
const nestedItem = menuComponents(subMenu)[2];
@@ -191,7 +190,7 @@
191190
const subMenu2 = getSubMenu(subMenu);
192191
expect(subMenu2.$.overlay.hasAttribute('right-aligned')).to.be.false;
193192
const subMenu2Rect = subMenu2.$.overlay.$.content.getBoundingClientRect();
194-
expect(subMenu2Rect.left).to.be.closeTo(nestedItemRect.right, 1);
193+
expect(subMenu2Rect.left).to.be.closeTo(nestedItemRect.right + padding / 2, 1);
195194
});
196195
}
197196

Loading
Loading

0 commit comments

Comments
 (0)