UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

198 lines (197 loc) 6.22 kB
"use client"; import { useRef, useCallback, useMemo } from 'react'; import { isAsync } from "../../../shared/helpers/isAsync.js"; export default function useFieldAsync({ onChange, onChangeContext, valueRef, forceUpdate, persistErrorState, revealError, setFieldState, hasError, warningRef, infoRef, fieldStateRef, removeErrorRef, hasPath, identifier, executeOnChangeRegardlessOfError, handlePathChangeDataContext }) { const asyncBehaviorIsEnabled = useMemo(() => { return isAsync(onChange) || isAsync(onChangeContext); }, [onChangeContext, onChange]); const validatedValueRef = useRef(undefined); const changeEventResultRef = useRef(null); const asyncProcessRef = useRef(null); const defineAsyncProcess = useCallback(name => { asyncProcessRef.current = name; }, []); const asyncBufferRef = useRef({}); for (const key in asyncBufferRef.current) { const { resolve, validateProcesses } = asyncBufferRef.current[key] || {}; if ((validateProcesses === null || validateProcesses === void 0 ? void 0 : validateProcesses()) === false) { delete asyncBufferRef.current[key]; if (typeof resolve === 'function') { window.requestAnimationFrame(resolve); } } } const eventPool = useRef({ onChangeValidator: null, onBlurValidator: null, onChangeContext: null, onChangeLocal: null }); const addToPool = useCallback((name, fn, runAsync) => { if (!eventPool.current[name]) { eventPool.current[name] = { fn, runAsync }; } }, []); const runPool = useCallback(async (cb = null) => { for (const key in eventPool.current) { if (!eventPool.current[key]) { continue; } const { fn, runAsync } = eventPool.current[key] || {}; if (fn) { eventPool.current[key] = null; if (runAsync) { await fn(); } else { fn(); } } } cb === null || cb === void 0 || cb(); }, []); const yieldAsyncProcess = useCallback(async ({ name, waitFor }) => { return new Promise(resolve => { const validateProcesses = () => { const result = waitFor.some(({ processName, withStates, hasValue }) => { const hasMatchingValue = hasValue === validatedValueRef.current; const result = (typeof hasValue === 'undefined' ? false : !hasMatchingValue) || (processName ? processName === asyncProcessRef.current : true) && (withStates === null || withStates === void 0 ? void 0 : withStates.some(state => { return state === fieldStateRef.current; })); return result; }); return result; }; if (validateProcesses() === true) { asyncBufferRef.current[name] = { resolve, validateProcesses }; } else { resolve(); setFieldState('pending'); } }); }, [setFieldState, fieldStateRef]); const handleChangeEventResult = useCallback(async () => { const result = changeEventResultRef.current || {}; if ('error' in result) { if (!result.error) { removeErrorRef.current(); } else { persistErrorState('gracefully', 'onChangeValidator', result.error); revealError(); } } if ('warning' in result) { warningRef.current = result.warning; } if ('info' in result) { infoRef.current = result.info; } if (asyncBehaviorIsEnabled) { await yieldAsyncProcess({ name: 'onSubmitContext', waitFor: [{ withStates: ['validating'] }] }); } defineAsyncProcess(undefined); if ((result === null || result === void 0 ? void 0 : result.success) === 'saved') { setFieldState('success'); } else if (result !== null && result !== void 0 && result.error) { setFieldState('error'); } else if (asyncBehaviorIsEnabled) { setFieldState('complete'); } forceUpdate(); }, [asyncBehaviorIsEnabled, defineAsyncProcess, removeErrorRef, persistErrorState, revealError, yieldAsyncProcess, setFieldState, warningRef, infoRef, forceUpdate]); const setEventResult = useCallback(async result => { if (result instanceof Error) { result = { error: result }; } changeEventResultRef.current = { ...changeEventResultRef.current, ...result }; await handleChangeEventResult(); }, [handleChangeEventResult]); const callOnChangeContext = useCallback(async () => { if (asyncBehaviorIsEnabled && !executeOnChangeRegardlessOfError) { await yieldAsyncProcess({ name: 'onChangeContext', waitFor: [{ processName: 'onChangeValidator', withStates: ['validating', 'error'], hasValue: valueRef.current }, { processName: 'onBlurValidator', withStates: ['validating', 'error'], hasValue: valueRef.current }] }); } if (hasPath) { if (isAsync(onChangeContext)) { defineAsyncProcess('onChangeContext'); if (!hasError() || executeOnChangeRegardlessOfError) { await setEventResult(await (handlePathChangeDataContext === null || handlePathChangeDataContext === void 0 ? void 0 : handlePathChangeDataContext(identifier))); } else { await setEventResult(null); } } else if (onChangeContext || !asyncBehaviorIsEnabled) { setEventResult(handlePathChangeDataContext === null || handlePathChangeDataContext === void 0 ? void 0 : handlePathChangeDataContext(identifier)); } } forceUpdate(); }, [asyncBehaviorIsEnabled, executeOnChangeRegardlessOfError, hasPath, yieldAsyncProcess, onChangeContext, defineAsyncProcess, hasError, setEventResult, handlePathChangeDataContext, identifier, forceUpdate, valueRef]); return { asyncBehaviorIsEnabled, defineAsyncProcess, addToPool, runPool, yieldAsyncProcess, handleChangeEventResult, setEventResult, callOnChangeContext, asyncProcessRef, validatedValueRef, changeEventResultRef }; } //# sourceMappingURL=useFieldAsync.js.map