1212 p-0
1313 backdrop:bg-transparent
1414 `,
15-
1615 attrs.class
1716 )"
1817 v-bind =" {...attrs, class:undefined}"
1918 :is =" useBackdrop ? 'dialog' : 'div'"
2019 ref =" dialogEl"
21- @mousedown =" useBackdrop ? mousedown = true : undefined"
22- @mouseup.self =" useBackdrop && handleMouseup"
20+ @mousedown.self =" handleMouseup"
2321>
24- <div v-if =" useBackdrop || modelValue" class =" scrollbar-hidden fixed overflow-scroll" :style =" `top:${pos.y}px;left:${pos.x}px;${pos.maxWidth ? `max-width:${pos.maxWidth}px` : ''}`" >
22+ <div v-if =" useBackdrop || modelValue"
23+ class =" scrollbar-hidden fixed overflow-scroll"
24+ :style =" `
25+ top:${pos.y}px;
26+ left:${pos.x}px;
27+ ${pos.maxWidth ? `max-width:${pos.maxWidth}px` : ''}
28+ ${pos.maxHeight ? `max-height:${pos.maxHeight}px` : ''}
29+ `"
30+ >
2531 <slot
2632 name =" popup"
2733 :position =" pos"
3339</template >
3440
3541<script setup lang="ts">
36- import { onMounted , type PropType , ref , watch } from " vue"
42+ import { onMounted , type PropType , ref , useAttrs , watch } from " vue"
3743
3844import { twMerge } from " ../../helpers/twMerge.js"
3945import { linkableByIdProps } from " ../shared/props.js"
@@ -42,8 +48,8 @@ import { linkableByIdProps } from "../shared/props.js"
4248const props = defineProps ({
4349 ... linkableByIdProps (),
4450 useBackdrop: { type: Boolean , required: false , default: true },
45- preferredHorizontal: { type: Array as PropType <(" center" | " right" | " left" | " either" )[]>, default : () => [" center" , " right" , " left" , " either" ]},
46- preferredVertical: { type: Array as PropType <(" top" | " bottom" | " either" )[]>, default : () => [" top" , " bottom" , " either" ]},
51+ preferredHorizontal: { type: Array as PropType <(" center" | " right" | " left" | " either" | " center-screen " )[]>, default : () => [" center" , " right" , " left" , " either" ]},
52+ preferredVertical: { type: Array as PropType <(" top" | " bottom" | " either" | " center-screen " )[]>, default : () => [" top" , " bottom" , " either" ]},
4753})
4854const attrs = useAttrs ()
4955defineOptions ({ name: " lib-popup" })
@@ -53,7 +59,7 @@ const dialogEl = ref<HTMLDialogElement | null>(null)
5359const popupEl = ref <HTMLElement | null >(null )
5460const buttonEl = ref <HTMLElement | null >(null )
5561
56- const pos = ref <{ x: number , y: number , maxWidth? : number }>({} as any )
62+ const pos = ref <{ x: number , y: number , maxWidth? : number , maxHeight ? : number }>({} as any )
5763const modelValue = defineModel <boolean >({ default: false })
5864let isOpen = false
5965
@@ -83,7 +89,7 @@ const recompute = (): void => {
8389 pos .value = {} as any
8490 return
8591 }
86- const finalPos: { x: number , y: number , maxWidth: number } = {} as any
92+ const finalPos: { x: number , y: number , maxWidth? : number , maxHeight ? : number } = {} as any
8793
8894 const el = buttonEl .value .getBoundingClientRect ()
8995 const veil = getVeilBoundingRect (props .useBackdrop ? dialogEl .value : document .body )
@@ -97,10 +103,20 @@ const recompute = (): void => {
97103 const spaceBottom = (veil .y + veil .height ) - (el .y + el .height )
98104
99105 const { preferredHorizontal, preferredVertical } = props
106+ let maxWidth: number
107+ let maxHeight: number
100108 /* eslint-disable no-labels */
101109 outerloop :
102110 for (const type of preferredHorizontal ) {
103111 switch (type ) {
112+ case " center-screen" :
113+ if (popup .width < veil .width ) {
114+ finalPos .x = (veil .width / 2 ) - (popup .width / 2 )
115+ } else {
116+ finalPos .x = 0
117+ maxWidth = finalPos .x
118+ }
119+ break
104120 case " center" :
105121 if (spaceLeftFromCenter >= (popup .width / 2 ) &&
106122 spaceRightFromCenter >= (popup .width / 2 )) {
@@ -133,6 +149,14 @@ const recompute = (): void => {
133149 outerloop :
134150 for (const type of preferredVertical ) {
135151 switch (type ) {
152+ case " center-screen" :
153+ if (popup .height < veil .height ) {
154+ finalPos .y = (veil .height / 2 ) - (popup .height / 2 )
155+ } else {
156+ finalPos .y = 0
157+ maxHeight = finalPos .y
158+ }
159+ break
136160 case " top" :
137161 if (spaceTop >= popup .height ) {
138162 finalPos .y = el .y - popup .height ; break outerloop
@@ -150,7 +174,8 @@ const recompute = (): void => {
150174 }
151175 }
152176 }
153- finalPos .maxWidth = veil .width - finalPos .x
177+ finalPos .maxWidth = maxWidth ?? veil .width - finalPos .x
178+ finalPos .maxHeight = maxHeight ?? veil .height - finalPos .y
154179 /* eslint-enable no-labels */
155180 pos .value = finalPos
156181 })
@@ -198,13 +223,9 @@ watch([() => modelValue.value, () => popupEl.value], () => {
198223})
199224
200225
201- const mousedown = ref (false )
202226const handleMouseup = ($event : MouseEvent ) => {
203227 $event .preventDefault ()
204- if (mousedown .value ) {
205- toggle ()
206- mousedown .value = false
207- }
228+ toggle ()
208229}
209230onMounted (() => {
210231 recompute ()
0 commit comments