From ce00954e7c0c6b4d5640c886f88065db749d49c7 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 12 Jun 2022 15:21:09 +0300
Subject: [PATCH] turns out it is needed still + some code cleanup

---
 src/components/popover/popover.js | 40 ++++++++++++++++++++-----------
 1 file changed, 26 insertions(+), 14 deletions(-)

diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index 1e8b3fb613..a91c084ffe 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -58,10 +58,18 @@ const Popover = {
       const anchorEl = (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el
       // SVGs don't have offsetWidth/Height, use fallback
       const anchorHeight = anchorEl.offsetHeight || anchorEl.clientHeight
+      const anchorWidth = anchorEl.offsetWidth || anchorEl.clientWidth
       const anchorScreenBox = anchorEl.getBoundingClientRect()
 
-      // Screen position of the origin point for popover
-      const origin = { x: anchorScreenBox.left, y: anchorScreenBox.top }
+      const anchorStyle = getComputedStyle(anchorEl)
+      const topPadding = parseFloat(anchorStyle.paddingTop)
+      const bottomPadding = parseFloat(anchorStyle.paddingBottom)
+
+      // Screen position of the origin point for popover = center of the anchor
+      const origin = {
+        x: anchorScreenBox.left + anchorWidth * 0.5,
+        y: anchorScreenBox.top + anchorHeight * 0.5
+      }
       const content = this.$refs.content
 
       // Minor optimization, don't call a slow reflow call if we don't have to
@@ -89,15 +97,17 @@ const Popover = {
         max: window.innerHeight - (margin.bottom || 5)
       }
 
-      let horizOffset = 0
+      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 ((origin.x) < xBounds.min) {
-        horizOffset += -origin.x + xBounds.min
+      if (leftBorder < xBounds.min) {
+        horizOffset += xBounds.min - leftBorder
       }
 
       // If overflowing from right, move it so that it doesn't
-      if ((origin.x + horizOffset + content.offsetWidth) > xBounds.max) {
-        horizOffset -= (origin.x + horizOffset + content.offsetWidth) - xBounds.max
+      if (rightBorder > xBounds.max) {
+        horizOffset -= rightBorder - xBounds.max
       }
 
       // Default to whatever user wished with placement prop
@@ -106,23 +116,25 @@ const Popover = {
       // Handle special cases, first force to displaying on top if there's not space on bottom,
       // regardless of what placement value was. Then check if there's not space on top, and
       // force to bottom, again regardless of what placement value was.
-      if (origin.y + content.offsetHeight > yBounds.max) usingTop = true
-      if (origin.y - content.offsetHeight < yBounds.min) usingTop = false
+      const topBoundary = origin.y - anchorHeight * 0.5 + (this.removePadding ? topPadding : 0)
+      const bottomBoundary = origin.y + anchorHeight * 0.5 - (this.removePadding ? bottomPadding : 0)
+      if (bottomBoundary + content.offsetHeight > yBounds.max) usingTop = true
+      if (topBoundary - content.offsetHeight < yBounds.min) usingTop = false
 
       const yOffset = (this.offset && this.offset.y) || 0
       const translateY = usingTop
-        ? yOffset - content.offsetHeight
-        : yOffset + anchorHeight
+        ? topBoundary - yOffset - content.offsetHeight
+        : bottomBoundary + yOffset
 
       const xOffset = (this.offset && this.offset.x) || 0
-      const translateX = horizOffset + xOffset
+      const translateX = origin.x + horizOffset + xOffset
 
       // Note, separate translateX and translateY avoids blurry text on chromium,
       // single translate or translate3d resulted in blurry text.
       this.styles = {
         opacity: 1,
-        left: `${Math.round(origin.x + translateX)}px`,
-        top: `${Math.round(origin.y + translateY)}px`,
+        left: `${Math.round(translateX)}px`,
+        top: `${Math.round(translateY)}px`,
         position: 'fixed'
       }
 
-- 
GitLab