Skip to content

Commit bb168c3

Browse files
committed
feat(runtime-vapor): fallback component
1 parent bc04592 commit bb168c3

File tree

4 files changed

+69
-25
lines changed

4 files changed

+69
-25
lines changed

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

Lines changed: 0 additions & 1 deletion
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

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,58 @@ 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 type { NormalizedRawProps, RawProps } from './componentProps'
88
import type { DynamicSlots, Slots } from './componentSlots'
9-
import { withAttrs } from './componentAttrs'
9+
import { walkRawProps, withAttrs } from './componentAttrs'
10+
import { isArray, isString } from '@vue/shared'
11+
import { renderEffect } from './renderEffect'
12+
import { normalizeBlock } from './dom/element'
13+
import { setDynamicProp } from './dom/prop'
1014

1115
export function createComponent(
12-
comp: Component,
16+
comp: Component | string,
1317
rawProps: RawProps | null = null,
1418
slots: Slots | null = null,
1519
dynamicSlots: DynamicSlots | null = null,
1620
singleRoot: boolean = false,
1721
once: boolean = false,
1822
) {
23+
if (isString(comp)) {
24+
// eslint-disable-next-line no-restricted-globals
25+
const el = document.createElement(comp)
26+
27+
if (rawProps) {
28+
if (!isArray(rawProps)) rawProps = [rawProps]
29+
renderEffect(() => {
30+
walkRawProps(rawProps as NormalizedRawProps, (key, value, getter) => {
31+
setDynamicProp(el, key, getter ? value() : value)
32+
})
33+
})
34+
}
35+
36+
if ((dynamicSlots && dynamicSlots.length) || (slots && slots.default)) {
37+
renderEffect(() => {
38+
let block: Block | undefined
39+
40+
if (slots && slots.default) {
41+
block = slots.default()
42+
} else {
43+
for (const slotFn of dynamicSlots!) {
44+
const slot = slotFn()
45+
if (slot.name === 'default') {
46+
block = slot.fn()
47+
break
48+
}
49+
}
50+
}
51+
52+
if (block) el.append(...normalizeBlock(block))
53+
})
54+
}
55+
56+
return el
57+
}
1958
const current = currentInstance!
2059
const instance = createComponentInstance(
2160
comp,

packages/runtime-vapor/src/componentAttrs.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { camelize, isArray, isFunction } 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 { NormalizedRawProps, RawProps } 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]
@@ -53,6 +42,24 @@ export function patchAttrs(instance: ComponentInternalInstance) {
5342
}
5443
}
5544

45+
export function walkRawProps(
46+
rawProps: NormalizedRawProps,
47+
cb: (key: string, value: any, getter?: boolean) => void,
48+
) {
49+
for (const props of Array.from(rawProps).reverse()) {
50+
if (isFunction(props)) {
51+
const resolved = props()
52+
for (const rawKey in resolved) {
53+
cb(rawKey, resolved[rawKey])
54+
}
55+
} else {
56+
for (const rawKey in props) {
57+
cb(rawKey, props[rawKey], true)
58+
}
59+
}
60+
}
61+
}
62+
5663
export function withAttrs(props: RawProps): RawProps {
5764
const instance = currentInstance!
5865
if (instance.component.inheritAttrs === false) return props

packages/runtime-vapor/src/componentSlots.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export interface DynamicSlot {
3535
fn: Slot
3636
}
3737

38-
type DynamicSlotFn = () => DynamicSlot | DynamicSlot[]
38+
type DynamicSlotFn = () => DynamicSlot
3939

4040
export type DynamicSlots = DynamicSlotFn[]
4141

@@ -60,12 +60,11 @@ export function initSlots(
6060
firstEffect(instance, () => {
6161
const slotRecord = (dynamicSlotRecords[index] =
6262
dynamicSlotRecords[index] || {})
63-
const dynamicSlot: DynamicSlot | DynamicSlot[] =
64-
callWithAsyncErrorHandling(
65-
fn,
66-
instance,
67-
VaporErrorCodes.RENDER_FUNCTION,
68-
)
63+
const dynamicSlot: DynamicSlot = callWithAsyncErrorHandling(
64+
fn,
65+
instance,
66+
VaporErrorCodes.RENDER_FUNCTION,
67+
)
6968
// array of dynamic slot generated by <template v-for="..." #[...]>
7069
if (isArray(dynamicSlot)) {
7170
for (let j = 0; j < dynamicSlot.length; j++) {

0 commit comments

Comments
 (0)