Rewrite position dropdown logic to be much smarter
This commit is contained in:
parent
f08562e0e4
commit
9c244f6645
|
@ -28,6 +28,7 @@ export default function positionDropdown(element, opts) {
|
||||||
// Compute bounds
|
// Compute bounds
|
||||||
const anchorBounds = anchor.getBoundingClientRect()
|
const anchorBounds = anchor.getBoundingClientRect()
|
||||||
const elementBounds = element.getBoundingClientRect()
|
const elementBounds = element.getBoundingClientRect()
|
||||||
|
const padding = 8
|
||||||
let styles = {
|
let styles = {
|
||||||
maxHeight: null,
|
maxHeight: null,
|
||||||
minWidth,
|
minWidth,
|
||||||
|
@ -42,45 +43,46 @@ export default function positionDropdown(element, opts) {
|
||||||
offset: opts.offset,
|
offset: opts.offset,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const renderHeight = maxHeight || elementBounds.height
|
// "outside" alignment (popover vertical center = anchor vertical center)
|
||||||
|
|
||||||
// Determine vertical styles
|
|
||||||
const topSpace = anchorBounds.top
|
|
||||||
const bottomSpace = window.innerHeight - anchorBounds.bottom
|
|
||||||
if (align === "right-outside" || align === "left-outside") {
|
if (align === "right-outside" || align === "left-outside") {
|
||||||
styles.top =
|
styles.top =
|
||||||
anchorBounds.top + anchorBounds.height / 2 - elementBounds.height / 2
|
anchorBounds.top + anchorBounds.height / 2 - elementBounds.height / 2
|
||||||
styles.maxHeight = maxHeight
|
styles.maxHeight = maxHeight
|
||||||
if (styles.top + elementBounds.height > window.innerHeight) {
|
}
|
||||||
styles.top = window.innerHeight - elementBounds.height
|
|
||||||
}
|
// Normal left/right alignment (top popover edge = botom anchor edge)
|
||||||
} else if (
|
else {
|
||||||
window.innerHeight - anchorBounds.bottom < renderHeight + offset &&
|
|
||||||
topSpace - bottomSpace > 100
|
|
||||||
) {
|
|
||||||
styles.top = anchorBounds.top - renderHeight - offset
|
|
||||||
styles.maxHeight = maxHeight
|
|
||||||
} else {
|
|
||||||
styles.top = anchorBounds.bottom + offset
|
styles.top = anchorBounds.bottom + offset
|
||||||
styles.maxHeight =
|
styles.maxHeight = maxHeight || window.innerHeight - styles.top
|
||||||
maxHeight || window.innerHeight - anchorBounds.bottom - 20
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine horizontal styles
|
// Determine horizontal styles
|
||||||
|
// Use anchor width if required
|
||||||
if (!maxWidth && useAnchorWidth) {
|
if (!maxWidth && useAnchorWidth) {
|
||||||
styles.maxWidth = anchorBounds.width
|
styles.maxWidth = anchorBounds.width
|
||||||
}
|
}
|
||||||
if (useAnchorWidth) {
|
if (useAnchorWidth) {
|
||||||
styles.minWidth = anchorBounds.width
|
styles.minWidth = anchorBounds.width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Right alignment (right popover edge = right anchor edge)
|
||||||
if (align === "right") {
|
if (align === "right") {
|
||||||
styles.left =
|
styles.left =
|
||||||
anchorBounds.left + anchorBounds.width - elementBounds.width
|
anchorBounds.left + anchorBounds.width - elementBounds.width
|
||||||
} else if (align === "right-outside") {
|
}
|
||||||
|
|
||||||
|
// Right outside alignment (left popover edge = right anchor edge)
|
||||||
|
else if (align === "right-outside") {
|
||||||
styles.left = anchorBounds.right + offset
|
styles.left = anchorBounds.right + offset
|
||||||
} else if (align === "left-outside") {
|
}
|
||||||
|
|
||||||
|
// Left outside alignment (right popover edge = left anchor edge)
|
||||||
|
else if (align === "left-outside") {
|
||||||
styles.left = anchorBounds.left - elementBounds.width - offset
|
styles.left = anchorBounds.left - elementBounds.width - offset
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
// Left alignment by default (left popover edge = left anchor edge)
|
||||||
|
else {
|
||||||
styles.left = anchorBounds.left
|
styles.left = anchorBounds.left
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +90,25 @@ export default function positionDropdown(element, opts) {
|
||||||
if (noShrink) {
|
if (noShrink) {
|
||||||
delete styles.maxHeight
|
delete styles.maxHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle screen overflow
|
||||||
|
// Check right overflow
|
||||||
|
if (styles.left + elementBounds.width > window.innerWidth) {
|
||||||
|
styles.left = window.innerWidth - elementBounds.width - padding
|
||||||
|
}
|
||||||
|
// Check bottom overflow
|
||||||
|
if (styles.top + elementBounds.height > window.innerHeight) {
|
||||||
|
styles.top = window.innerHeight - elementBounds.height - padding
|
||||||
|
|
||||||
|
// If we overflowed off the bottom and therefore locked to the bottom
|
||||||
|
// edge, we might now be covering the anchor. Therefore we can try
|
||||||
|
// moving left or right to reveal the full anchor again.
|
||||||
|
if (anchorBounds.right + elementBounds.width < window.innerWidth) {
|
||||||
|
styles.left = anchorBounds.right
|
||||||
|
} else if (anchorBounds.left - elementBounds.width > 0) {
|
||||||
|
styles.left = anchorBounds.left - elementBounds.width
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply styles
|
// Apply styles
|
||||||
|
|
Loading…
Reference in New Issue