wip: defineContext()

This commit is contained in:
Evan You
2020-11-12 14:10:39 -05:00
parent dc098c7f81
commit 6a9b56ca60
10 changed files with 200 additions and 142 deletions

View File

@@ -0,0 +1,22 @@
import { Slots } from './componentSlots'
import { warn } from './warning'
interface DefaultContext {
props: Record<string, unknown>
attrs: Record<string, unknown>
emit: (...args: any[]) => void
slots: Slots
}
export function defineContext<T extends Partial<DefaultContext> = {}>(
opts?: any // TODO infer
): { [K in keyof DefaultContext]: T[K] extends {} ? T[K] : DefaultContext[K] } {
if (__DEV__) {
warn(
`defineContext() is a compiler-hint helper that is only usable inside ` +
`<script setup> of a single file component. It will be compiled away ` +
`and should not be used in final distributed code.`
)
}
return null as any
}

View File

@@ -105,7 +105,7 @@ export interface ComponentInternalOptions {
export interface FunctionalComponent<P = {}, E extends EmitsOptions = {}>
extends ComponentInternalOptions {
// use of any here is intentional so it can be a valid JSX Element constructor
(props: P, ctx: SetupContext<E>): any
(props: P, ctx: SetupContext<E, P>): any
props?: ComponentPropsOptions<P>
emits?: E | (keyof E)[]
inheritAttrs?: boolean
@@ -167,7 +167,8 @@ export const enum LifecycleHooks {
ERROR_CAPTURED = 'ec'
}
export interface SetupContext<E = EmitsOptions> {
export interface SetupContext<E = EmitsOptions, P = Data> {
props: P
attrs: Data
slots: Slots
emit: EmitFn<E>
@@ -735,6 +736,9 @@ function createSetupContext(instance: ComponentInternalInstance): SetupContext {
// We use getters in dev in case libs like test-utils overwrite instance
// properties (overwrites should not be done in prod)
return Object.freeze({
get props() {
return instance.props
},
get attrs() {
return new Proxy(instance.attrs, attrHandlers)
},
@@ -747,6 +751,7 @@ function createSetupContext(instance: ComponentInternalInstance): SetupContext {
})
} else {
return {
props: instance.props,
attrs: instance.attrs,
slots: instance.slots,
emit: instance.emit

View File

@@ -96,7 +96,7 @@ export interface ComponentOptionsBase<
setup?: (
this: void,
props: Props,
ctx: SetupContext<E>
ctx: SetupContext<E, Props>
) => Promise<RawBindings> | RawBindings | RenderFunction | void
name?: string
template?: string | object // can be a direct DOM node

View File

@@ -95,6 +95,7 @@ export function renderComponentRoot(
props,
__DEV__
? {
props,
get attrs() {
markAttrsAccessed()
return attrs
@@ -102,7 +103,7 @@ export function renderComponentRoot(
slots,
emit
}
: { attrs, slots, emit }
: { props, attrs, slots, emit }
)
: render(props, null as any /* we know it doesn't need it */)
)

View File

@@ -1,15 +0,0 @@
import { EMPTY_OBJ } from '@vue/shared'
import { Slots } from '../componentSlots'
interface DefaultContext {
props: Record<string, unknown>
attrs: Record<string, unknown>
emit: (...args: any[]) => void
slots: Slots
}
export function useSetupContext<T extends Partial<DefaultContext> = {}>(
opts?: any // TODO infer
): { [K in keyof DefaultContext]: T[K] extends {} ? T[K] : DefaultContext[K] } {
return EMPTY_OBJ as any
}

View File

@@ -43,6 +43,7 @@ export { provide, inject } from './apiInject'
export { nextTick } from './scheduler'
export { defineComponent } from './apiDefineComponent'
export { defineAsyncComponent } from './apiAsyncComponent'
export { defineContext } from './apiDefineContext'
// Advanced API ----------------------------------------------------------------
@@ -261,8 +262,6 @@ import {
setCurrentRenderingInstance
} from './componentRenderUtils'
import { isVNode, normalizeVNode } from './vnode'
import { Slots } from './componentSlots'
import { EMPTY_OBJ } from '@vue/shared/src'
const _ssrUtils = {
createComponentInstance,