import { isString, debounce } from 'es-toolkit' import { isElement } from 'es-toolkit/compat' import { isRef, nextTick, onMounted, reactive, ref, onBeforeUnmount } from 'vue' import type { ComponentPublicInstance, Ref } from 'vue' type MaybeHTMLElement = HTMLElement | Ref | string | null interface FullCardOptions { parentContainer?: MaybeHTMLElement parentWrap?: MaybeHTMLElement } type ElementKey = 'container' | 'wrap' | 'card' export function useFullCard( target: Ref, options: FullCardOptions = {}, ) { const { parentContainer = '.main-container', parentWrap = '.main-wrap' } = options let resizeObserver: ResizeObserver | null = null const height = ref(0) const elementMap = reactive>({ container: null, wrap: null, card: null, }) function updateMaxHeight() { const { container, wrap, card } = elementMap if (!container || !wrap || !card) { return } const containerHeight = container.offsetHeight const wrapHeight = wrap.offsetHeight const cardHeight = card.offsetHeight height.value = (containerHeight < wrapHeight ? cardHeight - (wrapHeight - containerHeight) : cardHeight + containerHeight - wrapHeight) - 1 } const debounceUpdateMaxHeight = debounce(() => { updateMaxHeight() }, 300) function getParentElement(element: MaybeHTMLElement) { if (isString(element)) return elementMap.card?.closest(element) ?? null if (isRef(element)) return element.value if (isElement(element)) return element return null } function initTableResizeObserver() { if (!target.value) { height.value = undefined return } elementMap.card = (target.value?.$el as HTMLElement) ?? null nextTick(() => { elementMap.container = getParentElement(parentContainer) elementMap.wrap = getParentElement(parentWrap) const missingKeys = Object.entries(elementMap) .filter((value) => value[1] == null) .map(([key]) => key) if (missingKeys.length) { throw new Error(`Missing or null elements: ${missingKeys.join(', ')}`) } resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { const { height } = entry.contentRect if (height) debounceUpdateMaxHeight() } }) if (elementMap.container) { resizeObserver.observe(elementMap.container) } }) } onMounted(() => { initTableResizeObserver() }) onBeforeUnmount(() => { resizeObserver?.disconnect() }) return { height, updateMaxHeight, } }