Skip to content

Commit

Permalink
Merge branch 'main' into bwsy/fix/11821
Browse files Browse the repository at this point in the history
  • Loading branch information
baiwusanyu-c authored Sep 5, 2024
2 parents 0426878 + 3116553 commit 34f19b2
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 8 deletions.
12 changes: 12 additions & 0 deletions packages-private/dts-test/defineComponent.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,18 @@ describe('emits', () => {
},
})

// #11803 manual props annotation in setup()
const Hello = defineComponent({
name: 'HelloWorld',
inheritAttrs: false,
props: { foo: String },
emits: {
customClick: (args: string) => typeof args === 'string',
},
setup(props: { foo?: string }) {},
})
;<Hello onCustomClick={() => {}} />

// without emits
defineComponent({
setup(props, { emit }) {
Expand Down
11 changes: 6 additions & 5 deletions packages/runtime-core/src/apiDefineComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ export type DefineSetupFnComponent<
S
>

type ToResolvedProps<Props, Emits extends EmitsOptions> = Readonly<Props> &
Readonly<EmitsToProps<Emits>>

// defineComponent is a utility that is primarily used for type inference
// when declaring components. Type inference is provided in the component
// options (provided as the argument). The returned value has artificial types
Expand Down Expand Up @@ -210,8 +213,6 @@ export function defineComponent<
: ExtractPropTypes<RuntimePropsOptions>
: { [key in RuntimePropsKeys]?: any }
: TypeProps,
ResolvedProps = Readonly<InferredProps> &
Readonly<EmitsToProps<ResolvedEmits>>,
TypeRefs extends Record<string, unknown> = {},
>(
options: {
Expand All @@ -229,7 +230,7 @@ export function defineComponent<
*/
__typeRefs?: TypeRefs
} & ComponentOptionsBase<
ResolvedProps,
ToResolvedProps<InferredProps, ResolvedEmits>,
SetupBindings,
Data,
Computed,
Expand All @@ -249,7 +250,7 @@ export function defineComponent<
> &
ThisType<
CreateComponentPublicInstanceWithMixins<
ResolvedProps,
ToResolvedProps<InferredProps, ResolvedEmits>,
SetupBindings,
Data,
Computed,
Expand Down Expand Up @@ -278,7 +279,7 @@ export function defineComponent<
ResolvedEmits,
RuntimeEmitsKeys,
PublicProps,
ResolvedProps,
ToResolvedProps<InferredProps, ResolvedEmits>,
ExtractDefaultPropTypes<RuntimePropsOptions>,
Slots,
LocalComponents,
Expand Down
5 changes: 4 additions & 1 deletion packages/runtime-core/src/componentRenderUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export function renderComponentRoot(
setupState,
ctx,
inheritAttrs,
isMounted,
} = instance
const prev = setCurrentRenderingInstance(instance)

Expand Down Expand Up @@ -253,7 +254,9 @@ export function renderComponentRoot(
`that cannot be animated.`,
)
}
root.transition = vnode.transition
root.transition = isMounted
? vnode.component!.subTree.transition!
: vnode.transition
}

if (__DEV__ && setRoot) {
Expand Down
1 change: 1 addition & 0 deletions packages/runtime-core/src/components/BaseTransition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ const BaseTransitionImpl: ComponentOptions = {
if (!(instance.job.flags! & SchedulerJobFlags.DISPOSED)) {
instance.update()
}
delete leavingHooks.afterLeave
}
return emptyPlaceholder(child)
} else if (mode === 'in-out' && innerChild.type !== Comment) {
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime-core/src/components/KeepAlive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ const KeepAliveImpl: ComponentOptions = {
pendingCacheKey = null

if (!slots.default) {
return null
return (current = null)
}

const children = slots.default()
Expand Down
171 changes: 170 additions & 1 deletion packages/vue/__tests__/e2e/Transition.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1427,9 +1427,11 @@ describe('e2e: Transition', () => {
},
E2E_TIMEOUT,
)
})

describe('transition with KeepAlive', () => {
test(
'w/ KeepAlive + unmount innerChild',
'unmount innerChild (out-in mode)',
async () => {
const unmountSpy = vi.fn()
await page().exposeFunction('unmountSpy', unmountSpy)
Expand Down Expand Up @@ -1484,6 +1486,173 @@ describe('e2e: Transition', () => {
},
E2E_TIMEOUT,
)

// #11775
test(
'switch child then update include (out-in mode)',
async () => {
const onUpdatedSpyA = vi.fn()
const onUnmountedSpyC = vi.fn()

await page().exposeFunction('onUpdatedSpyA', onUpdatedSpyA)
await page().exposeFunction('onUnmountedSpyC', onUnmountedSpyC)

await page().evaluate(() => {
const { onUpdatedSpyA, onUnmountedSpyC } = window as any
const { createApp, ref, shallowRef, h, onUpdated, onUnmounted } = (
window as any
).Vue
createApp({
template: `
<div id="container">
<transition mode="out-in">
<KeepAlive :include="includeRef">
<component :is="current" />
</KeepAlive>
</transition>
</div>
<button id="switchToB" @click="switchToB">switchToB</button>
<button id="switchToC" @click="switchToC">switchToC</button>
<button id="switchToA" @click="switchToA">switchToA</button>
`,
components: {
CompA: {
name: 'CompA',
setup() {
onUpdated(onUpdatedSpyA)
return () => h('div', 'CompA')
},
},
CompB: {
name: 'CompB',
setup() {
return () => h('div', 'CompB')
},
},
CompC: {
name: 'CompC',
setup() {
onUnmounted(onUnmountedSpyC)
return () => h('div', 'CompC')
},
},
},
setup: () => {
const includeRef = ref(['CompA', 'CompB', 'CompC'])
const current = shallowRef('CompA')
const switchToB = () => (current.value = 'CompB')
const switchToC = () => (current.value = 'CompC')
const switchToA = () => {
current.value = 'CompA'
includeRef.value = ['CompA']
}
return { current, switchToB, switchToC, switchToA, includeRef }
},
}).mount('#app')
})

await transitionFinish()
expect(await html('#container')).toBe('<div>CompA</div>')

await click('#switchToB')
await nextTick()
await click('#switchToC')
await transitionFinish()
expect(await html('#container')).toBe('<div class="">CompC</div>')

await click('#switchToA')
await transitionFinish()
expect(await html('#container')).toBe('<div class="">CompA</div>')

// expect CompA only update once
expect(onUpdatedSpyA).toBeCalledTimes(1)
expect(onUnmountedSpyC).toBeCalledTimes(1)
},
E2E_TIMEOUT,
)

// #10827
test(
'switch and update child then update include (out-in mode)',
async () => {
const onUnmountedSpyB = vi.fn()
await page().exposeFunction('onUnmountedSpyB', onUnmountedSpyB)

await page().evaluate(() => {
const { onUnmountedSpyB } = window as any
const {
createApp,
ref,
shallowRef,
h,
provide,
inject,
onUnmounted,
} = (window as any).Vue
createApp({
template: `
<div id="container">
<transition name="test-anim" mode="out-in">
<KeepAlive :include="includeRef">
<component :is="current" />
</KeepAlive>
</transition>
</div>
<button id="switchToA" @click="switchToA">switchToA</button>
<button id="switchToB" @click="switchToB">switchToB</button>
`,
components: {
CompA: {
name: 'CompA',
setup() {
const current = inject('current')
return () => h('div', current.value)
},
},
CompB: {
name: 'CompB',
setup() {
const current = inject('current')
onUnmounted(onUnmountedSpyB)
return () => h('div', current.value)
},
},
},
setup: () => {
const includeRef = ref(['CompA'])
const current = shallowRef('CompA')
provide('current', current)

const switchToB = () => {
current.value = 'CompB'
includeRef.value = ['CompA', 'CompB']
}
const switchToA = () => {
current.value = 'CompA'
includeRef.value = ['CompA']
}
return { current, switchToB, switchToA, includeRef }
},
}).mount('#app')
})

await transitionFinish()
expect(await html('#container')).toBe('<div>CompA</div>')

await click('#switchToB')
await transitionFinish()
await transitionFinish()
expect(await html('#container')).toBe('<div class="">CompB</div>')

await click('#switchToA')
await transitionFinish()
await transitionFinish()
expect(await html('#container')).toBe('<div class="">CompA</div>')

expect(onUnmountedSpyB).toBeCalledTimes(1)
},
E2E_TIMEOUT,
)
})

describe('transition with Suspense', () => {
Expand Down

0 comments on commit 34f19b2

Please sign in to comment.