Skip to content

Commit b30ea62

Browse files
committed
feat: popup no longers needs relative el for positioning if center-screen is the first preferredHorizontal and Vertical placement
1 parent cc61c96 commit b30ea62

File tree

1 file changed

+37
-18
lines changed

1 file changed

+37
-18
lines changed

src/components/LibPopup/LibPopup.vue

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { onMounted, type PropType, ref, useAttrs, watch , type HTMLAttributes }
4444
import { getFallbackId, type LinkableByIdProps,type TailwindClassProp } from "../shared/props.js"
4545
4646
import { twMerge } from "../../helpers/twMerge.js"
47+
import { castType } from "@alanscodelog/utils"
4748
4849
const fallbackId = getFallbackId()
4950
// eslint-disable-next-line no-use-before-define
@@ -86,22 +87,33 @@ const getVeilBoundingRect = (el: HTMLElement): Omit<DOMRect, "toJSON"> => {
8687
}
8788
const recompute = (): void => {
8889
requestAnimationFrame(() => {
89-
if (!buttonEl.value || !popupEl.value || !dialogEl.value) {
90+
const allAreCenterScreen = props.preferredHorizontal[0] === "center-screen" && props.preferredVertical[0] === "center-screen"
91+
if ((!buttonEl.value && !allAreCenterScreen) || !popupEl.value || !dialogEl.value) {
9092
pos.value = {} as any
9193
return
9294
}
9395
const finalPos: { x: number, y: number, maxWidth?: number, maxHeight?: number } = {} as any
9496
95-
const el = buttonEl.value.getBoundingClientRect()
97+
const el = buttonEl.value?.getBoundingClientRect()
9698
const veil = getVeilBoundingRect(props.useBackdrop ? dialogEl.value : document.body)
9799
const popup = popupEl.value.getBoundingClientRect()
98100
99-
const spaceLeft = (el.x + el.width) - veil.x
100-
const spaceRight = (veil.x + veil.width) - el.x
101-
const spaceLeftFromCenter = (el.x + (el.width / 2)) - veil.x
102-
const spaceRightFromCenter = (veil.x + veil.width) - (el.x + (el.width / 2))
103-
const spaceTop = el.y - veil.y
104-
const spaceBottom = (veil.y + veil.height) - (el.y + el.height)
101+
const space = {
102+
left: 0,
103+
right: 0,
104+
leftFromCenter: 0,
105+
rightFromCenter: 0,
106+
top: 0,
107+
bottom: 0,
108+
}
109+
if (el) {
110+
space.left = (el.x + el.width) - veil.x
111+
space.right = (veil.x + veil.width) - (el.x + el.width)
112+
space.leftFromCenter = (el.x + (el.width / 2)) - veil.x
113+
space.rightFromCenter = (veil.x + veil.width) - (el.x + (el.width / 2))
114+
space.top = el.y - veil.y
115+
space.bottom = (veil.y + veil.height) - (el.y + el.height)
116+
}
105117
106118
const { preferredHorizontal, preferredVertical } = props
107119
let maxWidth: number | undefined
@@ -119,29 +131,33 @@ const recompute = (): void => {
119131
}
120132
break
121133
case "center":
122-
if (spaceLeftFromCenter >= (popup.width / 2) &&
123-
spaceRightFromCenter >= (popup.width / 2)) {
134+
castType<DOMRect>(el)
135+
if (space.leftFromCenter >= (popup.width / 2) &&
136+
space.rightFromCenter >= (popup.width / 2)) {
124137
finalPos.x = el.x + (el.width / 2) - (popup.width / 2)
125138
break outerloop
126139
}
127140
// todo temp fix when it's too wide, will prefer left
128-
if (((spaceRightFromCenter + spaceLeftFromCenter) <= popup.width)) {
141+
if (((space.rightFromCenter + space.leftFromCenter) <= popup.width)) {
129142
finalPos.x = 0
130143
break outerloop
131144
}
132145
break
133146
case "right":
134-
if (spaceRight >= popup.width) {
147+
castType<DOMRect>(el)
148+
if (space.right >= popup.width) {
135149
finalPos.x = el.x; break outerloop
136150
}
137151
break
138152
case "left":
139-
if (spaceLeft >= popup.width) {
153+
castType<DOMRect>(el)
154+
if (space.left >= popup.width) {
140155
finalPos.x = (el.x + el.width) - popup.width; break outerloop
141156
}
142157
break
143158
case "either": {
144-
if (spaceRight >= spaceLeft) {
159+
castType<DOMRect>(el)
160+
if (space.right >= space.left) {
145161
finalPos.x = el.x; break outerloop
146162
} else { finalPos.x = (el.x + el.width) - popup.width; break outerloop }
147163
}
@@ -159,17 +175,20 @@ const recompute = (): void => {
159175
}
160176
break
161177
case "top":
162-
if (spaceTop >= popup.height) {
178+
castType<DOMRect>(el)
179+
if (space.top >= popup.height) {
163180
finalPos.y = el.y - popup.height; break outerloop
164181
}
165182
break
166183
case "bottom":
167-
if (spaceBottom >= popup.height) {
184+
castType<DOMRect>(el)
185+
if (space.bottom >= popup.height) {
168186
finalPos.y = el.y + el.height; break outerloop
169187
}
170188
break
171189
case "either": {
172-
if (spaceTop >= spaceBottom) {
190+
castType<DOMRect>(el)
191+
if (space.top >= space.bottom) {
173192
finalPos.y = el.y - popup.height; break outerloop
174193
} else { finalPos.y = el.y + el.height; break outerloop }
175194
}
@@ -212,7 +231,7 @@ const unbindListeners = () => {
212231
window.removeEventListener("resize", recompute)
213232
}
214233
215-
watch([() => modelValue.value, () => popupEl.value], () => {
234+
watch([modelValue, popupEl], () => {
216235
if (modelValue.value) {
217236
show()
218237
recompute()

0 commit comments

Comments
 (0)