56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import type { MaybeRef } from '@vueuse/core'
|
|
import { useEventListener } from '@vueuse/core'
|
|
import type { Ref, ShallowRef, ToRefs } from 'vue'
|
|
import { computed, isRef, onMounted, ref, shallowRef, toValue, watch } from 'vue'
|
|
import type { SizeOptions } from '../../shared/size.js'
|
|
|
|
export interface SizeInfo<T extends HTMLElement> {
|
|
el: ShallowRef<T | undefined>
|
|
width: Ref<string>
|
|
height: Ref<string>
|
|
resize: () => void
|
|
}
|
|
export function useSize<T extends HTMLElement>(
|
|
options: ToRefs<SizeOptions>,
|
|
extraHeight: MaybeRef<number> = 0,
|
|
): SizeInfo<T> {
|
|
const el = shallowRef<T>()
|
|
const width = computed(() => toValue(options.width) || '100%')
|
|
const height = ref('auto')
|
|
|
|
const getRadio = (ratio: number | string | undefined): number => {
|
|
if (typeof ratio === 'string') {
|
|
const [width, height] = ratio.split(':')
|
|
const parsedRadio = Number(width) / Number(height)
|
|
|
|
if (!Number.isNaN(parsedRadio))
|
|
return parsedRadio
|
|
}
|
|
|
|
return typeof ratio === 'number' ? ratio : 16 / 9
|
|
}
|
|
|
|
const getHeight = (width: number): string => {
|
|
const height = toValue(options.height)
|
|
const ratio = getRadio(toValue(options.ratio))
|
|
|
|
return height || `${Number(width) / ratio + toValue(extraHeight)}px`
|
|
}
|
|
|
|
const resize = (): void => {
|
|
if (el.value)
|
|
height.value = getHeight(el.value.offsetWidth)
|
|
}
|
|
|
|
onMounted(() => {
|
|
resize()
|
|
if (isRef(extraHeight))
|
|
watch(extraHeight, resize)
|
|
|
|
useEventListener('orientationchange', resize)
|
|
useEventListener('resize', resize)
|
|
})
|
|
|
|
return { el, width, height, resize }
|
|
}
|