diff --git a/packages/main/src/Popover.js b/packages/main/src/Popover.js index 99b50f6d82d3..30a2b93afb77 100644 --- a/packages/main/src/Popover.js +++ b/packages/main/src/Popover.js @@ -1,4 +1,5 @@ import Integer from "@ui5/webcomponents-base/dist/types/Integer.js"; +import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; import Popup from "./Popup.js"; import PopoverPlacementType from "./types/PopoverPlacementType.js"; import PopoverVerticalAlign from "./types/PopoverVerticalAlign.js"; @@ -250,6 +251,12 @@ const metadata = { * @public */ class Popover extends Popup { + constructor() { + super(); + + this._handleResize = this.handleResize.bind(this); + } + static get metadata() { return metadata; } @@ -266,6 +273,14 @@ class Popover extends Popup { return 10; // px } + onEnterDOM() { + ResizeHandler.register(this, this._handleResize); + } + + onExitDOM() { + ResizeHandler.deregister(this, this._handleResize); + } + isOpenerClicked(event) { const target = event.target; return target === this._opener || (target.getFocusDomRef && target.getFocusDomRef() === this._opener) || event.composedPath().indexOf(this._opener) > -1; @@ -277,14 +292,15 @@ class Popover extends Popup { * @param {boolean} preventInitialFocus prevents applying the focus inside the popover * @public */ - openBy(opener, preventInitialFocus = false) { + async openBy(opener, preventInitialFocus = false) { if (!opener || this.opened) { return; } this._opener = opener; + this._openerRect = opener.getBoundingClientRect(); - super.open(preventInitialFocus); + await super.open(preventInitialFocus); } /** @@ -332,21 +348,36 @@ class Popover extends Popup { && openerRect.right === 0; } + handleResize() { + if (this.opened) { + this.reposition(); + } + } + reposition() { this.show(); } show() { let placement; - const popoverSize = this.popoverSize; - const openerRect = this._opener.getBoundingClientRect(); + const popoverSize = this.getPopoverSize(); + + if (popoverSize.width === 0 || popoverSize.height === 0) { + // size can not be determined properly at this point, popover will be shown with the next reposition + return; + } - if (this.shouldCloseDueToNoOpener(openerRect) && this.isFocusWithin()) { + if (this.isOpen()) { + // update opener rect if it was changed during the popover being opened + this._openerRect = this._opener.getBoundingClientRect(); + } + + if (this.shouldCloseDueToNoOpener(this._openerRect) && this.isFocusWithin()) { // reuse the old placement as the opener is not available, // but keep the popover open as the focus is within placement = this._oldPlacement; } else { - placement = this.calcPlacement(openerRect, popoverSize); + placement = this.calcPlacement(this._openerRect, popoverSize); } const stretching = this.horizontalAlign === PopoverHorizontalAlign.Stretch; @@ -379,7 +410,7 @@ class Popover extends Popup { } } - get popoverSize() { + getPopoverSize() { let width, height; let rect = this.getBoundingClientRect(); @@ -391,17 +422,15 @@ class Popover extends Popup { return { width, height }; } - this.style.visibility = "hidden"; this.style.display = "block"; + this.style.top = "-10000px"; + this.style.left = "-10000px"; rect = this.getBoundingClientRect(); width = rect.width; height = rect.height; - this.hide(); - this.style.visibility = "visible"; - return { width, height }; } @@ -595,6 +624,7 @@ class Popover extends Popup { switch (this.horizontalAlign) { case PopoverHorizontalAlign.Center: case PopoverHorizontalAlign.Stretch: + left = targetRect.left - (popoverSize.width - targetRect.width) / 2; break; case PopoverHorizontalAlign.Left: diff --git a/packages/main/src/Popup.js b/packages/main/src/Popup.js index 1cb5258c2871..419a9a0ad6f5 100644 --- a/packages/main/src/Popup.js +++ b/packages/main/src/Popup.js @@ -1,3 +1,4 @@ +import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { getRTL } from "@ui5/webcomponents-base/dist/config/RTL.js"; import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; @@ -321,7 +322,7 @@ class Popup extends UI5Element { * @param {boolean} preventInitialFocus prevents applying the focus inside the popup * @public */ - open(preventInitialFocus) { + async open(preventInitialFocus) { const prevented = !this.fireEvent("before-open", {}, true, false); if (prevented) { return; @@ -337,6 +338,7 @@ class Popup extends UI5Element { this._zIndex = getNextZIndex(); this.style.zIndex = this._zIndex; this._focusedElementBeforeOpen = getFocusedElement(); + this.show(); if (!this._disableInitialFocus && !preventInitialFocus) { @@ -346,6 +348,8 @@ class Popup extends UI5Element { this._addOpenedPopup(); this.opened = true; + + await renderFinished(); this.fireEvent("after-open", {}, false, false); } diff --git a/packages/main/test/pages/Popover.html b/packages/main/test/pages/Popover.html index 6df3f5c34abb..0d7dd0719d77 100644 --- a/packages/main/test/pages/Popover.html +++ b/packages/main/test/pages/Popover.html @@ -137,8 +137,8 @@ - Hello - World + +
@@ -375,6 +375,13 @@ Second button Sample text for the ui5-popover +
+
+ +
+ +
+
diff --git a/packages/main/test/specs/Popover.spec.js b/packages/main/test/specs/Popover.spec.js index 1a90dbb1d623..5d0e38b8455c 100644 --- a/packages/main/test/specs/Popover.spec.js +++ b/packages/main/test/specs/Popover.spec.js @@ -250,6 +250,24 @@ describe("Popover general interaction", () => { assert.ok(activeElementId, popoverId, "Popover remains focused"); }); + + it("tests that dynamically created popover is opened", () => { + browser.url("http://localhost:8080/test-resources/pages/Popover.html"); + + const btnOpenDynamic = $("#btnOpenDynamic"); + btnOpenDynamic.click(); + const popover = $('#dynamic-popover'); + + browser.waitUntil( + () => popover.getCSSProperty("top").parsed.value > 0 && popover.getCSSProperty("left").parsed.value > 0, + { + timeout: 500, + timeoutMsg: "popover was not opened after a timeout" + } + ); + + assert.ok(true, "popover is opened"); + }); }); describe("Acc", () => {