Improve dropdown logic
This commit is contained in:
parent
1ce4c8a569
commit
020cddc76e
|
@ -2,86 +2,68 @@ export default function positionDropdown(
|
||||||
element,
|
element,
|
||||||
{ anchor, align, maxWidth, useAnchorWidth }
|
{ anchor, align, maxWidth, useAnchorWidth }
|
||||||
) {
|
) {
|
||||||
let positionSide = "top"
|
const update = () => {
|
||||||
let maxHeight = 0
|
console.log("update")
|
||||||
let minWidth = 0
|
const anchorBounds = anchor.getBoundingClientRect()
|
||||||
let dimensions = getDimensions(anchor)
|
const elementBounds = element.getBoundingClientRect()
|
||||||
|
let styles = {
|
||||||
function getDimensions() {
|
maxHeight: null,
|
||||||
const {
|
minWidth: null,
|
||||||
bottom,
|
maxWidth,
|
||||||
top: spaceAbove,
|
left: null,
|
||||||
left,
|
top: null,
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
if (!maxWidth && useAnchorWidth) {
|
||||||
maxWidth = width
|
styles.maxWidth = anchorBounds.width
|
||||||
}
|
}
|
||||||
if (useAnchorWidth) {
|
if (useAnchorWidth) {
|
||||||
minWidth = width
|
styles.minWidth = anchorBounds.width
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
[positionSide]: y,
|
|
||||||
left,
|
|
||||||
width,
|
|
||||||
containerWidth: containerRect.width,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function calcLeftPosition() {
|
|
||||||
let left
|
|
||||||
|
|
||||||
if (align === "right") {
|
if (align === "right") {
|
||||||
left = dimensions.left + dimensions.width - dimensions.containerWidth
|
styles.left = anchorBounds.left + anchorBounds.width - elementBounds.width
|
||||||
} else if (align === "right-side") {
|
} else if (align === "right-side") {
|
||||||
left = dimensions.left + dimensions.width
|
styles.left = anchorBounds.left + anchorBounds.width
|
||||||
} else {
|
} 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.position = "absolute"
|
||||||
element.style.zIndex = "9999"
|
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 => {
|
const resizeObserver = new ResizeObserver(entries => {
|
||||||
entries.forEach(() => {
|
entries.forEach(update)
|
||||||
dimensions = getDimensions()
|
|
||||||
element.style[positionSide] = `${dimensions[positionSide]}px`
|
|
||||||
element.style.left = `${calcLeftPosition(dimensions).toFixed(0)}px`
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
resizeObserver.observe(anchor)
|
resizeObserver.observe(anchor)
|
||||||
resizeObserver.observe(element)
|
resizeObserver.observe(element)
|
||||||
|
|
||||||
|
document.addEventListener("scroll", update, true)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
destroy() {
|
destroy() {
|
||||||
resizeObserver.disconnect()
|
resizeObserver.disconnect()
|
||||||
|
document.removeEventListener("scroll", update, true)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue