diff --git a/packages/main/src/Popover.ts b/packages/main/src/Popover.ts index f754ba49f0ef..2e2783111e5f 100644 --- a/packages/main/src/Popover.ts +++ b/packages/main/src/Popover.ts @@ -20,6 +20,9 @@ import PopoverTemplate from "./generated/templates/PopoverTemplate.lit.js"; import browserScrollbarCSS from "./generated/themes/BrowserScrollbar.css.js"; import PopupsCommonCss from "./generated/themes/PopupsCommon.css.js"; import PopoverCss from "./generated/themes/Popover.css.js"; +import { calculateOrigCoordinates } from "./PopoverHelpers.js"; + +const scale = 0.7; const ARROW_SIZE = 8; @@ -443,7 +446,7 @@ class Popover extends Popup { let left = clamp( this._left!, Popover.VIEWPORT_MARGIN, - document.documentElement.clientWidth - popoverSize.width - Popover.VIEWPORT_MARGIN, + document.documentElement.clientWidth * scale - popoverSize.width - Popover.VIEWPORT_MARGIN, ); if (this.actualPlacementType === PopoverPlacementType.Right) { @@ -453,7 +456,7 @@ class Popover extends Popup { let top = clamp( this._top!, Popover.VIEWPORT_MARGIN, - document.documentElement.clientHeight - popoverSize.height - Popover.VIEWPORT_MARGIN, + document.documentElement.clientHeight * scale - popoverSize.height - Popover.VIEWPORT_MARGIN, ); if (this.actualPlacementType === PopoverPlacementType.Bottom) { @@ -463,7 +466,19 @@ class Popover extends Popup { this.arrowTranslateX = placement!.arrow.x; this.arrowTranslateY = placement!.arrow.y; + const transformedParent = this.findTransformedParent(); top = this._adjustForIOSKeyboard(top); + const stackingContextOffset = this._getStackingContextOffset(); + const { x: stackingLeft, y: stackingTop } = calculateOrigCoordinates(stackingContextOffset.left, stackingContextOffset.top, transformedParent); + left -= stackingLeft; + top -= stackingTop; + + // containingNode + if (transformedParent) { + const { x, y } = calculateOrigCoordinates(left, top, transformedParent); + left = x; + top = y; + } Object.assign(this.style, { top: `${top}px`, @@ -475,6 +490,16 @@ class Popover extends Popup { } } + findTransformedParent() { + let parent = this.parentElement; + while (parent) { + if (window.getComputedStyle(parent).transform) { + return parent; + } + parent = parent.parentElement; + } + } + /** * Adjust the desired top position to compensate for shift of the screen * caused by opened keyboard on iOS which affects all elements with position:fixed. @@ -492,6 +517,23 @@ class Popover extends Popup { return top + (Number.parseInt(this.style.top || "0") - actualTop); } + _getStackingContextOffset() { + let parentNode = this.parentElement ? this.parentNode as HTMLElement : (this.parentNode as ShadowRoot).host as HTMLElement; + + while (parentNode) { + const computedStyle = getComputedStyle(parentNode); + + if (["size", "inline-size"].indexOf(computedStyle.containerType) > -1 + || computedStyle.transform !== "none") { + return parentNode.getBoundingClientRect(); + } + + parentNode = parentNode.parentElement ? parentNode.parentNode as HTMLElement : (parentNode.parentNode as ShadowRoot).host as HTMLElement; + } + + return { left: 0, top: 0 }; + } + getPopoverSize(): PopoverSize { const rect = this.getBoundingClientRect(), width = rect.width, @@ -520,8 +562,8 @@ class Popover extends Popup { let top = 0; const allowTargetOverlap = this.allowTargetOverlap; - const clientWidth = document.documentElement.clientWidth; - const clientHeight = document.documentElement.clientHeight; + const clientWidth = document.documentElement.clientWidth * scale; + const clientHeight = document.documentElement.clientHeight * scale; let maxHeight = clientHeight; let maxWidth = clientWidth; diff --git a/packages/main/src/PopoverHelpers.ts b/packages/main/src/PopoverHelpers.ts new file mode 100644 index 000000000000..90f01c34ebc9 --- /dev/null +++ b/packages/main/src/PopoverHelpers.ts @@ -0,0 +1,39 @@ +// @ts-nocheck +const applyMatrix = (a: number, b: number, c: number, d: number, e: number, f: number, x: number, y: number): { x: number, y: number } => { + return { x: a*x + c*y + e, y: b*x + d*y + f} +} + +function translate(x: number, y: number, tx: number, ty: number) { + return applyMatrix(1,0,0,1,tx,ty,x,y); +} +function scale(x: number, y: number, scaleX: number, scaleY: number) { + return applyMatrix(scaleX, 0, 0, scaleY, 0, 0, x, y); +} + +// let translated = translate(8, 8, -466, -26) +// let scaled = scale(translated.x, translated.y, 0.7, 0.7) +// let translated2 = translate(scaled.x, scaled.y, 466, 26) + +function scaleWithOrigin(x: number, y: number, scaleX: number, scaleY: number, originX: number, originY: number) { + let translated = translate(x, y, -1 * originX, -1 * originY) + let scaled = scale(translated.x, translated.y, scaleX, scaleY) + let translated2 = translate(scaled.x, scaled.y, originX, originY) + return translated2; +} + +const calculateOrigCoordinates = (x: number, y: number, transformedElement: HTMLElement | undefined) => { + if (!transformedElement) { + return { x, y }; + } + let { transform, transformOrigin, marginLeft, marginTop } = window.getComputedStyle(transformedElement); + const transformArgs = transform.replace("matrix(", "").replace(")", "").split(",").map(v => parseFloat(v)); + + marginLeft = parseFloat(marginLeft); + marginTop = parseFloat(marginTop); + + const [ originX, originY ] = transformOrigin.split(" ").map(x => parseFloat(x)); + return scaleWithOrigin(x, y, 1 / transformArgs[0], 1 / transformArgs[3], originX + (marginLeft as number), originY + (marginTop as number)); +} + +window.calculateOrigCoordinates = calculateOrigCoordinates; +export { scaleWithOrigin, calculateOrigCoordinates }; diff --git a/packages/main/test/pages/Popover.html b/packages/main/test/pages/Popover.html index 03c011b2ffd5..1db54e6a3a4e 100644 --- a/packages/main/test/pages/Popover.html +++ b/packages/main/test/pages/Popover.html @@ -27,6 +27,37 @@ + + + Open Popover + + + + + Hello + World + Again + + +
+
+ + Super Danger ! + + + + Hello + World + Again + + +
+
+ + + +
+ Click me ! @@ -43,29 +74,9 @@

- Open Popover - - - Hello - World - Again - -
-
- - Super Danger ! - - - - Hello - World - Again - - -


@@ -395,7 +406,7 @@ Dialog Focus
Header text
- +