UNPKG

vue-reactivity-fantasy

Version:
319 lines (299 loc) 8.21 kB
'use strict'; const vue = require('vue'); const vueModuleDemi = require('vue-module-demi'); function untrack(fn) { const reactiveScope = vue.computed(() => fn()); const reactiveEffect = reactiveScope.effect; if (vueModuleDemi.isVue2) { reactiveEffect.teardown(); return reactiveEffect.get(); } else { const result = reactiveScope.value; reactiveEffect.stop(); return result; } } const tick = /* @__PURE__ */ Promise.resolve(); const queue = []; let queued = false; const scheduler = (fn) => { queue.push(fn); if (!queued) { queued = true; tick.then(flush); } }; const flush = () => { for (let i = 0; i < queue.length; i++) { queue[i](); } queue.length = 0; queued = false; }; function batch(fn) { const reactiveScope = vue.computed(() => fn()); const reactiveEffect = reactiveScope.effect; let scheduled = false; if (vueModuleDemi.isVue2) { const [track, trigger] = useForceUpdate(); let value; untrack(() => { const scope = vue.effectScope(true); scope.run(() => { value = reactiveScope.value; if (scheduled) { return; } scheduler(() => { trigger(); scheduled = false; }); scheduled = false; }); }); track(); return value; } else { const originScheduler = reactiveEffect.scheduler; reactiveEffect.scheduler = () => { if (scheduled) { return; } scheduler(() => { if (reactiveEffect.active) { if (originScheduler) { originScheduler(); } else { reactiveEffect.run(); } } scheduled = false; }); scheduled = false; }; } return reactiveScope.value; } function isWritableRef(v) { return vue.isRef(v) && !vue.isReadonly(v); } function isValidDependency(dep) { return vue.isRef(dep) || vue.isReactive(dep) || isFunction(dep) || Array.isArray(dep) && dep.every(isValidDependency); } function isFunction(val) { return typeof val === "function"; } function createManualEffect(setup, immediate = false) { let state = 0; let cleanup; const onCleanup = (fn) => { cleanup = fn; }; const clear = () => { isFunction(cleanup) && cleanup(); cleanup = void 0; state = 0; }; const doSetup = () => { if (isFunction(setup)) { const returnSetup = setup(onCleanup); if (!isFunction(cleanup) && isFunction(returnSetup)) { cleanup = returnSetup; } state++; } }; const ensure = () => { if (!state) { doSetup(); } }; const reset = (overrideSetup) => { if (isFunction(overrideSetup)) { setup = overrideSetup; } clear(); doSetup(); }; if (immediate) { doSetup(); } return { clear, ensure, reset }; } function resolveSourceValue(source) { return resolveSourceValueGetter(source)(); } function resolveSourceValueGetter(source) { return isFunction(source) ? source : () => vue.unref(source); } function resolveComputed(source) { return vue.computed(resolveSourceValueGetter(source)); } function createToggleControl(value, defaultValue, reverseValue) { const getDefaultValue = resolveSourceValueGetter(defaultValue); const getReverseValue = resolveSourceValueGetter(reverseValue); return { value, set: (newValue) => value.value = newValue, setDefault: () => value.value = getDefaultValue(), setReverse: () => value.value = getReverseValue(), toggle: () => { const defaultValue2 = getDefaultValue(); value.value = value.value === defaultValue2 ? getReverseValue() : defaultValue2; } }; } function useBoolean(initialValue = false) { const stateRef = isWritableRef(initialValue) ? initialValue : vue.ref(!!vue.unref(initialValue)); const toggleControl = createToggleControl( stateRef, () => true, () => false ); return [ stateRef, { set: toggleControl.set, setTrue: toggleControl.setDefault, setFalse: toggleControl.setReverse, toggle: toggleControl.toggle } ]; } function useComputed(source, setter, debugOptions) { const getter = resolveSourceValueGetter(source); const options = typeof setter === "object" ? setter : debugOptions; return isFunction(setter) ? vue.computed( { get: getter, set: setter }, options ) : vue.computed(getter, options); } function useEffect(setup, dependency, options) { const control = createManualEffect(); if (isValidDependency(dependency)) { return vue.watch( dependency, (dependency2, lastDependency, onCleanup) => { control.reset((onCleanup2) => setup(onCleanup2, dependency2, lastDependency)); onCleanup(control.clear); }, options ); } return vue.watchEffect( (onCleanup) => { control.reset((onCleanup2) => setup(onCleanup2)); onCleanup(control.clear); }, { ...options, immediate: void 0 } ); } function useMemo(source, dependency, options) { const stateRef = vue.ref(); const getter = resolveSourceValueGetter(source); useEffect( (_, dependency2, lastDependency) => { const currentState = getter(dependency2, lastDependency); if (!Object.is(stateRef.value, currentState)) { stateRef.value = currentState; } }, dependency, { ...options, immediate: true } ); return useComputed(stateRef); } function useTransformState(source, transform) { const getter = resolveSourceValueGetter(source); return vue.computed(() => transform(getter())); } function useDerivedState(props, getDerivedStateFromProps) { let prevState; return useMemo( useTransformState(props, (props2) => prevState = getDerivedStateFromProps(props2, prevState)) ); } function useFollowState(initialValue, target, options) { const stateRef = isWritableRef(initialValue) ? initialValue : vue.ref(vue.unref(initialValue)); const stopFollow = useEffect( (_, target2) => { stateRef.value = target2; options?.onFollow?.(); }, target, options ); return [stateRef, stopFollow]; } function useForceUpdate() { const signal = vue.ref(0); return [ () => signal.value, () => { signal.value++; } ]; } function useMergedState(source, defaultValue) { const getValue = resolveSourceValueGetter(source); const getDefaultValue = resolveSourceValueGetter(defaultValue); const getter = () => { const value = getValue(); return value === void 0 ? getDefaultValue() : value; }; return vue.computed(getter); } function useState(initialValue, shallow) { const createRef = shallow ? vue.shallowRef : vue.ref; const state = createRef(resolveSourceValue(initialValue)); return [ state, (value) => { state.value = value; } ]; } function useToggle(defaultValue = false, reverseValue) { const asBoolean = arguments.length <= 1; if (asBoolean && reverseValue === void 0) { reverseValue = !resolveSourceValue(defaultValue); } const transform = asBoolean ? (value) => Boolean(value) : (value) => value; const defaultValueRef = useTransformState(defaultValue, transform); const reverseValueRef = useTransformState(reverseValue, transform); const stateRef = vue.ref(defaultValueRef.value); return [stateRef, createToggleControl(stateRef, defaultValueRef, reverseValueRef)]; } exports.batch = batch; exports.createManualEffect = createManualEffect; exports.createToggleControl = createToggleControl; exports.isValidDependency = isValidDependency; exports.isWritableRef = isWritableRef; exports.resolveComputed = resolveComputed; exports.resolveSourceValue = resolveSourceValue; exports.resolveSourceValueGetter = resolveSourceValueGetter; exports.untrack = untrack; exports.useBoolean = useBoolean; exports.useComputed = useComputed; exports.useDerivedState = useDerivedState; exports.useEffect = useEffect; exports.useFollowState = useFollowState; exports.useForceUpdate = useForceUpdate; exports.useMemo = useMemo; exports.useMergedState = useMergedState; exports.useState = useState; exports.useToggle = useToggle; exports.useTransformState = useTransformState;