Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion packages-private/vapor-e2e-test/__tests__/transition.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,54 @@ describe('vapor transition', () => {
})

describe.todo('transition with Suspense', () => {})
describe.todo('transition with Teleport', () => {})

describe('transition with Teleport', () => {
test(
'apply transition to teleport child',
async () => {
const btnSelector = '.with-teleport > button'
const containerSelector = '.with-teleport > .container'
const targetSelector = `.with-teleport > .target`

await transitionFinish()
expect(await html(containerSelector)).toBe('')
expect(await html(targetSelector)).toBe('')

// enter
expect(
(await transitionStart(btnSelector, `${targetSelector} div`))
.classNames,
).toStrictEqual(['test', 'v-enter-from', 'v-enter-active'])
await nextFrame()
expect(await classList(`${targetSelector} div`)).toStrictEqual([
'test',
'v-enter-active',
'v-enter-to',
])
await transitionFinish()
expect(await html(targetSelector)).toBe(
'<div class="test">vapor compB</div>',
)
expect(await html(containerSelector)).toBe('')

// leave
expect(
(await transitionStart(btnSelector, `${targetSelector} div`))
.classNames,
).toStrictEqual(['test', 'v-leave-from', 'v-leave-active'])
await nextFrame()
expect(await classList(`${targetSelector} div`)).toStrictEqual([
'test',
'v-leave-active',
'v-leave-to',
])
await transitionFinish()
expect(await html(targetSelector)).toBe('')
expect(await html(containerSelector)).toBe('')
},
E2E_TIMEOUT,
)
})

