import { getReactFuncs } from "xbsj-xe2/dist-node/xe2-base-utils"; import { Ref, ref, ShallowRef, shallowRef, UnwrapRef, watch } from "vue"; import { Destroyable, getExtProp, ReactParamsType, setExtProp } from "xbsj-xe2/dist-node/xe2-base-utils"; import { VueRefDisposer } from "./createVueDisposer"; function _toVueRef(reactVar: ReactParamsType, readonly: boolean, toVueValue: ((s: Xe2ValueType) => VueValueType) | undefined, toXe2Value: ((s: VueValueType) => Xe2ValueType) | undefined, shallow: true): ShallowRef; function _toVueRef(reactVar: ReactParamsType, readonly: boolean, toVueValue: ((s: Xe2ValueType) => VueValueType) | undefined, toXe2Value: ((s: VueValueType) => Xe2ValueType) | undefined, shallow: false): Ref; function _toVueRef(reactVar: ReactParamsType, readonly: boolean, toVueValue: ((s: Xe2ValueType) => VueValueType) | undefined, toXe2Value: ((s: VueValueType) => Xe2ValueType) | undefined, shallow: boolean) { const [getValue, setValue, valueChanged] = getReactFuncs(reactVar); const defaultValue = getValue() as Xe2ValueType; const vueRef = !shallow ? ref(toVueValue ? toVueValue(defaultValue) : defaultValue as unknown as VueValueType) : shallowRef(defaultValue as unknown as VueValueType); const disposer = new Destroyable(); const unlinkFunc = () => !disposer.isDestroyed() && disposer.destroy(); if (!readonly) { disposer.dispose(watch(vueRef, val => { const vueValue = val as unknown as VueValueType; setValue(toXe2Value ? toXe2Value(vueValue) : (vueValue as unknown as Xe2ValueType)); }, { deep: !!toVueValue })); } if (valueChanged) { disposer.dispose(valueChanged.dwon(() => { const xe2Value = getValue(); vueRef.value = toVueValue ? toVueValue(xe2Value) : (xe2Value as unknown as VueValueType); })); } setVueRefDisposeFunc(vueRef, unlinkFunc); return vueRef; } export function setVueRefDisposeFunc(vueRef: Ref, disposeFunc: () => void) { setExtProp(vueRef, '_vueRefDisposeFunc', disposeFunc); } export function getVueRefDisposeFunc(vueRef: Ref) { return getExtProp<() => void>(vueRef, '_vueRefDisposeFunc'); } export function destroyVueRef(vueRef: Ref) { const disposeFunc = getVueRefDisposeFunc(vueRef); if (disposeFunc) { disposeFunc(); } else { console.warn(`cannot find disposeFunc from vueRef!`); } } function _toVueRefWithoutUndefined(reactVar: ReactParamsType, defaultValue: T, cloneVueValueFunc: ((v: T) => T) | undefined, readonly: boolean, shallow: true): ShallowRef; function _toVueRefWithoutUndefined(reactVar: ReactParamsType, defaultValue: T, cloneVueValueFunc: ((v: T) => T) | undefined, readonly: boolean, shallow: false): Ref; function _toVueRefWithoutUndefined(reactVar: ReactParamsType, defaultValue: T, cloneVueValueFunc: ((v: T) => T) | undefined, readonly: boolean, shallow: boolean) { const [getValue] = getReactFuncs(reactVar); if (shallow) { return _toVueRef( reactVar, readonly, v => cloneVueValueFunc ? cloneVueValueFunc(v ?? defaultValue) : (v ?? defaultValue), s => (s === defaultValue && getValue() === undefined) ? undefined : s, true, ); } else { return _toVueRef( reactVar, readonly, v => cloneVueValueFunc ? cloneVueValueFunc(v ?? defaultValue) : (v ?? defaultValue), s => (s === defaultValue && getValue() === undefined) ? undefined : s, false, ); } } /** * 用来将xe2的响应式变量转变成vue3的响应式变量 * @example * const d = createVueDisposer(onBeforeUnmount); * const propUiTreeRef = toReadonlyVueRef(d, [propUiTreeManager, 'propUiTree']); * const showSceneTreeViewRef = toVR(d, [projectManager, "showSceneTreeView"]) * const showPlayerViewRef = toVR(d, [projectManager, "showPlayerView"]) */ export function toVueRef(disposer: VueRefDisposer, reactVar: ReactParamsType, toVueValue?: (s: Xe2ValueType) => VueValueType, toXe2Value?: (s: VueValueType) => Xe2ValueType) { return disposer.disposeVueRef(_toVueRef(reactVar, false, toVueValue, toXe2Value, false)) as Ref; } /** * toVR = toVueRef */ export const toVR = toVueRef; /** * 用来将xe2的响应式变量转变成vue3的响应式变量 * @example * const d = createVueDisposer(onBeforeUnmount); * const propUiTreeRef = toReadonlyVueRef(d, [propUiTreeManager, 'propUiTree']); * const showSceneTreeViewRef = toVR(d, [projectManager, "showSceneTreeView"]) * const showPlayerViewRef = toVR(d, [projectManager, "showPlayerView"]) */ export function toShallowVueRef(disposer: VueRefDisposer, reactVar: ReactParamsType, toVueValue?: (s: Xe2ValueType) => VueValueType, toXe2Value?: (s: VueValueType) => Xe2ValueType) { return disposer.disposeVueRef(_toVueRef(reactVar, false, toVueValue, toXe2Value, true)) as ShallowRef; } /** * toSVR = toShallowVueRef */ export const toSVR = toShallowVueRef; /** * 用来将xe2的响应式变量转变成vue3的响应式变量 * @example * const d = createVueDisposer(onBeforeUnmount); * const propUiTreeRef = toReadonlyVueRef(d, [propUiTreeManager, 'propUiTree']); * const showSceneTreeViewRef = toVR(d, [projectManager, "showSceneTreeView"]) * const showPlayerViewRef = toVR(d, [projectManager, "showPlayerView"]) */ export function toReadonlyVueRef(disposer: VueRefDisposer, reactVar: ReactParamsType, toVueValue?: (s: Xe2ValueType) => VueValueType, toXe2Value?: (s: VueValueType) => Xe2ValueType) { return disposer.disposeVueRef(_toVueRef(reactVar, true, toVueValue, toXe2Value, false)) as Ref }; /** * toRVR = toReadonlyVueRef */ export const toRVR = toReadonlyVueRef; /** * 用来将xe2的响应式变量转变成vue3的响应式变量 * @example * const d = createVueDisposer(onBeforeUnmount); * const propUiTreeRef = toReadonlyVueRef(d, [propUiTreeManager, 'propUiTree']); * const showSceneTreeViewRef = toVR(d, [projectManager, "showSceneTreeView"]) * const showPlayerViewRef = toVR(d, [projectManager, "showPlayerView"]) */ export function toReadonlyShallowVueRef(disposer: VueRefDisposer, reactVar: ReactParamsType, toVueValue?: (s: Xe2ValueType) => VueValueType, toXe2Value?: (s: VueValueType) => Xe2ValueType) { return disposer.disposeVueRef(_toVueRef(reactVar, true, toVueValue, toXe2Value, true)) as ShallowRef }; /** * toRSVR = toReadonlyShallowVueRef */ export const toRSVR = toReadonlyShallowVueRef; /** * 用来将xe2的响应式变量转变成vue3的响应式变量,并且去掉undefined * @example * const d = createVueDisposer(onBeforeUnmount); * const propUiTreeRef = toReadonlyVueRef(d, [propUiTreeManager, 'propUiTree']); * const showSceneTreeViewRef = toVR(d, [projectManager, "showSceneTreeView"]) * const showPlayerViewRef = toVR(d, [projectManager, "showPlayerView"]) */ export function toVueRefWithoutUndefined(disposer: VueRefDisposer, reactVar: ReactParamsType, defaultValue: T, cloneVueValueFunc?: ((v: T) => T) | undefined) { return disposer.disposeVueRef(_toVueRefWithoutUndefined(reactVar, defaultValue, cloneVueValueFunc, false, false)); } export function toShallowVueRefWithoutUndefined(disposer: VueRefDisposer, reactVar: ReactParamsType, defaultValue: T, cloneVueValueFunc?: ((v: T) => T) | undefined) { return disposer.disposeVueRef(_toVueRefWithoutUndefined(reactVar, defaultValue, cloneVueValueFunc, false, true)); } export function toReadonlyVueRefWithoutUndefined(disposer: VueRefDisposer, reactVar: ReactParamsType, defaultValue: T, cloneVueValueFunc?: ((v: T) => T) | undefined) { return disposer.disposeVueRef(_toVueRefWithoutUndefined(reactVar, defaultValue, cloneVueValueFunc, true, false)); } export function toReadonlyShallowVueRefWithoutUndefined(disposer: VueRefDisposer, reactVar: ReactParamsType, defaultValue: T, cloneVueValueFunc?: ((v: T) => T) | undefined) { return disposer.disposeVueRef(_toVueRefWithoutUndefined(reactVar, defaultValue, cloneVueValueFunc, true, true)); } /** * toVRWU = toVueRefWithoutUndefined */ export const toVRWU = toVueRefWithoutUndefined; /** * toSVRWU = toShallowVueRefWithoutUndefined */ export const toSVRWU = toShallowVueRefWithoutUndefined; /** * toRVRWU = toReadonlyVueRefWithoutUndefined */ export const toRVRWU = toReadonlyVueRefWithoutUndefined; /** * toRSVRWU = toReadonlyShallowVueRefWithoutUndefined */ export const toRSVRWU = toReadonlyShallowVueRefWithoutUndefined;