mirror of https://github.com/vuejs/core.git
wip: slot props
This commit is contained in:
parent
f413e00e43
commit
f8a7046e65
|
@ -112,39 +112,14 @@ export function getPropsProxyHandlers(
|
||||||
: null
|
: null
|
||||||
|
|
||||||
const getAttr = (target: RawProps, key: string) => {
|
const getAttr = (target: RawProps, key: string) => {
|
||||||
if (isProp(key) || isEmitListener(emitsOptions, key)) {
|
if (!isProp(key) && !isEmitListener(emitsOptions, key)) {
|
||||||
return
|
return getAttrFromRawProps(target, key)
|
||||||
}
|
|
||||||
const dynamicSources = target.$
|
|
||||||
if (dynamicSources) {
|
|
||||||
let i = dynamicSources.length
|
|
||||||
let source, isDynamic
|
|
||||||
while (i--) {
|
|
||||||
source = dynamicSources[i]
|
|
||||||
isDynamic = isFunction(source)
|
|
||||||
source = isDynamic ? (source as Function)() : source
|
|
||||||
if (hasOwn(source, key)) {
|
|
||||||
return isDynamic ? source[key] : source[key]()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasOwn(target, key)) {
|
|
||||||
return target[key]()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasAttr = (target: RawProps, key: string) => {
|
const hasAttr = (target: RawProps, key: string) => {
|
||||||
if (isAttr(key)) {
|
if (isAttr(key)) {
|
||||||
const dynamicSources = target.$
|
return hasAttrFromRawProps(target, key)
|
||||||
if (dynamicSources) {
|
|
||||||
let i = dynamicSources.length
|
|
||||||
while (i--) {
|
|
||||||
if (hasOwn(resolveSource(dynamicSources[i]), key)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hasOwn(target, key)
|
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -188,6 +163,40 @@ export function getPropsProxyHandlers(
|
||||||
return (comp.__propsHandlers = [propsHandlers, attrsHandlers])
|
return (comp.__propsHandlers = [propsHandlers, attrsHandlers])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAttrFromRawProps(rawProps: RawProps, key: string): unknown {
|
||||||
|
if (key === '$') return
|
||||||
|
const dynamicSources = rawProps.$
|
||||||
|
if (dynamicSources) {
|
||||||
|
let i = dynamicSources.length
|
||||||
|
let source, isDynamic
|
||||||
|
while (i--) {
|
||||||
|
source = dynamicSources[i]
|
||||||
|
isDynamic = isFunction(source)
|
||||||
|
source = isDynamic ? (source as Function)() : source
|
||||||
|
if (hasOwn(source, key)) {
|
||||||
|
return isDynamic ? source[key] : source[key]()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasOwn(rawProps, key)) {
|
||||||
|
return rawProps[key]()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasAttrFromRawProps(rawProps: RawProps, key: string): boolean {
|
||||||
|
if (key === '$') return false
|
||||||
|
const dynamicSources = rawProps.$
|
||||||
|
if (dynamicSources) {
|
||||||
|
let i = dynamicSources.length
|
||||||
|
while (i--) {
|
||||||
|
if (hasOwn(resolveSource(dynamicSources[i]), key)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasOwn(rawProps, key)
|
||||||
|
}
|
||||||
|
|
||||||
export function normalizePropsOptions(
|
export function normalizePropsOptions(
|
||||||
comp: VaporComponent,
|
comp: VaporComponent,
|
||||||
): NormalizedPropsOptions {
|
): NormalizedPropsOptions {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import { EMPTY_OBJ, NO, hasOwn, isArray, isFunction } from '@vue/shared'
|
import { EMPTY_OBJ, NO, hasOwn, isArray, isFunction } from '@vue/shared'
|
||||||
import { type Block, type BlockFn, DynamicFragment } from './block'
|
import { type Block, type BlockFn, DynamicFragment } from './block'
|
||||||
import type { RawProps } from './componentProps'
|
import {
|
||||||
|
type RawProps,
|
||||||
|
getAttrFromRawProps,
|
||||||
|
hasAttrFromRawProps,
|
||||||
|
} from './componentProps'
|
||||||
import { currentInstance } from '@vue/runtime-core'
|
import { currentInstance } from '@vue/runtime-core'
|
||||||
import type { VaporComponentInstance } from './component'
|
import type { VaporComponentInstance } from './component'
|
||||||
import { renderEffect } from './renderEffect'
|
import { renderEffect } from './renderEffect'
|
||||||
|
@ -78,14 +82,10 @@ export function getSlot(target: RawSlots, key: string): Slot | undefined {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
const dynamicSlotsPropsProxyHandlers: ProxyHandler<RawProps> = {
|
const dynamicSlotsPropsProxyHandlers: ProxyHandler<RawProps> = {
|
||||||
get(target, key: string) {
|
get: getAttrFromRawProps,
|
||||||
return target[key]
|
has: hasAttrFromRawProps,
|
||||||
},
|
ownKeys: target => Object.keys(target).filter(k => k !== '$'),
|
||||||
has(target, key) {
|
|
||||||
return key in target
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO how to handle empty slot return blocks?
|
// TODO how to handle empty slot return blocks?
|
||||||
|
@ -97,38 +97,27 @@ export function createSlot(
|
||||||
rawProps?: RawProps,
|
rawProps?: RawProps,
|
||||||
fallback?: Slot,
|
fallback?: Slot,
|
||||||
): Block {
|
): Block {
|
||||||
|
const fragment = new DynamicFragment('slot')
|
||||||
const rawSlots = (currentInstance as VaporComponentInstance)!.rawSlots
|
const rawSlots = (currentInstance as VaporComponentInstance)!.rawSlots
|
||||||
const resolveSlot = () => getSlot(rawSlots, isFunction(name) ? name() : name)
|
|
||||||
const slotProps = rawProps
|
const slotProps = rawProps
|
||||||
? rawProps.$
|
|
||||||
? new Proxy(rawProps, dynamicSlotsPropsProxyHandlers)
|
? new Proxy(rawProps, dynamicSlotsPropsProxyHandlers)
|
||||||
: rawProps
|
|
||||||
: EMPTY_OBJ
|
: EMPTY_OBJ
|
||||||
|
|
||||||
if (isFunction(name) || rawSlots.$) {
|
// always create effect because a slot may contain dynamic root inside
|
||||||
// dynamic slot name, or dynamic slot sources
|
// which affects fallback
|
||||||
const fragment = new DynamicFragment('slot')
|
|
||||||
renderEffect(() => {
|
renderEffect(() => {
|
||||||
const slot = resolveSlot()
|
const slot = getSlot(rawSlots, isFunction(name) ? name() : name)
|
||||||
if (slot) {
|
if (slot) {
|
||||||
fragment.update(
|
fragment.update(
|
||||||
() => slot(slotProps) || (fallback && fallback()),
|
() => slot(slotProps) || (fallback && fallback()),
|
||||||
// pass the stable slot fn as key to avoid toggling when resolving
|
// TODO this key needs to account for possible fallback (v-if)
|
||||||
// to the same slot
|
// inside the slot
|
||||||
slot,
|
slot,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
fragment.update(fallback)
|
fragment.update(fallback)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return fragment
|
return fragment
|
||||||
} else {
|
|
||||||
// static
|
|
||||||
const slot = resolveSlot()
|
|
||||||
if (slot) {
|
|
||||||
const block = slot(slotProps)
|
|
||||||
if (block) return block
|
|
||||||
}
|
|
||||||
return fallback ? fallback() : []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,10 @@ import { isVaporComponent } from '../component'
|
||||||
export function insert(
|
export function insert(
|
||||||
block: Block,
|
block: Block,
|
||||||
parent: ParentNode,
|
parent: ParentNode,
|
||||||
anchor: Node | null = null,
|
anchor: Node | null | 0 = null,
|
||||||
): void {
|
): void {
|
||||||
if (block instanceof Node) {
|
if (block instanceof Node) {
|
||||||
parent.insertBefore(block, anchor)
|
parent.insertBefore(block, anchor === 0 ? parent.firstChild : anchor)
|
||||||
} else if (isVaporComponent(block)) {
|
} else if (isVaporComponent(block)) {
|
||||||
if (!block.isMounted) {
|
if (!block.isMounted) {
|
||||||
if (block.bm) invokeArrayFns(block.bm)
|
if (block.bm) invokeArrayFns(block.bm)
|
||||||
|
@ -27,13 +27,12 @@ export function insert(
|
||||||
} else {
|
} else {
|
||||||
// fragment
|
// fragment
|
||||||
insert(block.nodes, parent, anchor)
|
insert(block.nodes, parent, anchor)
|
||||||
if (block.anchor) parent.insertBefore(block.anchor, anchor)
|
if (block.anchor) insert(block.anchor, parent, anchor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function prepend(parent: ParentNode, ...blocks: Block[]): void {
|
export function prepend(parent: ParentNode, ...blocks: Block[]): void {
|
||||||
const anchor = parent.firstChild
|
for (const b of blocks) insert(b, parent, 0)
|
||||||
for (const b of blocks) insert(b, parent, anchor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO optimize
|
// TODO optimize
|
||||||
|
|
Loading…
Reference in New Issue