Skip to content

Commit

Permalink
fix(ui5-popover): arrow is now centered on close to the edge opener (#…
Browse files Browse the repository at this point in the history
…8205)

Fixes: #7152
  • Loading branch information
dimovpetar committed Jan 31, 2024
1 parent 9bcf589 commit d17a4bc
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 70 deletions.
12 changes: 6 additions & 6 deletions packages/main/src/Popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ class Popover extends Popup {
* @private
*/
calcPlacement(targetRect: DOMRect, popoverSize: PopoverSize): CalculatedPlacement {
let left = 0;
let left = Popover.VIEWPORT_MARGIN;
let top = 0;
const allowTargetOverlap = this.allowTargetOverlap;

Expand Down Expand Up @@ -570,10 +570,10 @@ class Popover extends Popup {

// correct popover positions
if (isVertical) {
if (popoverSize.width > clientWidth || left < 0) {
left = 0;
} else if (left + popoverSize.width > clientWidth) {
left -= left + popoverSize.width - clientWidth;
if (popoverSize.width > clientWidth || left < Popover.VIEWPORT_MARGIN) {
left = Popover.VIEWPORT_MARGIN;
} else if (left + popoverSize.width > clientWidth - Popover.VIEWPORT_MARGIN) {
left = clientWidth - Popover.VIEWPORT_MARGIN - popoverSize.width;
}
} else {
if (popoverSize.height > clientHeight || top < 0) { // eslint-disable-line
Expand Down Expand Up @@ -719,7 +719,7 @@ class Popover extends Popup {

getVerticalLeft(targetRect: DOMRect, popoverSize: PopoverSize): number {
const horizontalAlign = this._actualHorizontalAlign;
let left = 0;
let left = Popover.VIEWPORT_MARGIN;

switch (horizontalAlign) {
case PopoverHorizontalAlign.Center:
Expand Down
34 changes: 23 additions & 11 deletions packages/main/test/pages/Popover.html
Original file line number Diff line number Diff line change
Expand Up @@ -212,42 +212,50 @@
<br>
<ui5-title>placement-type="Right" (default)</ui5-title>
<p>No space on the Right, try Left, Bottom, Top</p>
<ui5-button id="btnFullWidth" class="popover7auto">Click me !</ui5-button>
<ui5-button id="btnFullWidth" class="fullWidth">Click me !</ui5-button>
<ui5-button id="btnNormalWidth">Click me !</ui5-button>
<br>
<br>
<ui5-title>placement-type="Right" (default) and allow-target-overlap=true </ui5-title>
<p>No space on the right, try Left, Bottom, Top and if nothing works, the target will be overlapped</p>
<ui5-button id="btnFullWidthTargetOverlap" class="popover7auto">Click me !</ui5-button>
<ui5-button id="btnFullWidthTargetOverlap" class="fullWidth">Click me !</ui5-button>
<ui5-button id="btnNormalWidthTargetOverlap">Click me !</ui5-button>

<br>
<br>
<ui5-title>placement-type="Left"</ui5-title>
<p>No space on the Left, try Right, Bottom, Top</p>
<ui5-button id="btnFullWidthLeft" class="popover7auto">Click me !</ui5-button>
<ui5-button id="btnFullWidthLeft" class="fullWidth">Click me !</ui5-button>
<div class="popover13auto">
<ui5-button id="btnNormalWidthLeft">Click me !</ui5-button>
</div>

<br>
<br>
<ui5-title>placement-type="Left" and allow-target-overlap=true</ui5-title>
<p>No space on the right, try Roght, Bottom, Top and if nothing works, the target will be overlapped</p>
<ui5-button id="btnFullWidthLeftTargetOverlap" class="popover7auto">Click me !</ui5-button>
<p>No space on the right, try Right, Bottom, Top and if nothing works, the target will be overlapped</p>
<ui5-button id="btnFullWidthLeftTargetOverlap" class="fullWidth">Click me !</ui5-button>
<div class="popover13auto">
<ui5-button id="btnNormalWidthLeftTargetOverlap">Click me !</ui5-button>
</div>

<br>
<br>
<ui5-title>placement-type="Top"</ui5-title>
<ui5-button id="btnFullWidthTop" class="popover7auto">Click me !</ui5-button>
<ui5-button id="btnFullWidthTop" class="fullWidth">Click me !</ui5-button>
<div class="flexContainerSpaceBetween">
<ui5-button id="btnLeftEdgeTop">...</ui5-button>
<ui5-button id="btnRightEdgeTop">...</ui5-button>
</div>

<br>
<br>
<ui5-title>placement-type="Bottom"</ui5-title>
<ui5-button id="btnFullWidthBottom" class="popover7auto">Click me !</ui5-button>
<ui5-button id="btnFullWidthBottom" class="fullWidth">Click me !</ui5-button>
<div class="flexContainerSpaceBetween">
<ui5-button id="btnLeftEdgeBottom">...</ui5-button>
<ui5-button id="btnRightEdgeBottom">...</ui5-button>
</div>

<ui5-popover header-text="My Heading" id="popFullWidth" class="popover6auto">
<div slot="header">
Expand Down Expand Up @@ -575,12 +583,16 @@ <h2>Horizontal Align</h2>
popFullWidthLeftTargetOverlap.showAt(btnNormalWidthLeftTargetOverlap);
});

btnFullWidthTop.addEventListener("click", function (event) {
popFullWidthTop.showAt(btnFullWidthTop);
[btnFullWidthTop, btnLeftEdgeTop, btnRightEdgeTop].forEach((el) => {
el.addEventListener("click", function (event) {
popFullWidthTop.showAt(el);
});
});

btnFullWidthBottom.addEventListener("click", function (event) {
popFullWidthBottom.showAt(btnFullWidthBottom);
[btnFullWidthBottom, btnLeftEdgeBottom, btnRightEdgeBottom].forEach((el) => {
el.addEventListener("click", function (event) {
popFullWidthBottom.showAt(el);
});
});

btnQuickViewCardOpener.addEventListener("click", function (event) {
Expand Down
8 changes: 7 additions & 1 deletion packages/main/test/pages/styles/Popover.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ ui5-date-picker,
width: 300px
}

.popover7auto {
.fullWidth {
width: 100%
}

Expand Down Expand Up @@ -73,3 +73,9 @@ ui5-date-picker,
position: relative;
z-index: 1;
}

.flexContainerSpaceBetween {
display: flex;
justify-content: space-between;
}

145 changes: 93 additions & 52 deletions packages/main/test/specs/Popover.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,26 +421,22 @@ describe("Acc", () => {
});
});

describe("Horizontal Alignment", () => {
before(async () => {
await browser.url(`test/pages/Popover.html`);
});

describe("Alignment", () => {
const EPS = 2; // 2px

const isHorizontallyCentered = async (popover, opener) => {
const popoverRect = {
...await popover.getLocation(),
...await popover.getSize()
const isHorizontallyCentered = async (element, opener) => {
const elemRect = {
...await element.getLocation(),
...await element.getSize()
};
const openerRect = {
...await opener.getLocation(),
...await opener.getSize()
};
const openerCenter = openerRect.x + openerRect.width / 2;
const expectedPopoverLeft = openerCenter - popoverRect.width / 2;
const expectedElemX = openerCenter - elemRect.width / 2;

return Math.abs(popoverRect.x - expectedPopoverLeft) < EPS;
return Math.abs(elemRect.x - expectedElemX) < EPS;
}

const isHorizontallyLeftAligned = async (popover, opener) => {
Expand Down Expand Up @@ -471,59 +467,104 @@ describe("Horizontal Alignment", () => {
return Math.abs(openerRight - popoverRight) < EPS;
}

it("Center", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Center']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");
describe("Horizontal Alignment", () => {
before(async () => {
await browser.url(`test/pages/Popover.html`);
});

assert.ok(await isHorizontallyCentered(popover, opener), `Popover should be centered`);
});
it("Center", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Center']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");

it("Left", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Left']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");
assert.ok(await isHorizontallyCentered(popover, opener), `Popover should be centered`);
});

assert.ok(await isHorizontallyLeftAligned(popover, opener), `Popover should be left aligned`);
});
it("Left", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Left']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");

it("Right", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Right']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");
assert.ok(await isHorizontallyLeftAligned(popover, opener), `Popover should be left aligned`);
});

assert.ok(await isHorizontallyRightAligned(popover, opener), `Popover should be right aligned`);
});
it("Right", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Right']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");

it("Center, in RTL", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Center']").click();
await browser.$("#rtlCb").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");
assert.ok(await isHorizontallyRightAligned(popover, opener), `Popover should be right aligned`);
});

assert.ok(await isHorizontallyCentered(popover, opener), `Popover should be centered`);
});
it("Center, in RTL", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Center']").click();
await browser.$("#rtlCb").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");

assert.ok(await isHorizontallyCentered(popover, opener), `Popover should be centered`);
});

it("Left, in RTL", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Left']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");
it("Left, in RTL", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Left']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");

assert.ok(isHorizontallyRightAligned(popover, opener), `Popover should be right aligned, flipped by RTL direction`);
assert.ok(isHorizontallyRightAligned(popover, opener), `Popover should be right aligned, flipped by RTL direction`);
});

it("Right, in RTL", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Right']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");

assert.ok(await isHorizontallyLeftAligned(popover, opener), `Popover should be left aligned, flipped by RTL direction`);
});
});

it("Right, in RTL", async () => {
await browser.$("[ui5-radio-button][name='horizontalAlign'][text='Right']").click();
await browser.$("#horizontalAlignBtn").click();
const popover = await browser.$("#popoverHorizontalAlign");
const opener = await browser.$("#targetOpener");
describe("Arrow Horizontal Alignment", () => {
before(async () => {
await browser.url(`test/pages/Popover.html`);
});

it("Arrow centering when opener has big width", async () => {
const opener = await browser.$("#btnFullWidthTop");
await opener.click();
const popover = await browser.$("#popFullWidthTop");
const arrow = await popover.shadow$(".ui5-popover-arrow");

assert.ok(await isHorizontallyCentered(arrow, opener), `Arrow should be centered`);

await browser.keys("Escape");
});

it("Arrow centering when opener is to the left edge", async () => {
const opener = await browser.$("#btnLeftEdgeTop");
await opener.click();
const popover = await browser.$("#popFullWidthTop");
const arrow = await popover.shadow$(".ui5-popover-arrow");

assert.ok(await isHorizontallyCentered(arrow, opener), `Arrow should be centered`);

await browser.keys("Escape");
});

it("Arrow centering when opener is to the right edge", async () => {
const opener = await browser.$("#btnRightEdgeTop");
await opener.click();
const popover = await browser.$("#popFullWidthTop");
const arrow = await popover.shadow$(".ui5-popover-arrow");

assert.ok(await isHorizontallyLeftAligned(popover, opener), `Popover should be left aligned, flipped by RTL direction`);
assert.ok(await isHorizontallyCentered(arrow, opener), `Arrow should be centered`);

await browser.keys("Escape");
});
});
});

Expand Down

0 comments on commit d17a4bc

Please sign in to comment.