diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index 00ee4df85..b6e2c6213 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -54,7 +54,9 @@ export function genCreateComponent( NEWLINE, `const n${operation.id} = `, ...genCall( - vaporHelper('createComponent'), + operation.asset + ? vaporHelper('createComponentWithFallback') + : vaporHelper('createComponent'), tag, rawProps, rawSlots, diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index aeaa07164..40290a080 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -19,17 +19,19 @@ import { } from '@vue/runtime-dom' import { type Block, isBlock } from './block' import { pauseTracking, resetTracking } from '@vue/reactivity' -import { EMPTY_OBJ, isFunction } from '@vue/shared' +import { EMPTY_OBJ, isFunction, isString } from '@vue/shared' import { type RawProps, getPropsProxyHandlers, hasFallthroughAttrs, normalizePropsOptions, + resolveDynamicProps, setupPropsValidation, } from './componentProps' -import { setDynamicProp } from './dom/prop' import { renderEffect } from './renderEffect' import { emit, normalizeEmitsOptions } from './componentEmits' +import { setStyle } from './dom/style' +import { setClass, setDynamicProp } from './dom/prop' export { currentInstance } from '@vue/runtime-dom' @@ -266,7 +268,7 @@ export function isVaporComponent( export class SetupContext { attrs: Record emit: EmitFn - // slots: Readonly + // TODO slots: Readonly expose: (exposed?: Record) => void constructor(instance: VaporComponentInstance) { @@ -278,3 +280,47 @@ export class SetupContext { } } } + +export function createComponentWithFallback( + comp: VaporComponent | string, + rawProps: RawProps | undefined, + // TODO slots: RawSlots | null + isSingleRoot?: boolean, +): HTMLElement | VaporComponentInstance { + if (!isString(comp)) { + return createComponent(comp, rawProps, isSingleRoot) + } + + // eslint-disable-next-line no-restricted-globals + const el = document.createElement(comp) + + if (rawProps) { + renderEffect(() => { + let classes: unknown[] | undefined + let styles: unknown[] | undefined + const resolved = resolveDynamicProps(rawProps) + for (const key in resolved) { + const value = resolved[key] + if (key === 'class') (classes ||= []).push(value) + else if (key === 'style') (styles ||= []).push(value) + else setDynamicProp(el, key, value) + } + if (classes) setClass(el, classes) + if (styles) setStyle(el, styles) + }) + } + + // TODO + // if (slots) { + // if (!Array.isArray(slots)) slots = [slots] + // for (let i = 0; i < slots.length; i++) { + // const slot = slots[i] + // if (!isDynamicSlotFn(slot) && slot.default) { + // const block = slot.default && slot.default() + // if (block) el.append(...normalizeBlock(block)) + // } + // } + // } + + return el +} diff --git a/packages/runtime-vapor/src/componentProps.ts b/packages/runtime-vapor/src/componentProps.ts index ff941d2ec..e9336b5ed 100644 --- a/packages/runtime-vapor/src/componentProps.ts +++ b/packages/runtime-vapor/src/componentProps.ts @@ -231,29 +231,33 @@ export function setupPropsValidation(instance: VaporComponentInstance): void { const rawProps = instance.rawProps if (!rawProps) return renderEffect(() => { - const mergedRawProps: Record = {} - for (const key in rawProps) { - if (key !== '$') { - mergedRawProps[key] = rawProps[key]() - } - } - if (rawProps.$) { - for (const source of rawProps.$) { - const isDynamic = isFunction(source) - const resolved = isDynamic ? source() : source - for (const key in resolved) { - mergedRawProps[key] = isDynamic - ? resolved[key] - : (resolved[key] as Function)() - } - } - } pushWarningContext(instance) validateProps( - mergedRawProps, + resolveDynamicProps(rawProps), instance.props, normalizePropsOptions(instance.type)[0]!, ) popWarningContext() }, true /* noLifecycle */) } + +export function resolveDynamicProps(props: RawProps): Record { + const mergedRawProps: Record = {} + for (const key in props) { + if (key !== '$') { + mergedRawProps[key] = props[key]() + } + } + if (props.$) { + for (const source of props.$) { + const isDynamic = isFunction(source) + const resolved = isDynamic ? source() : source + for (const key in resolved) { + mergedRawProps[key] = isDynamic + ? resolved[key] + : (resolved[key] as Function)() + } + } + } + return mergedRawProps +} diff --git a/packages/runtime-vapor/src/index.ts b/packages/runtime-vapor/src/index.ts index a368fa638..eeced2e2a 100644 --- a/packages/runtime-vapor/src/index.ts +++ b/packages/runtime-vapor/src/index.ts @@ -1,4 +1,4 @@ -export { createComponent } from './component' +export { createComponent, createComponentWithFallback } from './component' export { renderEffect } from './renderEffect' export { createVaporApp } from './apiCreateApp' export { defineComponent } from './apiDefineComponent' @@ -19,3 +19,6 @@ export { } from './dom/prop' export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event' export { setRef } from './dom/templateRef' + +// re-exports +export { resolveComponent } from '@vue/runtime-dom'