2024-09-17 10:32:28 +08:00
|
|
|
import { type Ref, isRef, onScopeDispose } from '@vue/reactivity'
|
2024-04-25 04:57:45 +08:00
|
|
|
import {
|
2024-12-04 14:22:26 +08:00
|
|
|
type VaporComponentInstance,
|
2024-04-25 04:57:45 +08:00
|
|
|
currentInstance,
|
2024-12-11 11:50:17 +08:00
|
|
|
getExposed,
|
2024-04-25 04:57:45 +08:00
|
|
|
isVaporComponent,
|
2024-12-12 22:34:35 +08:00
|
|
|
} from './component'
|
2024-12-04 14:22:26 +08:00
|
|
|
import {
|
2025-01-30 10:12:36 +08:00
|
|
|
ErrorCodes,
|
2024-12-04 14:22:26 +08:00
|
|
|
type SchedulerJob,
|
|
|
|
callWithErrorHandling,
|
|
|
|
queuePostFlushCb,
|
|
|
|
warn,
|
|
|
|
} from '@vue/runtime-dom'
|
2024-04-13 02:54:34 +08:00
|
|
|
import {
|
|
|
|
EMPTY_OBJ,
|
|
|
|
hasOwn,
|
|
|
|
isArray,
|
|
|
|
isFunction,
|
|
|
|
isString,
|
|
|
|
remove,
|
|
|
|
} from '@vue/shared'
|
2024-01-20 23:48:10 +08:00
|
|
|
|
|
|
|
export type NodeRef = string | Ref | ((ref: Element) => void)
|
2024-12-04 14:22:26 +08:00
|
|
|
export type RefEl = Element | VaporComponentInstance
|
2024-01-20 23:48:10 +08:00
|
|
|
|
2024-12-12 22:34:35 +08:00
|
|
|
export type setRefFn = (
|
|
|
|
el: RefEl,
|
|
|
|
ref: NodeRef,
|
|
|
|
oldRef?: NodeRef,
|
|
|
|
refFor?: boolean,
|
|
|
|
) => NodeRef | undefined
|
|
|
|
|
|
|
|
export function createTemplateRefSetter(): setRefFn {
|
|
|
|
const instance = currentInstance as VaporComponentInstance
|
|
|
|
return (...args) => setRef(instance, ...args)
|
|
|
|
}
|
|
|
|
|
2024-01-20 23:48:10 +08:00
|
|
|
/**
|
|
|
|
* Function for handling a template ref
|
|
|
|
*/
|
2024-05-01 02:17:16 +08:00
|
|
|
export function setRef(
|
2024-12-12 22:34:35 +08:00
|
|
|
instance: VaporComponentInstance,
|
2024-05-01 02:17:16 +08:00
|
|
|
el: RefEl,
|
|
|
|
ref: NodeRef,
|
|
|
|
oldRef?: NodeRef,
|
|
|
|
refFor = false,
|
2024-08-09 16:56:59 +08:00
|
|
|
): NodeRef | undefined {
|
2024-12-12 22:34:35 +08:00
|
|
|
if (!instance || instance.isUnmounted) return
|
2024-01-20 23:48:10 +08:00
|
|
|
|
2024-12-12 22:34:35 +08:00
|
|
|
const setupState: any = __DEV__ ? instance.setupState || {} : null
|
2024-12-11 11:50:17 +08:00
|
|
|
const refValue = isVaporComponent(el) ? getExposed(el) || el : el
|
2024-04-25 04:57:45 +08:00
|
|
|
|
2024-01-21 13:59:56 +08:00
|
|
|
const refs =
|
2024-12-12 22:34:35 +08:00
|
|
|
instance.refs === EMPTY_OBJ ? (instance.refs = {}) : instance.refs
|
2024-01-21 13:59:56 +08:00
|
|
|
|
2024-05-01 02:17:16 +08:00
|
|
|
// dynamic ref changed. unset old ref
|
|
|
|
if (oldRef != null && oldRef !== ref) {
|
|
|
|
if (isString(oldRef)) {
|
|
|
|
refs[oldRef] = null
|
2024-12-12 22:34:35 +08:00
|
|
|
if (__DEV__ && hasOwn(setupState, oldRef)) {
|
2024-05-01 02:17:16 +08:00
|
|
|
setupState[oldRef] = null
|
|
|
|
}
|
|
|
|
} else if (isRef(oldRef)) {
|
|
|
|
oldRef.value = null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-20 23:48:10 +08:00
|
|
|
if (isFunction(ref)) {
|
2024-04-25 04:57:45 +08:00
|
|
|
const invokeRefSetter = (value?: Element | Record<string, any>) => {
|
2025-01-30 10:12:36 +08:00
|
|
|
callWithErrorHandling(ref, currentInstance, ErrorCodes.FUNCTION_REF, [
|
|
|
|
value,
|
|
|
|
refs,
|
|
|
|
])
|
2024-04-13 02:54:34 +08:00
|
|
|
}
|
|
|
|
|
2024-04-25 04:57:45 +08:00
|
|
|
invokeRefSetter(refValue)
|
2024-12-12 22:34:35 +08:00
|
|
|
// TODO this gets called repeatedly in renderEffect when it's dynamic ref?
|
2024-04-25 04:57:45 +08:00
|
|
|
onScopeDispose(() => invokeRefSetter())
|
2024-01-20 23:48:10 +08:00
|
|
|
} else {
|
|
|
|
const _isString = isString(ref)
|
|
|
|
const _isRef = isRef(ref)
|
2024-04-13 02:54:34 +08:00
|
|
|
let existing: unknown
|
2024-01-20 23:48:10 +08:00
|
|
|
|
|
|
|
if (_isString || _isRef) {
|
2024-04-13 02:54:34 +08:00
|
|
|
const doSet: SchedulerJob = () => {
|
|
|
|
if (refFor) {
|
|
|
|
existing = _isString
|
2024-12-12 22:34:35 +08:00
|
|
|
? __DEV__ && hasOwn(setupState, ref)
|
2024-04-13 02:54:34 +08:00
|
|
|
? setupState[ref]
|
|
|
|
: refs[ref]
|
|
|
|
: ref.value
|
|
|
|
|
|
|
|
if (!isArray(existing)) {
|
2024-04-25 04:57:45 +08:00
|
|
|
existing = [refValue]
|
2024-04-13 02:54:34 +08:00
|
|
|
if (_isString) {
|
|
|
|
refs[ref] = existing
|
2024-12-12 22:34:35 +08:00
|
|
|
if (__DEV__ && hasOwn(setupState, ref)) {
|
2024-04-13 02:54:34 +08:00
|
|
|
setupState[ref] = refs[ref]
|
|
|
|
// if setupState[ref] is a reactivity ref,
|
|
|
|
// the existing will also become reactivity too
|
|
|
|
// need to get the Proxy object by resetting
|
|
|
|
existing = setupState[ref]
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ref.value = existing
|
|
|
|
}
|
2024-04-25 04:57:45 +08:00
|
|
|
} else if (!existing.includes(refValue)) {
|
|
|
|
existing.push(refValue)
|
2024-04-13 02:54:34 +08:00
|
|
|
}
|
|
|
|
} else if (_isString) {
|
2024-04-25 04:57:45 +08:00
|
|
|
refs[ref] = refValue
|
2024-12-12 22:34:35 +08:00
|
|
|
if (__DEV__ && hasOwn(setupState, ref)) {
|
2024-04-25 04:57:45 +08:00
|
|
|
setupState[ref] = refValue
|
2024-01-20 23:48:10 +08:00
|
|
|
}
|
|
|
|
} else if (_isRef) {
|
2024-04-25 04:57:45 +08:00
|
|
|
ref.value = refValue
|
2024-01-20 23:48:10 +08:00
|
|
|
} else if (__DEV__) {
|
|
|
|
warn('Invalid template ref type:', ref, `(${typeof ref})`)
|
|
|
|
}
|
|
|
|
}
|
2024-04-13 02:54:34 +08:00
|
|
|
doSet.id = -1
|
2024-04-19 16:19:56 +08:00
|
|
|
queuePostFlushCb(doSet)
|
2024-04-13 02:54:34 +08:00
|
|
|
|
2024-12-12 22:34:35 +08:00
|
|
|
// TODO this gets called repeatedly in renderEffect when it's dynamic ref?
|
2024-04-13 02:54:34 +08:00
|
|
|
onScopeDispose(() => {
|
2024-04-19 16:19:56 +08:00
|
|
|
queuePostFlushCb(() => {
|
2024-04-13 02:54:34 +08:00
|
|
|
if (isArray(existing)) {
|
2024-04-25 04:57:45 +08:00
|
|
|
remove(existing, refValue)
|
2024-04-13 02:54:34 +08:00
|
|
|
} else if (_isString) {
|
|
|
|
refs[ref] = null
|
2024-12-12 22:34:35 +08:00
|
|
|
if (__DEV__ && hasOwn(setupState, ref)) {
|
2024-04-13 02:54:34 +08:00
|
|
|
setupState[ref] = null
|
|
|
|
}
|
|
|
|
} else if (_isRef) {
|
|
|
|
ref.value = null
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
2024-01-20 23:48:10 +08:00
|
|
|
} else if (__DEV__) {
|
2024-12-12 22:34:35 +08:00
|
|
|
warn('Invalid template ref type:', ref, `(${typeof ref})`)
|
2024-01-20 23:48:10 +08:00
|
|
|
}
|
|
|
|
}
|
2024-05-01 02:17:16 +08:00
|
|
|
return ref
|
2024-01-20 23:48:10 +08:00
|
|
|
}
|