}
}
- const isTemplateNode = (node: Node): node is HTMLTemplateElement => {
- return (
- node.nodeType === DOMNodeTypes.ELEMENT &&
- (node as Element).tagName === 'TEMPLATE'
- )
- }
-
return [hydrate, hydrateNode]
}
+export const isTemplateNode = (node: Node): node is HTMLTemplateElement => {
+ return (
+ node.nodeType === DOMNodeTypes.ELEMENT &&
+ (node as Element).tagName === 'TEMPLATE'
+ )
+}
+
/**
* Dev only
*/
* @internal
*/
export { createCanSetSetupRefChecker } from './rendererTemplateRef'
+/**
+ * @internal
+ */
+export { isTemplateNode } from './hydration'
})
})
- describe.todo('transition', async () => {
+ describe('transition', async () => {
test('transition appear', async () => {
const { container } = await testHydration(
`<template>
import {
+ type BaseTransitionProps,
type GenericComponentInstance,
type TransitionElement,
type TransitionHooks,
baseResolveTransitionHooks,
checkTransitionMode,
currentInstance,
+ isTemplateNode,
leaveCbKey,
+ queuePostFlushCb,
resolveTransitionProps,
useTransitionState,
warn,
import { extend, isArray } from '@vue/shared'
import { renderEffect } from '../renderEffect'
import { isFragment } from '../fragment'
+import {
+ currentHydrationNode,
+ isHydrating,
+ setCurrentHydrationNode,
+} from '../dom/hydration'
const decorate = (t: typeof VaporTransition) => {
t.displayName = 'VaporTransition'
export const VaporTransition: FunctionalVaporComponent = /*@__PURE__*/ decorate(
(props, { slots, attrs }) => {
+ // wrapped <transition appear>
+ let resetDisplay: Function | undefined
+ if (
+ isHydrating &&
+ currentHydrationNode &&
+ isTemplateNode(currentHydrationNode)
+ ) {
+ // replace <template> node with inner child
+ const {
+ content: { firstChild },
+ parentNode,
+ } = currentHydrationNode
+ if (firstChild) {
+ if (
+ firstChild instanceof HTMLElement ||
+ firstChild instanceof SVGElement
+ ) {
+ const originalDisplay = firstChild.style.display
+ firstChild.style.display = 'none'
+ resetDisplay = () => (firstChild.style.display = originalDisplay)
+ }
+
+ parentNode!.replaceChild(firstChild, currentHydrationNode)
+ setCurrentHydrationNode(firstChild)
+ }
+ }
+
const children = (slots.default && slots.default()) as any as Block
if (!children) return
const { mode } = props
checkTransitionMode(mode)
- let resolvedProps
+ let resolvedProps: BaseTransitionProps<Element>
let isMounted = false
renderEffect(() => {
resolvedProps = resolveTransitionProps(props)
})
}
- applyTransitionHooks(
+ const hooks = applyTransitionHooks(
children,
{
state: useTransitionState(),
fallthroughAttrs,
)
+ if (resetDisplay && resolvedProps!.appear) {
+ const child = findTransitionBlock(children)!
+ hooks.beforeEnter(child)
+ resetDisplay()
+ queuePostFlushCb(() => hooks.enter(child))
+ }
+
return children
},
)
el[vShowOriginalDisplay] =
el.style.display === 'none' ? '' : el.style.display
}
- if (
- (__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
- isHydrating
- ) {
- if (!value && el.style.display !== 'none') {
- warnPropMismatch(
- el,
- 'style',
- MismatchTypes.STYLE,
- `display: ${el.style.display}`,
- 'display: none',
- )
- logMismatchError()
- el.style.display = 'none'
- el[vShowOriginalDisplay] = ''
+ if ($transition) {
+ if (value) {
+ $transition.beforeEnter(target)
+ el.style.display = el[vShowOriginalDisplay]!
+ $transition.enter(target)
+ } else {
+ // during initial render, the element is not yet inserted into the
+ // DOM, and it is hidden, no need to trigger transition
+ if (target.isConnected) {
+ $transition.leave(target, () => {
+ el.style.display = 'none'
+ })
+ } else {
+ el.style.display = 'none'
+ }
}
} else {
- if ($transition) {
- if (value) {
- $transition.beforeEnter(target)
- el.style.display = el[vShowOriginalDisplay]!
- $transition.enter(target)
- } else {
- // during initial render, the element is not yet inserted into the
- // DOM, and it is hidden, no need to trigger transition
- if (target.isConnected) {
- $transition.leave(target, () => {
- el.style.display = 'none'
- })
- } else {
- el.style.display = 'none'
- }
+ if (
+ (__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
+ isHydrating
+ ) {
+ if (!value && el.style.display !== 'none') {
+ warnPropMismatch(
+ el,
+ 'style',
+ MismatchTypes.STYLE,
+ `display: ${el.style.display}`,
+ 'display: none',
+ )
+ logMismatchError()
+
+ el.style.display = 'none'
+ el[vShowOriginalDisplay] = ''
}
} else {
el.style.display = value ? el[vShowOriginalDisplay]! : 'none'
}
}
+
el[vShowHidden] = !value
} else if (__DEV__) {
warn(