@@ -46,7 +46,7 @@ import { getFallbackId, type LinkableByIdProps,type TailwindClassProp } from "..
4646import { twMerge } from " ../../helpers/twMerge.js"
4747import { castType } from " @alanscodelog/utils/castType.js"
4848import { isArray } from " @alanscodelog/utils/isArray.js"
49- import type { IPopupReference , PopupPosition , PopupPositioner , PopupPositionModifier , PopupSpaceInfo } from " ../../types.js"
49+ import type { IPopupReference , PopupPosition , PopupPositioner , PopupPositionModifier , PopupSpaceInfo , SimpleDOMRect } from " ../../types.js"
5050
5151const fallbackId = getFallbackId ()
5252// eslint-disable-next-line no-use-before-define
@@ -65,19 +65,19 @@ defineOptions({ name: "lib-popup" })
6565const dialogEl = ref <HTMLDialogElement | null >(null )
6666const popupEl = ref <IPopupReference | null >(null )
6767const buttonEl = ref <IPopupReference | null >(null )
68+ const backgroundEl = ref <IPopupReference | null >(null )
6869
6970const pos = ref <PopupPosition >({} as any )
7071const modelValue = defineModel <boolean >({ default: false })
7172let isOpen = false
7273
7374
7475/**
75- * We don't have access to the dialog backdrop and without extra styling, it's of 0 width/height,
76- * positioned in the center of the screen, with margins taking up all the space.
76+ * We don't have access to the dialog backdrop and without extra styling, it's of 0 width/height, positioned in the center of the screen, with margins taking up all the space.
7777 *
78- * This returns a modified rect that makes more logical sense. It's also available when we aren't using the dialog element.
78+ * This returns a modified rect that makes more logical sense.
7979 */
80- const getVeilBoundingRect = (el : HTMLElement ): Omit < DOMRect , " toJSON " > => {
80+ const getDialogBoundingRect = (el : HTMLElement ): SimpleDOMRect => {
8181 const rect = el .getBoundingClientRect ()
8282 return {
8383 x: 0 ,
@@ -90,7 +90,7 @@ const getVeilBoundingRect = (el: HTMLElement): Omit<DOMRect, "toJSON"> => {
9090 right: 0 ,
9191 }
9292}
93- let lastButtonElPos: ReturnType < IPopupReference [ " getBoundingClientRect " ]> | undefined
93+ let lastButtonElPos: SimpleDOMRect | undefined
9494const recompute = (force : boolean = false ): void => {
9595 requestAnimationFrame (() => {
9696 const horzHasCenterScreen = isArray (props .preferredHorizontal )
@@ -107,7 +107,11 @@ const recompute = (force: boolean = false): void => {
107107 return
108108 }
109109 const el = buttonEl .value ?.getBoundingClientRect ()
110- const veil = getVeilBoundingRect (props .useBackdrop ? dialogEl .value : document .body )
110+ const bg = backgroundEl .value ?.getBoundingClientRect () ?? (
111+ props .useBackdrop
112+ ? getDialogBoundingRect (dialogEl .value )
113+ : document .body .getBoundingClientRect ()
114+ )
111115 const popup = popupEl .value .getBoundingClientRect ()
112116
113117 let finalPos: { x: number , y: number , maxWidth? : number , maxHeight? : number } = {} as any
@@ -136,30 +140,30 @@ const recompute = (force: boolean = false): void => {
136140 bottom: 0 ,
137141 }
138142 if (el ) {
139- space .left = (el .x + el .width ) - veil .x
140- space .leftLeft = el .x - veil .x
141- space .right = (veil .x + veil .width ) - (el .x + el .width )
142- space .rightRight = veil .x + veil .width - el .x
143- space .leftFromCenter = (el .x + (el .width / 2 )) - veil .x
144- space .rightFromCenter = (veil .x + veil .width ) - (el .x + (el .width / 2 ))
145- space .topFromCenter = (el .y + (el .height / 2 )) - veil .y
146- space .bottomFromCenter = (veil .y + veil .height ) - (el .y + (el .height / 2 ))
147- space .top = el .y - veil .y
148- space .bottom = (veil .y + veil .height ) - (el .y + el .height )
143+ space .left = (el .x + el .width ) - bg .x
144+ space .leftLeft = el .x - bg .x
145+ space .right = (bg .x + bg .width ) - (el .x + el .width )
146+ space .rightRight = bg .x + bg .width - el .x
147+ space .leftFromCenter = (el .x + (el .width / 2 )) - bg .x
148+ space .rightFromCenter = (bg .x + bg .width ) - (el .x + (el .width / 2 ))
149+ space .topFromCenter = (el .y + (el .height / 2 )) - bg .y
150+ space .bottomFromCenter = (bg .y + bg .height ) - (el .y + (el .height / 2 ))
151+ space .top = el .y - bg .y
152+ space .bottom = (bg .y + bg .height ) - (el .y + el .height )
149153 }
150154 const { preferredHorizontal, preferredVertical } = props
151155 let maxWidth: number | undefined
152156 let maxHeight: number | undefined
153157 if (typeof preferredHorizontal === " function" ) {
154- finalPos .x = preferredHorizontal (el , popup , veil , space )
158+ finalPos .x = preferredHorizontal (el , popup , bg , space )
155159 } else {
156160 /* eslint-disable no-labels */
157161 outerloop :
158162 for (const type of preferredHorizontal ) {
159163 switch (type ) {
160164 case " center-screen" :
161- if (popup .width < veil .width ) {
162- finalPos .x = (veil .width / 2 ) - (popup .width / 2 )
165+ if (popup .width < bg .width ) {
166+ finalPos .x = (bg .width / 2 ) - (popup .width / 2 )
163167 } else {
164168 finalPos .x = 0
165169 maxWidth = finalPos .x
@@ -198,7 +202,7 @@ const recompute = (force: boolean = false): void => {
198202 if (space .right >= popup .width ) {
199203 finalPos .x = el .x + el .width ; break outerloop
200204 } else {
201- finalPos .x = veil .x + veil .width - popup .width ; break outerloop
205+ finalPos .x = bg .x + bg .width - popup .width ; break outerloop
202206 }
203207
204208 case " right" :
@@ -226,14 +230,14 @@ const recompute = (force: boolean = false): void => {
226230 }
227231 }
228232 if (typeof preferredVertical === " function" ) {
229- finalPos .y = preferredVertical (el , popup , veil , space )
233+ finalPos .y = preferredVertical (el , popup , bg , space )
230234 } else {
231235 outerloop :
232236 for (const type of preferredVertical ) {
233237 switch (type ) {
234238 case " center-screen" :
235- if (popup .height < veil .height ) {
236- finalPos .y = (veil .height / 2 ) - (popup .height / 2 )
239+ if (popup .height < bg .height ) {
240+ finalPos .y = (bg .height / 2 ) - (popup .height / 2 )
237241 } else {
238242 finalPos .y = 0
239243 maxHeight = finalPos .y
@@ -263,7 +267,7 @@ const recompute = (force: boolean = false): void => {
263267 if (space .bottom >= popup .height ) {
264268 finalPos .y = el .y + el .height ; break outerloop
265269 } else {
266- finalPos .y = veil .y + veil .height - popup .height ; break outerloop
270+ finalPos .y = bg .y + bg .height - popup .height ; break outerloop
267271 }
268272 case " center-most" :
269273 case " center" :
@@ -299,7 +303,7 @@ const recompute = (force: boolean = false): void => {
299303 finalPos .maxHeight = maxHeight ?? undefined
300304 /* eslint-enable no-labels */
301305 if (props .modifyPosition ) {
302- finalPos = props .modifyPosition (finalPos , el , popup , veil , space )
306+ finalPos = props .modifyPosition (finalPos , el , popup , bg , space )
303307 }
304308 pos .value = finalPos
305309 lastButtonElPos = el
@@ -363,7 +367,11 @@ defineExpose({
363367 recompute ,
364368 setReference : (el : IPopupReference | null ) => {
365369 buttonEl .value = el
366- }
370+ },
371+ setBackground : (el : IPopupReference | null ) => {
372+ backgroundEl .value = el
373+ },
374+
367375})
368376
369377 </script >
0 commit comments