feat(runtime-vapor): setup helpers useAttrs & useSlots (#172)

This commit is contained in:
ubugeeei 2024-04-01 04:51:37 +09:00 committed by GitHub
parent 9f8bf4fc82
commit db140a1e37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 122 additions and 6 deletions

View File

@ -0,0 +1,87 @@
import type { SetupContext } from '../src/component'
import {
createComponent,
defineComponent,
ref,
template,
useAttrs,
useSlots,
} from '../src'
import { makeRender } from './_utils'
const define = makeRender<any>()
describe('SFC <script setup> helpers', () => {
test.todo('should warn runtime usage', () => {})
test('useSlots / useAttrs (no args)', () => {
let slots: SetupContext['slots'] | undefined
let attrs: SetupContext['attrs'] | undefined
const Comp = {
setup() {
slots = useSlots()
attrs = useAttrs()
},
}
const count = ref(0)
const passedAttrs = { id: () => count.value }
const passedSlots = {
default: () => template('')(),
x: () => template('')(),
}
const { render } = define({
render: () => createComponent(Comp, passedAttrs, passedSlots),
})
render()
expect(typeof slots!.default).toBe('function')
expect(typeof slots!.x).toBe('function')
expect(attrs).toMatchObject({ id: 0 })
count.value++
expect(attrs).toMatchObject({ id: 1 })
})
test('useSlots / useAttrs (with args)', () => {
let slots: SetupContext['slots'] | undefined
let attrs: SetupContext['attrs'] | undefined
let ctx: SetupContext | undefined
const Comp = defineComponent({
setup(_, _ctx) {
slots = useSlots()
attrs = useAttrs()
ctx = _ctx
},
})
const { render } = define({ render: () => createComponent(Comp) })
render()
expect(slots).toBe(ctx!.slots)
expect(attrs).toBe(ctx!.attrs)
})
describe.todo('mergeDefaults', () => {
test.todo('object syntax', () => {})
test.todo('array syntax', () => {})
test.todo('merging with skipFactory', () => {})
test.todo('should warn missing', () => {})
})
describe('mergeModels', () => {
test.todo('array syntax', () => {})
test.todo('object syntax', () => {})
test.todo('overwrite', () => {})
})
test.todo('createPropsRestProxy', () => {})
describe.todo('withAsyncContext', () => {
test.todo('basic', async () => {})
test.todo('error handling', async () => {})
test.todo('should not leak instance on multiple awaits', async () => {})
test.todo('should not leak on multiple awaits + error', async () => {})
test.todo('race conditions', async () => {})
test.todo('should teardown in-scope effects', async () => {})
})
})

View File

@ -0,0 +1,24 @@
import {
type SetupContext,
createSetupContext,
getCurrentInstance,
} from './component'
import { warn } from './warning'
// TODO: warning compiler-macros runtime usages
export function useSlots(): SetupContext['slots'] {
return getContext().slots
}
export function useAttrs(): SetupContext['attrs'] {
return getContext().attrs
}
function getContext(): SetupContext {
const i = getCurrentInstance()!
if (__DEV__ && !i) {
warn(`useContext() called without active instance.`)
}
return i.setupContext || (i.setupContext = createSetupContext(i))
}

View File

@ -110,6 +110,7 @@ export {
onErrorCaptured,
// onServerPrefetch,
} from './apiLifecycle'
export { useAttrs, useSlots } from './apiSetupHelpers'
export {
createVaporApp,
type App,

View File

@ -1,10 +1,10 @@
<script setup lang="ts">
import {
getCurrentInstance,
onBeforeMount,
onBeforeUnmount,
onMounted,
onUnmounted,
useAttrs,
watchEffect,
} from 'vue/vapor'
@ -14,7 +14,7 @@ const props = defineProps<{
baz: string
}>()
const attrs = getCurrentInstance()?.attrs
const attrs = useAttrs()
watchEffect(() => {
console.log({ ...attrs })
@ -29,8 +29,12 @@ onUnmounted(() => console.log('sub: unmounted'))
</script>
<template>
<div>sub-comp</div>
{{ props }}
{{ attrs }}
{{ keys(attrs) }}
<h2>sub-comp</h2>
<p>
props: {{ props }}
<br />
attrs: {{ attrs }}
<br />
keys(attrs): {{ keys(attrs) }}
</p>
</template>