Skip to content

Commit afafd83

Browse files
committed
feat(runtime-vapor): fallback component
1 parent f85ac40 commit afafd83

File tree

4 files changed

+84
-22
lines changed

4 files changed

+84
-22
lines changed

Diff for: 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()

Diff for: packages/runtime-vapor/src/apiCreateComponent.ts

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

1221
export function createComponent(
13-
comp: Component,
22+
comp: Component | string,
1423
rawProps: RawProps | null = null,
1524
slots: RawSlots | null = null,
1625
singleRoot: boolean = false,
1726
once: boolean = false,
1827
): ComponentInternalInstance {
28+
if (isString(comp)) {
29+
return fallbackComponent(comp, rawProps, slots, singleRoot)
30+
}
31+
1932
const current = currentInstance!
2033
const instance = createComponentInstance(
2134
comp,
@@ -30,3 +43,43 @@ export function createComponent(
3043

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

Diff for: 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): void {
@@ -14,19 +14,8 @@ export function patchAttrs(instance: ComponentInternalInstance): void {
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]

Diff for: 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
): void {
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)