Skip to content

Commit

Permalink
fix(transition): get root el of DEV_FRAGMENT_ROOT
Browse files Browse the repository at this point in the history
  • Loading branch information
jonaskuske committed Mar 1, 2024
1 parent f66a75e commit b1b30d6
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
2 changes: 2 additions & 0 deletions packages/runtime-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ export {
normalizeStyle,
} from '@vue/shared'

export { filterSingleRoot } from './componentRenderUtils'

// For test-utils
export { transformVNodeArgs } from './vnode'

Expand Down
26 changes: 25 additions & 1 deletion packages/runtime-dom/src/components/TransitionGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import {
Fragment,
type SetupContext,
type VNode,
type VNodeArrayChildren,
compatUtils,
createVNode,
filterSingleRoot,
getCurrentInstance,
getTransitionRawChildren,
onUpdated,
Expand All @@ -26,7 +28,7 @@ import {
useTransitionState,
warn,
} from '@vue/runtime-core'
import { extend } from '@vue/shared'
import { PatchFlags, ShapeFlags, extend } from '@vue/shared'

const positionMap = new WeakMap<VNode, DOMRect>()
const newPositionMap = new WeakMap<VNode, DOMRect>()
Expand Down Expand Up @@ -113,6 +115,28 @@ const TransitionGroupImpl: ComponentOptions = {
}

prevChildren = children

// In dev mode, comments are preserved, and it's possible for a template
// to have comments alongside the root element which makes it a fragment.
// In that case we re-assign `el` so DOM operations access the actual
// root element instead of the fragment root. (#6745)
if (__DEV__ && prevChildren) {
prevChildren.forEach(child => {
if (
child.shapeFlag & ShapeFlags.COMPONENT &&
child.component &&
child.component.subTree.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT
) {
const elementRoot = filterSingleRoot(
child.component.subTree.children as VNodeArrayChildren
)
if (elementRoot) {
child.el = elementRoot.el
}
}
})
}

children = slots.default ? getTransitionRawChildren(slots.default()) : []

for (let i = 0; i < children.length; i++) {
Expand Down
41 changes: 41 additions & 0 deletions packages/vue/__tests__/e2e/TransitionGroup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -508,4 +508,45 @@ describe('e2e: TransitionGroup', () => {

expect(`<TransitionGroup> children must be keyed`).toHaveBeenWarned()
})

test(
'works when child component has single root + comments',
async () => {
const onErrorSpy = vi.fn()
await page().exposeFunction('onErrorSpy', onErrorSpy)

await page().evaluate(() => {
const { onErrorSpy } = window as any
const { createApp, ref, onErrorCaptured } = (window as any).Vue

const app = createApp({
template: `
<div id="container">
<transition-group>
<a-component v-if="show"></a-component>
</transition-group>
</div>
<button id="toggleBtn" @click="click">button</button>
`,
setup: () => {
onErrorCaptured(() => onErrorSpy())
const show = ref(true)
const click = () => (show.value = false)
return { show, click }
}
})
app.component('a-component', { template: `<!----><div></div>` })
app.mount('#app')
})

expect(await html('#container')).toBe('<!----><div></div>')

await htmlWhenTransitionStart()
await transitionFinish()

expect(onErrorSpy).not.toBeCalled()
expect(await html('#container')).toBe('')
},
E2E_TIMEOUT
)
})

0 comments on commit b1b30d6

Please sign in to comment.