Skip to content

Commit 697016e

Browse files
committed
fix(VOverlay): resolve size with CSS function (calc, min, vw) to pixels
1 parent 42f68b3 commit 697016e

2 files changed

Lines changed: 45 additions & 9 deletions

File tree

packages/vuetify/src/components/VDialog/__test__/VDialog.spec.browser.tsx

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { VDialog } from '../VDialog'
33

44
// Utilities
5-
import { commands, render, screen, userEvent, wait } from '@test'
5+
import { commands, page, render, screen, userEvent, wait } from '@test'
66
import { h, nextTick, ref } from 'vue'
77
import { createMemoryHistory, createRouter } from 'vue-router'
88

@@ -40,10 +40,28 @@ describe('VDialog', () => {
4040
</VDialog>
4141
))
4242

43-
await expect.element(screen.getByCSS('.v-overlay__content')).toHaveStyle({ maxWidth: '300px' })
43+
expect(screen.getByCSS('.v-overlay__content')).toHaveStyle({ maxWidth: '300px' })
4444

4545
maxWidth.value = 500
46-
await expect.element(screen.getByCSS('.v-overlay__content')).toHaveStyle({ maxWidth: '500px' })
46+
await expect.poll(() => screen.getByCSS('.v-overlay__content')).toHaveStyle({ maxWidth: '500px' })
47+
})
48+
49+
it('should respect a CSS function max-width', async () => {
50+
await page.viewport(1280, 800) // 50vw resolves to 640px
51+
52+
const model = ref(true)
53+
const maxWidth = ref('min(50vw, 200px)')
54+
render(() => (
55+
<VDialog v-model={ model.value } maxWidth={ maxWidth.value }>
56+
<div>Content</div>
57+
</VDialog>
58+
))
59+
60+
await expect.poll(() => document.querySelector('.v-overlay__content')).not.toBeNull()
61+
expect(screen.getByCSS('.v-overlay__content').getBoundingClientRect()).toMatchObject({ width: 200 })
62+
63+
maxWidth.value = 'min(50vw, 1000px)'
64+
await expect.poll(() => screen.getByCSS('.v-overlay__content').getBoundingClientRect()).toMatchObject({ width: 640 })
4765
})
4866

4967
it('should emit afterLeave', async () => {

packages/vuetify/src/components/VOverlay/locationStrategies.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,18 @@ function staticLocationStrategy (data: LocationStrategyData, props: StrategyProp
186186
return { updateLocation }
187187
}
188188

189+
/** Resolve a CSS length the browser understands (calc(), min(), vw, …) to pixels */
190+
function resolveCssLength (value: string, container: HTMLElement, isWidth: boolean) {
191+
const probe = document.createElement('div')
192+
probe.style.position = 'absolute'
193+
probe.style.visibility = 'hidden'
194+
probe.style[isWidth ? 'width' : 'height'] = value
195+
container.appendChild(probe)
196+
const size = isWidth ? probe.offsetWidth : probe.offsetHeight
197+
container.removeChild(probe)
198+
return size > 0 ? size : Infinity
199+
}
200+
189201
/** Get size of element ignoring max-width/max-height */
190202
function getIntrinsicSize (el: HTMLElement, isRtl: boolean) {
191203
// const scrollables = new Map<Element, [number, number]>()
@@ -257,14 +269,20 @@ function connectedLocationStrategy (data: LocationStrategyData, props: StrategyP
257269
const isWidth = key.endsWith('Width')
258270
return () => {
259271
const raw = props[key]
260-
const val = parseFloat(raw!)
261-
if (isNaN(val)) return Infinity
262-
if (typeof raw === 'string' && raw.endsWith('%')) {
272+
if (raw == null) return Infinity
273+
274+
const container = (data.contentEl.value?.parentElement ?? document.documentElement) as HTMLElement
275+
276+
if (typeof raw === 'number' || /^-?[\d.]+(?:px)?$/.test(raw.trim())) {
277+
return parseFloat(raw as string)
278+
}
279+
if (raw.endsWith('%')) {
263280
// resolve against the overlay container, like CSS would
264-
const box = getElementBox(data.contentEl.value?.parentElement ?? document.documentElement)
265-
return val * (isWidth ? box.width : box.height) / 100
281+
const box = getElementBox(container)
282+
return parseFloat(raw) * (isWidth ? box.width : box.height) / 100
266283
}
267-
return val
284+
// let the browser resolve viewport units, calc(), min(), max(), clamp(), etc.
285+
return resolveCssLength(raw, container, isWidth)
268286
}
269287
})
270288

0 commit comments

Comments
 (0)