commit: d3b5d27f297ae37a9684cb7d8fb2602e4c66b919
parent 7c633aa9525c8a0533281947c587ff1a5ded75ec
Author: Henry Jameson <me@hjkos.com>
Date:   Wed, 15 Jun 2022 03:50:57 +0300
properly center user popovers
Diffstat:
1 file changed, 40 insertions(+), 28 deletions(-)
diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
@@ -79,9 +79,10 @@ const Popover = {
         x: anchorScreenBox.left + anchorWidth * 0.5,
         y: anchorScreenBox.top + anchorHeight * 0.5
       }
-      const content = this.overlayCentersSelector
+      const content = this.$refs.content
+      const overlayCenter = this.overlayCentersSelector
         ? this.$refs.content.querySelector(this.overlayCentersSelector)
-        : this.$refs.content
+        : null
 
       // Minor optimization, don't call a slow reflow call if we don't have to
       const parentScreenBox = this.boundTo &&
@@ -108,20 +109,39 @@ const Popover = {
         max: window.innerHeight - (margin.bottom || 5)
       }
 
-      if (!this.overlayCenters) {
-        let horizOffset = content.offsetWidth * -0.5
-        const leftBorder = origin.x + horizOffset
-        const rightBorder = origin.x - horizOffset
-        // If overflowing from left, move it so that it doesn't
-        if (leftBorder < xBounds.min) {
-          horizOffset += xBounds.min - leftBorder
-        }
+      let horizOffset = 0
+      let vertOffset = 0
 
-        // If overflowing from right, move it so that it doesn't
-        if (rightBorder > xBounds.max) {
-          horizOffset -= rightBorder - xBounds.max
-        }
+      if (overlayCenter) {
+        const box = content.getBoundingClientRect()
+        const overlayCenterScreenBox = overlayCenter.getBoundingClientRect()
+        const leftInnerOffset = overlayCenterScreenBox.left - box.left
+        const topInnerOffset = overlayCenterScreenBox.top - box.top
+        horizOffset = -leftInnerOffset - overlayCenter.offsetWidth * 0.5
+        vertOffset = -topInnerOffset - overlayCenter.offsetWidth * 0.5
+      } else {
+        horizOffset = content.offsetWidth * -0.5
+        vertOffset = content.offsetWidth * -0.5
+      }
+      const leftBorder = origin.x + horizOffset
+      const rightBorder = origin.x - horizOffset
+      // If overflowing from left, move it so that it doesn't
+      if (leftBorder < xBounds.min) {
+        horizOffset += xBounds.min - leftBorder
+      }
+
+      // If overflowing from right, move it so that it doesn't
+      if (rightBorder > xBounds.max) {
+        horizOffset -= rightBorder - xBounds.max
+      }
 
+      let translateX = 0
+      let translateY = 0
+
+      if (overlayCenter) {
+        translateX = origin.x + horizOffset
+        translateY = origin.y + vertOffset
+      } else {
         // Default to whatever user wished with placement prop
         let usingTop = this.placement !== 'bottom'
 
@@ -134,25 +154,17 @@ const Popover = {
         if (topBoundary - content.offsetHeight < yBounds.min) usingTop = false
 
         const yOffset = (this.offset && this.offset.y) || 0
-        const translateY = usingTop
+        translateY = usingTop
           ? topBoundary - yOffset - content.offsetHeight
           : bottomBoundary + yOffset
 
         const xOffset = (this.offset && this.offset.x) || 0
-        const translateX = origin.x + horizOffset + xOffset
-
-        this.styles = {
-          left: `${Math.round(translateX)}px`,
-          top: `${Math.round(translateY)}px`
-        }
-      } else {
-        const translateY = origin.y - content.offsetHeight
-        const translateX = origin.x - content.offsetWidth
+        translateX = origin.x + horizOffset + xOffset
+      }
 
-        this.styles = {
-          left: `${Math.round(translateX)}px`,
-          top: `${Math.round(translateY)}px`
-        }
+      this.styles = {
+        left: `${Math.round(translateX)}px`,
+        top: `${Math.round(translateY)}px`
       }
 
       if (parentScreenBox) {