import { defineComponent, h, Transition, type BaseTransitionProps, type PropType, } from 'vue'; export const ExpandTransition = defineComponent({ name: 'ExpandTransition', props: { mode: { type: String as PropType['mode']>, default: 'out-in', }, }, setup(props, { slots }) { const beforeEnter = (el: Element) => { const element = el as HTMLElement; element.style.height = '0'; element.style.opacity = '0'; element.style.overflow = 'hidden'; }; const enter = (el: Element, done: () => void) => { const element = el as HTMLElement; element.style.transition = 'none'; element.style.height = 'auto'; const targetHeight = element.scrollHeight + 'px'; element.style.height = '0'; void element.offsetHeight; element.style.transition = 'height 300ms ease-in-out, opacity 300ms ease-in-out'; element.style.height = targetHeight; element.style.opacity = '1'; const cleanup = () => { element.style.height = 'auto'; element.style.overflow = ''; element.removeEventListener('transitionend', cleanup); done(); }; element.addEventListener('transitionend', cleanup); }; const leave = (el: Element, done: () => void) => { const element = el as HTMLElement; const height = element.scrollHeight + 'px'; element.style.height = height; element.style.opacity = '1'; element.style.overflow = 'hidden'; void element.offsetHeight; element.style.transition = 'height 300ms ease-in-out, opacity 300ms ease-in-out'; element.style.height = '0'; element.style.opacity = '0'; const cleanup = () => { element.removeEventListener('transitionend', cleanup); done(); }; element.addEventListener('transitionend', cleanup); }; const cancel = (el: Element) => { const element = el as HTMLElement; element.style.transition = ''; element.style.height = 'auto'; element.style.opacity = ''; element.style.overflow = ''; }; return () => h( Transition, { mode: props.mode, onBeforeEnter: beforeEnter, onEnter: enter, onLeave: leave, onEnterCancelled: cancel, onLeaveCancelled: cancel, }, slots, ); }, });