Skip to content

Commit cec7c20

Browse files
committed
feat(runtime-vapor): fallback component
1 parent a8248cf commit cec7c20

File tree

4 files changed

+84
-22
lines changed

4 files changed

+84
-22
lines changed

packages/runtime-vapor/__tests__/apiCreateVaporApp.spec.ts

-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ describe('api: createVaporApp', () => {
134134
setup() {
135135
const FooBar = resolveComponent('foo-bar')
136136
const BarBaz = resolveComponent('bar-baz')
137-
// @ts-expect-error TODO support string
138137
return [createComponent(FooBar), createComponent(BarBaz)]
139138
},
140139
}).create()

packages/runtime-vapor/src/apiCreateComponent.ts

+56-3
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,31 @@ import {
33
createComponentInstance,
44
currentInstance,
55
} from './component'
6-
import { setupComponent } from './apiRender'
7-
import type { RawProps } from './componentProps'
6+
import { type Block, setupComponent } from './apiRender'
7+
import {
8+
type NormalizedRawProps,
9+
type RawProps,
10+
normalizeRawProps,
11+
walkRawProps,
12+
} from './componentProps'
813
import type { RawSlots } from './componentSlots'
914
import { withAttrs } from './componentAttrs'
15+
import { isString } from '@vue/shared'
16+
import { renderEffect } from './renderEffect'
17+
import { normalizeBlock } from './dom/element'
18+
import { setDynamicProp } from './dom/prop'
1019

1120
export function createComponent(
12-
comp: Component,
21+
comp: Component | string,
1322
rawProps: RawProps | null = null,
1423
slots: RawSlots | null = null,
1524
singleRoot: boolean = false,
1625
once: boolean = false,
1726
) {
27+
if (isString(comp)) {
28+
return fallbackComponent(comp, rawProps, slots, singleRoot)
29+
}
30+
1831
const current = currentInstance!
1932
const instance = createComponentInstance(
2033
comp,
@@ -29,3 +42,43 @@ export function createComponent(
2942

3043
return instance
3144
}
45+
46+
function fallbackComponent(
47+
comp: string,
48+
rawProps: RawProps | null,
49+
slots: RawSlots | null,
50+
singleRoot: boolean,
51+
) {
52+
// eslint-disable-next-line no-restricted-globals
53+
const el = document.createElement(comp)
54+
55+
if (rawProps) {
56+
rawProps = normalizeRawProps(rawProps)
57+
renderEffect(() => {
58+
walkRawProps(rawProps as NormalizedRawProps, (key, value, getter) => {
59+
setDynamicProp(el, key, getter ? value() : value)
60+
})
61+
})
62+
}
63+
64+
if (slots && slots.length) {
65+
renderEffect(() => {
66+
let block: Block | undefined
67+
68+
if (slots && slots.default) {
69+
block = slots.default()
70+
} else {
71+
for (const slotFn of dynamicSlots!) {
72+
const slot = slotFn()
73+
if (slot.name === 'default') {
74+
block = slot.fn()
75+
break
76+
}
77+
}
78+
}
79+
80+
if (block) el.append(...normalizeBlock(block))
81+
})
82+
}
83+
return { __return: el, rawProps }
84+
}

packages/runtime-vapor/src/componentAttrs.ts

+3-14
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { camelize, isArray, isFunction } from '@vue/shared'
1+
import { camelize, isArray } from '@vue/shared'
22
import { type ComponentInternalInstance, currentInstance } from './component'
33
import { isEmitListener } from './componentEmits'
44
import { setDynamicProps } from './dom/prop'
5-
import type { RawProps } from './componentProps'
5+
import { type RawProps, walkRawProps } from './componentProps'
66
import { renderEffect } from './renderEffect'
77

88
export function patchAttrs(instance: ComponentInternalInstance) {
@@ -14,19 +14,8 @@ export function patchAttrs(instance: ComponentInternalInstance) {
1414

1515
if (!rawProps.length) return
1616
const keys = new Set<string>()
17-
for (const props of Array.from(rawProps).reverse()) {
18-
if (isFunction(props)) {
19-
const resolved = props()
20-
for (const rawKey in resolved) {
21-
registerAttr(rawKey, resolved[rawKey])
22-
}
23-
} else {
24-
for (const rawKey in props) {
25-
registerAttr(rawKey, props[rawKey], true)
26-
}
27-
}
28-
}
2917

18+
walkRawProps(rawProps, registerAttr)
3019
for (const key in attrs) {
3120
if (!keys.has(key)) {
3221
delete attrs[key]

packages/runtime-vapor/src/componentProps.ts

+25-4
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,7 @@ export function initProps(
8383
isStateful: boolean,
8484
once: boolean,
8585
) {
86-
if (!rawProps) rawProps = []
87-
else if (!isArray(rawProps)) rawProps = [rawProps]
88-
instance.rawProps = rawProps
89-
86+
instance.rawProps = rawProps = normalizeRawProps(rawProps)
9087
const props: Data = {}
9188
const attrs = (instance.attrs = shallowReactive<Data>({}))
9289
const [options] = instance.propsOptions
@@ -166,6 +163,30 @@ function registerProp(
166163
}
167164
}
168165

166+
export function normalizeRawProps(rawProps: RawProps) {
167+
if (!rawProps) return []
168+
if (!isArray(rawProps)) return [rawProps]
169+
return rawProps
170+
}
171+
172+
export function walkRawProps(
173+
rawProps: NormalizedRawProps,
174+
cb: (key: string, value: any, getter?: boolean) => void,
175+
) {
176+
for (const props of Array.from(rawProps).reverse()) {
177+
if (isFunction(props)) {
178+
const resolved = props()
179+
for (const rawKey in resolved) {
180+
cb(rawKey, resolved[rawKey])
181+
}
182+
} else {
183+
for (const rawKey in props) {
184+
cb(rawKey, props[rawKey], true)
185+
}
186+
}
187+
}
188+
}
189+
169190
function getRawKey(obj: Data, key: string) {
170191
return Object.keys(obj).find(k => camelize(k) === key)
171192
}

0 commit comments

Comments
 (0)