From 020cddc76efdc489144eefe9ef7114350c419e05 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 12 Jan 2023 14:42:05 +0000 Subject: [PATCH] Improve dropdown logic --- .../bbui/src/Actions/position_dropdown.js | 96 ++++++++----------- 1 file changed, 39 insertions(+), 57 deletions(-) diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js index 88f8783633..e89f28a69e 100644 --- a/packages/bbui/src/Actions/position_dropdown.js +++ b/packages/bbui/src/Actions/position_dropdown.js @@ -2,86 +2,68 @@ export default function positionDropdown( element, { anchor, align, maxWidth, useAnchorWidth } ) { - let positionSide = "top" - let maxHeight = 0 - let minWidth = 0 - let dimensions = getDimensions(anchor) - - function getDimensions() { - const { - bottom, - top: spaceAbove, - left, - width, - } = anchor.getBoundingClientRect() - const spaceBelow = window.innerHeight - bottom - const containerRect = element.getBoundingClientRect() - - let y - if (window.innerHeight - bottom < 100) { - positionSide = "bottom" - maxHeight = spaceAbove - 20 - y = window.innerHeight - spaceAbove + 5 - } else { - positionSide = "top" - y = bottom + 5 - maxHeight = spaceBelow - 20 + const update = () => { + console.log("update") + const anchorBounds = anchor.getBoundingClientRect() + const elementBounds = element.getBoundingClientRect() + let styles = { + maxHeight: null, + minWidth: null, + maxWidth, + left: null, + top: null, } + // Determine vertical styles + if (window.innerHeight - anchorBounds.bottom < 100) { + styles.top = anchorBounds.top - elementBounds.height - 5 + } else { + styles.top = anchorBounds.bottom + 5 + styles.maxHeight = window.innerHeight - anchorBounds.bottom - 20 + } + + // Determine horizontal styles if (!maxWidth && useAnchorWidth) { - maxWidth = width + styles.maxWidth = anchorBounds.width } if (useAnchorWidth) { - minWidth = width + styles.minWidth = anchorBounds.width } - - return { - [positionSide]: y, - left, - width, - containerWidth: containerRect.width, - } - } - - function calcLeftPosition() { - let left - if (align === "right") { - left = dimensions.left + dimensions.width - dimensions.containerWidth + styles.left = anchorBounds.left + anchorBounds.width - elementBounds.width } else if (align === "right-side") { - left = dimensions.left + dimensions.width + styles.left = anchorBounds.left + anchorBounds.width } else { - left = dimensions.left + styles.left = anchorBounds.left } - return left + // Apply styles + Object.entries(styles).forEach(([style, value]) => { + if (value) { + element.style[style] = `${value.toFixed(0)}px` + } else { + element.style[style] = null + } + }) } + // Apply initial styles which don't need to change element.style.position = "absolute" element.style.zIndex = "9999" - if (maxWidth) { - element.style.maxWidth = `${maxWidth}px` - } - if (minWidth) { - element.style.minWidth = `${minWidth}px` - } - element.style.maxHeight = `${maxHeight.toFixed(0)}px` - element.style.transformOrigin = `center ${positionSide}` - element.style[positionSide] = `${dimensions[positionSide]}px` - element.style.left = `${calcLeftPosition(dimensions).toFixed(0)}px` + // Observe both anchor and element and resize the popover as appropriate const resizeObserver = new ResizeObserver(entries => { - entries.forEach(() => { - dimensions = getDimensions() - element.style[positionSide] = `${dimensions[positionSide]}px` - element.style.left = `${calcLeftPosition(dimensions).toFixed(0)}px` - }) + entries.forEach(update) }) resizeObserver.observe(anchor) resizeObserver.observe(element) + + document.addEventListener("scroll", update, true) + return { destroy() { resizeObserver.disconnect() + document.removeEventListener("scroll", update, true) }, } }