Tweak orientation helper to prevent popups from going off screen

This commit is contained in:
Adrien Maston
2026-01-23 14:06:17 +01:00
parent 65b2db0ec8
commit 764eb8987a
5 changed files with 29 additions and 23 deletions
+2 -2
View File
@@ -27,13 +27,13 @@
&:where(.popup--align-left), &:where(.popup--align-left),
&.orient-left { &.orient-left {
inset-inline: auto 0; inset-inline: auto 0;
transform: translateX(0); transform: translateX(var(--orient-offset, 0px));
} }
&:where(.popup--align-right), &:where(.popup--align-right),
&.orient-right { &.orient-right {
inset-inline: 0 auto; inset-inline: 0 auto;
transform: translateX(0); transform: translateX(var(--orient-offset, 0px));
} }
form { form {
+2 -2
View File
@@ -20,12 +20,12 @@
&.orient-right { &.orient-right {
inset-inline: 0 auto; inset-inline: 0 auto;
translate: 0 -100%; translate: var(--orient-offset, 0px) -100%;
} }
&.orient-left { &.orient-left {
inset-inline: auto 0; inset-inline: auto 0;
translate: 0 -100%; translate: var(--orient-offset, 0px) -100%;
} }
} }
@@ -26,7 +26,7 @@ export default class extends Controller {
this.dialogTarget.showModal() this.dialogTarget.showModal()
} else { } else {
this.dialogTarget.show() this.dialogTarget.show()
orient(this.dialogTarget) orient({ target: this.dialogTarget, anchor: this.element })
} }
this.loadLazyFrames() this.loadLazyFrames()
@@ -46,7 +46,7 @@ export default class extends Controller {
this.dialogTarget.close() this.dialogTarget.close()
this.dialogTarget.setAttribute("aria-hidden", "true") this.dialogTarget.setAttribute("aria-hidden", "true")
this.dialogTarget.blur() this.dialogTarget.blur()
orient(this.dialogTarget, false) orient({ target: this.dialogTarget, reset: true })
this.dispatch("close") this.dispatch("close")
} }
@@ -15,11 +15,11 @@ export default class extends Controller {
} }
mouseEnter(event) { mouseEnter(event) {
orient(this.#tooltipElement) orient({ target: this.#tooltipElement, anchor: this.element })
} }
mouseOut(event) { mouseOut(event) {
orient(this.#tooltipElement, false) orient({ target: this.#tooltipElement, reset: true })
} }
get #tooltipElement() { get #tooltipElement() {
+21 -15
View File
@@ -1,24 +1,30 @@
const EDGE_THRESHOLD = 16 const EDGE_THRESHOLD = 16
export function orient(el, orient = true) { export function orient({ target, anchor = null, reset = false }) {
el.classList.remove("orient-left", "orient-right") target.classList.remove("orient-left", "orient-right")
target.style.removeProperty("--orient-offset")
if (!orient) return if (reset) return
const rightSpace = spaceOnRight(el) const targetGeometry = geometry(target)
const leftSpace = spaceOnLeft(el) const anchorGeometry = geometry(anchor)
if (rightSpace < EDGE_THRESHOLD && rightSpace < leftSpace) { if (targetGeometry.spaceOnRight < EDGE_THRESHOLD && targetGeometry.spaceOnRight < targetGeometry.spaceOnLeft) {
el.classList.add("orient-left") const offset = Math.min(0, anchorGeometry.spaceOnLeft + anchorGeometry.width - targetGeometry.width) * -1
} else if (leftSpace < EDGE_THRESHOLD && leftSpace < rightSpace) { target.classList.add("orient-left")
el.classList.add("orient-right") target.style.setProperty("--orient-offset", `${offset}px`)
} else if (targetGeometry.spaceOnLeft < EDGE_THRESHOLD && targetGeometry.spaceOnLeft < targetGeometry.spaceOnRight) {
const offset = Math.max(0, anchorGeometry.spaceOnLeft + targetGeometry.width - window.innerWidth) * -1
target.classList.add("orient-right")
target.style.setProperty("--orient-offset", `${offset}px`)
} }
} }
function spaceOnLeft(el) { function geometry(el) {
return el.getBoundingClientRect().left const rect = el.getBoundingClientRect()
} return {
spaceOnLeft: rect.left,
function spaceOnRight(el) { spaceOnRight: window.innerWidth - rect.right,
return window.innerWidth - el.getBoundingClientRect().right width: rect.width
}
} }