|
@@ -25,13 +25,23 @@ import {
|
|
|
isString,
|
|
isString,
|
|
|
remove,
|
|
remove,
|
|
|
} from '@vue/shared'
|
|
} from '@vue/shared'
|
|
|
-import { DynamicFragment, isDynamicFragment, isFragment } from './fragment'
|
|
|
|
|
|
|
+import {
|
|
|
|
|
+ type DynamicFragment,
|
|
|
|
|
+ type VaporFragment,
|
|
|
|
|
+ isDynamicFragment,
|
|
|
|
|
+ isFragment,
|
|
|
|
|
+} from './fragment'
|
|
|
|
|
+import { isInteropEnabled } from './vdomInteropState'
|
|
|
|
|
|
|
|
export type NodeRef =
|
|
export type NodeRef =
|
|
|
| string
|
|
| string
|
|
|
| Ref
|
|
| Ref
|
|
|
| ((ref: Element | VaporComponentInstance, refs: Record<string, any>) => void)
|
|
| ((ref: Element | VaporComponentInstance, refs: Record<string, any>) => void)
|
|
|
-export type RefEl = Element | VaporComponentInstance
|
|
|
|
|
|
|
+export type RefEl =
|
|
|
|
|
+ | Element
|
|
|
|
|
+ | VaporComponentInstance
|
|
|
|
|
+ | DynamicFragment
|
|
|
|
|
+ | VaporFragment
|
|
|
|
|
|
|
|
export type setRefFn = (
|
|
export type setRefFn = (
|
|
|
el: RefEl,
|
|
el: RefEl,
|
|
@@ -57,12 +67,25 @@ function ensureCleanup(el: RefEl): { fn: () => void } {
|
|
|
export function createTemplateRefSetter(): setRefFn {
|
|
export function createTemplateRefSetter(): setRefFn {
|
|
|
const instance = currentInstance as VaporComponentInstance
|
|
const instance = currentInstance as VaporComponentInstance
|
|
|
const oldRefMap = new WeakMap<RefEl, NodeRef | undefined>()
|
|
const oldRefMap = new WeakMap<RefEl, NodeRef | undefined>()
|
|
|
|
|
+ const setRefMap = new WeakMap<DynamicFragment, () => void>()
|
|
|
|
|
+
|
|
|
return (el, ref, refFor, refKey) => {
|
|
return (el, ref, refFor, refKey) => {
|
|
|
- if (isDynamicFragment(el)) {
|
|
|
|
|
- ;(el.onUpdated || (el.onUpdated = [])).push(() => {
|
|
|
|
|
- setRef(instance, el, ref, oldRefMap.get(el), refFor, refKey)
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ // Re-apply refs after DynamicFragment updates.
|
|
|
|
|
+ if (isDynamicFragment(el) || (isVaporComponent(el) && isAsyncWrapper(el))) {
|
|
|
|
|
+ const frag = isDynamicFragment(el)
|
|
|
|
|
+ ? (el as DynamicFragment)
|
|
|
|
|
+ : ((el as VaporComponentInstance).block as DynamicFragment)
|
|
|
|
|
+ const doSet = () =>
|
|
|
|
|
+ oldRefMap.set(
|
|
|
|
|
+ el,
|
|
|
|
|
+ setRef(instance, el, ref, oldRefMap.get(el), refFor, refKey),
|
|
|
|
|
+ )
|
|
|
|
|
+ const prevSet = setRefMap.get(frag)
|
|
|
|
|
+ if (prevSet && frag.onUpdated) remove(frag.onUpdated, prevSet)
|
|
|
|
|
+ ;(frag.onUpdated || (frag.onUpdated = [])).push(doSet)
|
|
|
|
|
+ setRefMap.set(frag, doSet)
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
const oldRef = setRef(instance, el, ref, oldRefMap.get(el), refFor, refKey)
|
|
const oldRef = setRef(instance, el, ref, oldRefMap.get(el), refFor, refKey)
|
|
|
oldRefMap.set(el, oldRef)
|
|
oldRefMap.set(el, oldRef)
|
|
|
return oldRef
|
|
return oldRef
|
|
@@ -72,7 +95,7 @@ export function createTemplateRefSetter(): setRefFn {
|
|
|
/**
|
|
/**
|
|
|
* Function for handling a template ref
|
|
* Function for handling a template ref
|
|
|
*/
|
|
*/
|
|
|
-export function setRef(
|
|
|
|
|
|
|
+function setRef(
|
|
|
instance: VaporComponentInstance,
|
|
instance: VaporComponentInstance,
|
|
|
el: RefEl,
|
|
el: RefEl,
|
|
|
ref: NodeRef,
|
|
ref: NodeRef,
|
|
@@ -83,22 +106,17 @@ export function setRef(
|
|
|
if (!instance || instance.isUnmounted) return
|
|
if (!instance || instance.isUnmounted) return
|
|
|
|
|
|
|
|
// vdom interop
|
|
// vdom interop
|
|
|
- if (isFragment(el) && el.setRef) {
|
|
|
|
|
|
|
+ if (isInteropEnabled && isFragment(el) && el.setRef) {
|
|
|
el.setRef(instance, ref, refFor, refKey)
|
|
el.setRef(instance, ref, refFor, refKey)
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (isVaporComponent(el) && isAsyncWrapper(el)) {
|
|
if (isVaporComponent(el) && isAsyncWrapper(el)) {
|
|
|
- const frag = el.block as DynamicFragment
|
|
|
|
|
- // async component not resolved yet, register ref setter
|
|
|
|
|
- // it will be called when the async component is resolved
|
|
|
|
|
- if (!el.type.__asyncResolved) {
|
|
|
|
|
- frag.setAsyncRef = i => setRef(instance, i, ref, oldRef, refFor)
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // unresolved: handled in DynamicFragment's updated hook
|
|
|
|
|
+ if (!el.type.__asyncResolved) return
|
|
|
|
|
|
|
|
- // set ref to the inner component instead
|
|
|
|
|
- el = frag.nodes as VaporComponentInstance
|
|
|
|
|
|
|
+ // resolved: set ref to the inner component
|
|
|
|
|
+ el = (el.block as DynamicFragment).nodes as VaporComponentInstance
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const setupState: any = __DEV__ ? instance.setupState || {} : null
|
|
const setupState: any = __DEV__ ? instance.setupState || {} : null
|
|
@@ -121,7 +139,7 @@ export function setRef(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// dynamic ref changed. unset old ref
|
|
// dynamic ref changed. unset old ref
|
|
|
- if (oldRef != null && (oldRef !== ref || isDynamicFragment(el))) {
|
|
|
|
|
|
|
+ if (oldRef != null && oldRef !== ref) {
|
|
|
if (isString(oldRef)) {
|
|
if (isString(oldRef)) {
|
|
|
refs[oldRef] = null
|
|
refs[oldRef] = null
|
|
|
if (__DEV__ && canSetSetupRef(oldRef)) {
|
|
if (__DEV__ && canSetSetupRef(oldRef)) {
|
|
@@ -129,12 +147,28 @@ export function setRef(
|
|
|
}
|
|
}
|
|
|
} else if (isRef(oldRef)) {
|
|
} else if (isRef(oldRef)) {
|
|
|
if (canSetRef(oldRef)) oldRef.value = null
|
|
if (canSetRef(oldRef)) oldRef.value = null
|
|
|
|
|
+ } else if (isFunction(oldRef) && isDynamicFragment(el)) {
|
|
|
|
|
+ callWithErrorHandling(oldRef, instance, ErrorCodes.FUNCTION_REF, [
|
|
|
|
|
+ null,
|
|
|
|
|
+ refs,
|
|
|
|
|
+ ])
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (oldRef != null && isDynamicFragment(el)) {
|
|
|
|
|
+ if (isFunction(oldRef)) {
|
|
|
|
|
+ callWithErrorHandling(oldRef, instance, ErrorCodes.FUNCTION_REF, [
|
|
|
|
|
+ null,
|
|
|
|
|
+ refs,
|
|
|
|
|
+ ])
|
|
|
|
|
+ } else if (refFor) {
|
|
|
|
|
+ // For dynamic ref-for branches, remove only this branch's previous value.
|
|
|
|
|
+ const cleanup = refCleanups.get(el)
|
|
|
|
|
+ if (cleanup) cleanup.fn()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (isFunction(ref)) {
|
|
if (isFunction(ref)) {
|
|
|
const invokeRefSetter = (value?: Element | Record<string, any> | null) => {
|
|
const invokeRefSetter = (value?: Element | Record<string, any> | null) => {
|
|
|
- callWithErrorHandling(ref, currentInstance, ErrorCodes.FUNCTION_REF, [
|
|
|
|
|
|
|
+ callWithErrorHandling(ref, instance, ErrorCodes.FUNCTION_REF, [
|
|
|
value,
|
|
value,
|
|
|
refs,
|
|
refs,
|
|
|
])
|
|
])
|
|
@@ -215,7 +249,8 @@ export function setRef(
|
|
|
const getRefValue = (el: RefEl) => {
|
|
const getRefValue = (el: RefEl) => {
|
|
|
if (isVaporComponent(el)) {
|
|
if (isVaporComponent(el)) {
|
|
|
return getExposed(el) || el
|
|
return getExposed(el) || el
|
|
|
- } else if (el instanceof DynamicFragment) {
|
|
|
|
|
|
|
+ } else if (isDynamicFragment(el)) {
|
|
|
|
|
+ if (isArray(el.nodes)) return null
|
|
|
return getRefValue(el.nodes as RefEl)
|
|
return getRefValue(el.nodes as RefEl)
|
|
|
}
|
|
}
|
|
|
return el
|
|
return el
|