describe('transition with v-show', () => {
test(
Expand Down
15 changes: 15 additions & 0 deletions packages-private/vapor-e2e-test/transition/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,21 @@ const click = () => {
</div>
<!-- mode end -->

<!-- with teleport -->
<div class="with-teleport">
<div class="target"></div>
<div class="container">
<Transition>
<Teleport to=".target" defer>
<!-- comment -->
<VaporCompB v-if="!toggle" class="test"></VaporCompB>
</Teleport>
</Transition>
</div>
<button @click="toggle = !toggle">button</button>
</div>
<!-- with teleport end -->

<!-- with keep-alive -->
<div class="keep-alive">
<div>
Expand Down
17 changes: 11 additions & 6 deletions packages/compiler-vapor/src/transforms/vSlot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,17 @@ function transformComponentSlot(

let slotKey
if (isTransitionNode(node) && nonSlotTemplateChildren.length) {
const keyProp = findProp(
nonSlotTemplateChildren[0] as ElementNode,
'key',
) as VaporDirectiveNode
if (keyProp) {
slotKey = keyProp.exp
const nonCommentChild = nonSlotTemplateChildren.find(
n => n.type !== NodeTypes.COMMENT,
)
if (nonCommentChild) {
const keyProp = findProp(
nonCommentChild as ElementNode,
'key',
) as VaporDirectiveNode
if (keyProp) {
slotKey = keyProp.exp
}
}
}

Expand Down
18 changes: 8 additions & 10 deletions packages/runtime-vapor/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,10 +381,7 @@ export function setupComponent(
component.inheritAttrs !== false &&
Object.keys(instance.attrs).length
) {
const el = getRootElement(instance)
if (el) {
renderEffect(() => applyFallthroughProps(el, instance.attrs))
}
renderEffect(() => applyFallthroughProps(instance.block, instance.attrs))
}

setActiveSub(prevSub)
Expand All @@ -402,9 +399,12 @@ export function applyFallthroughProps(
block: Block,
attrs: Record<string, any>,
): void {
isApplyingFallthroughProps = true
setDynamicProps(block as Element, [attrs])
isApplyingFallthroughProps = false
const el = getRootElement(block)
if (el) {
isApplyingFallthroughProps = true
setDynamicProps(el, [attrs])
isApplyingFallthroughProps = false
}
}

/**
Expand Down Expand Up @@ -761,9 +761,7 @@ export function getExposed(
}
}

function getRootElement({
block,
}: VaporComponentInstance): Element | undefined {
function getRootElement(block: Block): Element | undefined {
if (block instanceof Element) {
return block
}
Expand Down
4 changes: 4 additions & 0 deletions packages/runtime-vapor/src/components/Teleport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
runWithoutHydration,
setCurrentHydrationNode,
} from '../dom/hydration'
import { applyTransitionHooks } from './Transition'

export const VaporTeleportImpl = {
name: 'VaporTeleport',
Expand Down Expand Up @@ -122,6 +123,9 @@ export class TeleportFragment extends VaporFragment {
if (!this.parent || isHydrating) return

const mount = (parent: ParentNode, anchor: Node | null) => {
if (this.$transition) {
applyTransitionHooks(this.nodes, this.$transition)
}
insert(
this.nodes,
(this.mountContainer = parent),
Expand Down
58 changes: 37 additions & 21 deletions packages/runtime-vapor/src/components/Transition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
baseResolveTransitionHooks,
checkTransitionMode,
currentInstance,
getComponentName,
isTemplateNode,
leaveCbKey,
queuePostFlushCb,
Expand All @@ -33,8 +34,10 @@ import {
setCurrentHydrationNode,
} from '../dom/hydration'

const displayName = 'VaporTransition'

const decorate = (t: typeof VaporTransition) => {
t.displayName = 'VaporTransition'
t.displayName = displayName
t.props = TransitionPropsValidators
t.__vapor = true
return t
Expand Down Expand Up @@ -208,8 +211,18 @@ export function applyTransitionHooks(
hooks: VaporTransitionHooks,
fallthroughAttrs: boolean = true,
): VaporTransitionHooks {
// filter out comment nodes
if (isArray(block)) {
block = block.filter(b => !(b instanceof Comment))
if (block.length === 1) {
block = block[0]
} else if (block.length === 0) {
return hooks
}
}

const isFrag = isFragment(block)
const child = findTransitionBlock(block)
const child = findTransitionBlock(block, isFrag)
if (!child) {
// set transition hooks on fragment for reusing during it's updating
if (isFrag) setTransitionHooksOnFragment(block, hooks)
Expand Down Expand Up @@ -296,43 +309,46 @@ export function findTransitionBlock(
return transitionBlockCache.get(block)
}

let isFrag = false
let child: TransitionBlock | undefined
if (block instanceof Node) {
// transition can only be applied on Element child
if (block instanceof Element) child = block
} else if (isVaporComponent(block)) {
child = findTransitionBlock(block.block)
// stop searching if encountering nested Transition component
if (getComponentName(block.type) === displayName) return undefined
child = findTransitionBlock(block.block, inFragment)
// use component id as key
if (child && child.$key === undefined) child.$key = block.uid
} else if (isArray(block)) {
child = block[0] as TransitionBlock
let hasFound = false
for (const c of block) {
const item = findTransitionBlock(c)
if (item instanceof Element) {
if (__DEV__ && hasFound) {
// warn more than one non-comment child
warn(
'<transition> can only be used on a single element or component. ' +
'Use <transition-group> for lists.',
)
break
}
child = item
hasFound = true
if (!__DEV__) break
if (c instanceof Comment) continue
// check if the child is a fragment to suppress warnings
if (isFragment(c)) inFragment = true
const item = findTransitionBlock(c, inFragment)
if (__DEV__ && hasFound) {
// warn more than one non-comment child
warn(
'<transition> can only be used on a single element or component. ' +
'Use <transition-group> for lists.',
)
break
}
child = item
hasFound = true
if (!__DEV__) break
}
} else if ((isFrag = isFragment(block))) {
} else if (isFragment(block)) {
// mark as in fragment to suppress warnings
inFragment = true
if (block.insert) {
child = block
} else {
child = findTransitionBlock(block.nodes, true)
}
}

if (__DEV__ && !child && !inFragment && !isFrag) {
if (__DEV__ && !child && !inFragment) {
warn('Transition component has no valid child element')
}

Expand All @@ -344,7 +360,7 @@ export function setTransitionHooksOnFragment(
hooks: VaporTransitionHooks,
): void {
if (isFragment(block)) {
setTransitionHooks(block, hooks)
block.$transition = hooks
} else if (isArray(block)) {
for (let i = 0; i < block.length; i++) {
setTransitionHooksOnFragment(block[i], hooks)
Expand Down
Loading