UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

119 lines (118 loc) 4.34 kB
"use client"; import { useCallback, useContext, useMemo, useRef, useSyncExternalStore } from 'react'; import pointer, { isPath } from "../utils/json-pointer/index.js"; import DataContextRefContext from "../DataContext/DataContextRefContext.js"; import IterateItemContext from "../Iterate/IterateItemContext.js"; import usePath from "./usePath.js"; export default function useDataValue(pathProp, value, options = {}) { const providedDataContextRef = useContext(DataContextRefContext); const fallbackDataContextRef = useRef(undefined); const dataContextRef = providedDataContextRef !== null && providedDataContextRef !== void 0 ? providedDataContextRef : fallbackDataContextRef; const iterateItemContext = useContext(IterateItemContext); const snapshotVersionRef = useRef(0); const { pathType = 'auto' } = options; const { makePath, makeIteratePath } = usePath(); const resolvePath = useCallback(path => { if (pathType === 'absolute') { return makePath(path); } if (pathType === 'iterate') { return makeIteratePath(path); } if (iterateItemContext) { if (path.startsWith('//')) { return makePath(path); } const currentItemPath = makeIteratePath('/'); if (path === currentItemPath || path.startsWith(`${currentItemPath}/`)) { return path; } return makeIteratePath(path); } return makePath(path); }, [iterateItemContext, makeIteratePath, makePath, pathType]); const subscribablePaths = useMemo(() => { if (!pathProp) { return undefined; } const paths = Array.isArray(pathProp) ? pathProp : [pathProp]; const normalizedPaths = paths.filter(isPath).map(path => resolvePath(path)); return normalizedPaths.length > 0 ? normalizedPaths : undefined; }, [pathProp, resolvePath]); const subscribablePath = typeof pathProp === 'string' && subscribablePaths?.length === 1 ? subscribablePaths[0] : undefined; const subscribe = useCallback(callback => { if (subscribablePaths?.length && dataContextRef.current?.subscribeDataValue) { const handleUpdate = () => { snapshotVersionRef.current += 1; callback(); }; const unsubscribers = subscribablePaths.map(path => dataContextRef.current.subscribeDataValue(path, handleUpdate)); return () => { unsubscribers.forEach(unsubscribe => unsubscribe()); }; } return () => undefined; }, [dataContextRef, subscribablePaths]); const getSnapshot = useCallback(() => { if (subscribablePath) { return dataContextRef.current?.getDataValue?.(subscribablePath); } return snapshotVersionRef.current; }, [dataContextRef, subscribablePath]); const subscribedValue = useSyncExternalStore(subscribe, getSnapshot, getSnapshot); const get = useCallback((selector, data = dataContextRef.current?.internalDataRef?.current) => { if (selector === '/') { return data; } return pointer.has(data, selector) ? pointer.get(data, selector) : undefined; }, [dataContextRef]); const getValueByPath = useCallback((path, data = undefined) => { if (isPath(path)) { return get(makePath(path), data); } }, [get, makePath]); const getValueByIteratePath = useCallback(path => { if (isPath(path)) { return get(makeIteratePath(path)); } }, [get, makeIteratePath]); const moveValueToPath = useCallback((path, value, object = {}) => { if (path !== '/' && isPath(path)) { pointer.set(object, path, value); return object; } return value; }, []); const getData = useCallback((path, options) => { if (isPath(path)) { const value = getValueByPath(path); if (options?.includeCurrentPath && path !== '/') { return moveValueToPath(path, value); } return value; } }, [getValueByPath, moveValueToPath]); const getSourceValue = useCallback(source => { if (typeof source === 'string' && isPath(source)) { return get(resolvePath(source)); } return source; }, [get, resolvePath]); if (typeof pathProp === 'string') { value = subscribablePath ? subscribedValue : getSourceValue(pathProp); } return { getSourceValue, getValueByPath, getValueByIteratePath, moveValueToPath, getData, value }; } //# sourceMappingURL=useDataValue.js.map