wip: slot props

This commit is contained in:
Evan You 2024-12-08 10:16:25 +08:00
parent f413e00e43
commit f8a7046e65
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
3 changed files with 66 additions and 69 deletions

View File

@ -112,39 +112,14 @@ export function getPropsProxyHandlers(
: null
const getAttr = (target: RawProps, key: string) => {
if (isProp(key) || isEmitListener(emitsOptions, key)) {
return
}
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]()
if (!isProp(key) && !isEmitListener(emitsOptions, key)) {
return getAttrFromRawProps(target, key)
}
}
const hasAttr = (target: RawProps, key: string) => {
if (isAttr(key)) {
const dynamicSources = target.$
if (dynamicSources) {
let i = dynamicSources.length
while (i--) {
if (hasOwn(resolveSource(dynamicSources[i]), key)) {
return true
}
}
}
return hasOwn(target, key)
return hasAttrFromRawProps(target, key)
} else {
return false
}
@ -188,6 +163,40 @@ export function getPropsProxyHandlers(
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(
comp: VaporComponent,
): NormalizedPropsOptions {

View File

@ -1,6 +1,10 @@
import { EMPTY_OBJ, NO, hasOwn, isArray, isFunction } from '@vue/shared'
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 type { VaporComponentInstance } from './component'
import { renderEffect } from './renderEffect'
@ -78,14 +82,10 @@ export function getSlot(target: RawSlots, key: string): Slot | undefined {
}
}
// TODO
const dynamicSlotsPropsProxyHandlers: ProxyHandler<RawProps> = {
get(target, key: string) {
return target[key]
},
has(target, key) {
return key in target
},
get: getAttrFromRawProps,
has: hasAttrFromRawProps,
ownKeys: target => Object.keys(target).filter(k => k !== '$'),
}
// TODO how to handle empty slot return blocks?
@ -97,38 +97,27 @@ export function createSlot(
rawProps?: RawProps,
fallback?: Slot,
): Block {
const fragment = new DynamicFragment('slot')
const rawSlots = (currentInstance as VaporComponentInstance)!.rawSlots
const resolveSlot = () => getSlot(rawSlots, isFunction(name) ? name() : name)
const slotProps = rawProps
? rawProps.$
? new Proxy(rawProps, dynamicSlotsPropsProxyHandlers)
: rawProps
? new Proxy(rawProps, dynamicSlotsPropsProxyHandlers)
: EMPTY_OBJ
if (isFunction(name) || rawSlots.$) {
// dynamic slot name, or dynamic slot sources
const fragment = new DynamicFragment('slot')
renderEffect(() => {
const slot = resolveSlot()
if (slot) {
fragment.update(
() => slot(slotProps) || (fallback && fallback()),
// pass the stable slot fn as key to avoid toggling when resolving
// to the same slot
slot,
)
} else {
fragment.update(fallback)
}
})
return fragment
} else {
// static
const slot = resolveSlot()
// always create effect because a slot may contain dynamic root inside
// which affects fallback
renderEffect(() => {
const slot = getSlot(rawSlots, isFunction(name) ? name() : name)
if (slot) {
const block = slot(slotProps)
if (block) return block
fragment.update(
() => slot(slotProps) || (fallback && fallback()),
// TODO this key needs to account for possible fallback (v-if)
// inside the slot
slot,
)
} else {
fragment.update(fallback)
}
return fallback ? fallback() : []
}
})
return fragment
}

View File

@ -7,10 +7,10 @@ import { isVaporComponent } from '../component'
export function insert(
block: Block,
parent: ParentNode,
anchor: Node | null = null,
anchor: Node | null | 0 = null,
): void {
if (block instanceof Node) {
parent.insertBefore(block, anchor)
parent.insertBefore(block, anchor === 0 ? parent.firstChild : anchor)
} else if (isVaporComponent(block)) {
if (!block.isMounted) {
if (block.bm) invokeArrayFns(block.bm)
@ -27,13 +27,12 @@ export function insert(
} else {
// fragment
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 {
const anchor = parent.firstChild
for (const b of blocks) insert(b, parent, anchor)
for (const b of blocks) insert(b, parent, 0)
}
// TODO optimize