Răsfoiți Sursa

wip: handle template ref forwarding

daiwei 1 an în urmă
părinte
comite
367924ca9e

+ 1 - 0
packages/runtime-core/src/index.ts

@@ -563,6 +563,7 @@ export { initFeatureFlags } from './featureFlags'
 export {
   createAsyncComponentContext,
   useAsyncComponentState,
+  isAsyncWrapper,
 } from './apiAsyncComponent'
 /**
  * @internal

+ 1 - 1
packages/runtime-vapor/__tests__/apiDefineAsyncComponent.spec.ts

@@ -629,7 +629,7 @@ describe('api: defineAsyncComponent', () => {
     expect(root.innerHTML).toBe('<!--async component-->')
   })
 
-  test.todo('template ref forwarding', async () => {
+  test('template ref forwarding', async () => {
     let resolve: (comp: VaporComponent) => void
     const Foo = defineVaporAsyncComponent(
       () =>

+ 12 - 3
packages/runtime-vapor/src/apiDefineAsyncComponent.ts

@@ -38,7 +38,6 @@ export function defineVaporAsyncComponent<T extends VaporComponent>(
   return defineVaporComponent({
     name: 'VaporAsyncComponentWrapper',
 
-    // @ts-expect-error
     __asyncLoader: load,
 
     // __asyncHydrate(el, instance, hydrate) {
@@ -97,7 +96,7 @@ export function defineVaporAsyncComponent<T extends VaporComponent>(
         resolvedComp = getResolvedComp()
         let blockFn
         if (loaded.value && resolvedComp) {
-          blockFn = () => createInnerComp(resolvedComp!, instance)
+          blockFn = () => createInnerComp(resolvedComp!, instance, frag)
         } else if (error.value && errorComponent) {
           blockFn = () =>
             createComponent(errorComponent, { error: () => error.value })
@@ -115,7 +114,17 @@ export function defineVaporAsyncComponent<T extends VaporComponent>(
 function createInnerComp(
   comp: VaporComponent,
   parent: VaporComponentInstance,
+  frag?: DynamicFragment,
 ): VaporComponentInstance {
   const { rawProps, rawSlots, isSingleRoot, appContext } = parent
-  return createComponent(comp, rawProps, rawSlots, isSingleRoot, appContext)
+  const i = createComponent(comp, rawProps, rawSlots, isSingleRoot, appContext)
+  // set ref
+  frag && frag.setRef && frag.setRef(i)
+
+  // TODO custom element
+  // pass the custom element callback on to the inner comp
+  // and remove it from the async wrapper
+  // i.ce = ce
+  // delete parent.ce
+  return i
 }

+ 17 - 1
packages/runtime-vapor/src/apiTemplateRef.ts

@@ -7,8 +7,10 @@ import {
 } from './component'
 import {
   ErrorCodes,
+  type GenericComponentInstance,
   type SchedulerJob,
   callWithErrorHandling,
+  isAsyncWrapper,
   queuePostFlushCb,
   warn,
 } from '@vue/runtime-dom'
@@ -20,6 +22,7 @@ import {
   isString,
   remove,
 } from '@vue/shared'
+import type { DynamicFragment } from './block'
 
 export type NodeRef = string | Ref | ((ref: Element) => void)
 export type RefEl = Element | VaporComponentInstance
@@ -47,9 +50,22 @@ export function setRef(
   refFor = false,
 ): NodeRef | undefined {
   if (!instance || instance.isUnmounted) return
+  const isVaporComp = isVaporComponent(el)
+  if (isVaporComp && isAsyncWrapper(el as GenericComponentInstance)) {
+    if (!(el as VaporComponentInstance).type.__asyncResolved) {
+      const frag = (el as VaporComponentInstance).block as DynamicFragment
+      frag.setRef = (el: RefEl) => setRef(instance, el, ref, oldRef, refFor)
+      return
+    } else {
+      el = ((el as VaporComponentInstance).block as DynamicFragment)
+        .nodes as RefEl
+    }
+  }
 
   const setupState: any = __DEV__ ? instance.setupState || {} : null
-  const refValue = isVaporComponent(el) ? getExposed(el) || el : el
+  const refValue = isVaporComp
+    ? getExposed(el as VaporComponentInstance) || el
+    : el
 
   const refs =
     instance.refs === EMPTY_OBJ ? (instance.refs = {}) : instance.refs

+ 2 - 0
packages/runtime-vapor/src/block.ts

@@ -8,6 +8,7 @@ import {
 import { createComment, createTextNode } from './dom/node'
 import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
 import { isHydrating } from './dom/hydration'
+import type { RefEl } from './apiTemplateRef'
 
 export type Block =
   | Node
@@ -23,6 +24,7 @@ export class VaporFragment {
   anchor?: Node
   insert?: (parent: ParentNode, anchor: Node | null) => void
   remove?: (parent?: ParentNode) => void
+  setRef?: (el: RefEl) => void
 
   constructor(nodes: Block) {
     this.nodes = nodes

+ 2 - 0
packages/runtime-vapor/src/component.ts

@@ -92,6 +92,8 @@ export interface ObjectVaporComponent
 
   name?: string
   vapor?: boolean
+  __asyncLoader?: () => Promise<VaporComponent>
+  __asyncResolved?: VaporComponent
 }
 
 interface SharedInternalOptions {