UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

1,224 lines (1,223 loc) 46.8 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.clearedData = void 0; exports.default = Provider; var _parse = _interopRequireDefault(require("core-js-pure/stable/json/parse.js")); var _push = _interopRequireDefault(require("core-js-pure/stable/instance/push.js")); var _react = _interopRequireWildcard(require("react")); var _index = _interopRequireDefault(require("../../utils/json-pointer/index.js")); var _index2 = require("../../utils/index.js"); var _helpers = require("../../../../shared/helpers.js"); var _index3 = _interopRequireDefault(require("../../Field/Provider/index.js")); var _useUpdateEffect = _interopRequireDefault(require("../../../../shared/helpers/useUpdateEffect.js")); var _GlobalStatusProvider = _interopRequireDefault(require("../../../../components/global-status/GlobalStatusProvider.js")); var _isAsync = require("../../../../shared/helpers/isAsync.js"); var _useSharedState = require("../../../../shared/helpers/useSharedState.js"); var _Context = _interopRequireDefault(require("../../../../shared/Context.js")); var _useTranslation = _interopRequireDefault(require("../../hooks/useTranslation.js")); var _usePath = require("../../hooks/usePath.js"); var _Context2 = _interopRequireDefault(require("../Context.js")); var _structuredClone = require("../../../../shared/helpers/structuredClone.js"); var _useIsomorphicLayoutEffect = require("../../../../shared/helpers/useIsomorphicLayoutEffect.js"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const isArrayJsonPointer = /^\/\d+(\/|$)/; function Provider(props) { var _sharedAttachments$da, _translations$resolve; const [, forceUpdate] = (0, _react.useReducer)(() => ({}), {}); const { id, globalStatusId = 'main', defaultData, emptyData, data, schema, onChange, onPathChange, onSubmit, onSubmitRequest, onSubmitComplete, onCommit, onClear, onUpdateDataValue, scrollTopOnSubmit, minimumAsyncBehaviorTime, asyncSubmitTimeout, sessionStorageId, ajvInstance, transformIn, transformOut, filterSubmitData, countryCode, locale, translations, required, errorMessages, isolate, children, ...rest } = props; if (data !== undefined && sessionStorageId !== undefined) { throw new Error('Use "defaultData" instead of "data" when using sessionStorageId'); } const { hasContext } = (0, _react.useContext)(_Context2.default) || {}; if (hasContext && !isolate) { throw new Error('DataContext (Form.Handler) cannot be nested'); } const formElementRef = (0, _react.useRef)(null); const { locale: sharedLocale } = (0, _react.useContext)(_Context.default) || {}; const translation = (0, _useTranslation.default)().Field; const ajvRef = (0, _react.useRef)(); const getAjvInstance = (0, _react.useCallback)((instance = ajvInstance) => { if (!ajvRef.current) { ajvRef.current = (0, _index2.makeAjvInstance)(instance); } return ajvRef.current; }, [ajvInstance]); (0, _react.useEffect)(() => { if (schema && !(0, _index2.isZodSchema)(schema) && !ajvInstance) { (0, _helpers.warn)('Form.Handler received a JSON Schema but no ajvInstance. Provide ajvInstance={makeAjvInstance()} to enable schema validation.'); } }, [schema, ajvInstance]); const mountedFieldsRef = (0, _react.useRef)(new Map()); const snapshotsRef = (0, _react.useRef)(new Map()); const existingFieldsRef = (0, _react.useRef)(new Map()); const hasVisibleErrorRef = (0, _react.useRef)(new Map()); const errorsRef = (0, _react.useRef)(); const addSetShowAllErrorsRef = (0, _react.useRef)([]); const showAllErrorsRef = (0, _react.useRef)(false); const setShowAllErrors = (0, _react.useCallback)(showAllErrors => { showAllErrorsRef.current = showAllErrors ? Date.now() : showAllErrors; forceUpdate(); addSetShowAllErrorsRef.current.forEach(fn => fn === null || fn === void 0 ? void 0 : fn(showAllErrors)); }, []); const executeSectionValidators = (0, _react.useCallback)(contextErrors => { if (!sectionSchemasRef.current.size) { const hasContextErrors = contextErrors && Object.keys(contextErrors).length > 0; errorsRef.current = hasContextErrors ? contextErrors : undefined; return errorsRef.current; } const sectionErrors = {}; sectionSchemasRef.current.forEach(({ path, schema, validator }) => { if (!validator) { return; } const normalizedPath = path || '/'; const sectionData = normalizedPath === '/' ? internalDataRef.current : _index.default.has(internalDataRef.current, normalizedPath) ? _index.default.get(internalDataRef.current, normalizedPath) : undefined; const validationResult = validator(sectionData); if (validationResult === true) { return; } let errors = {}; if ((0, _index2.isZodSchema)(schema)) { const issues = validator.errors; if (issues !== null && issues !== void 0 && issues.length) { errors = (0, _index2.zodErrorsToFormErrors)(issues); } } else { const ajvValidator = validator; const ajvErrors = ajvValidator.errors; if (ajvErrors && ajvErrors.length) { errors = (0, _index2.ajvErrorsToFormErrors)(ajvErrors, sectionData); } } Object.entries(errors).forEach(([errorPath, error]) => { const combinedPath = (0, _usePath.appendPath)(normalizedPath, errorPath); sectionErrors[combinedPath] = error; }); }); const hasSectionErrors = Object.keys(sectionErrors).length > 0; const hasContextErrors = contextErrors && Object.keys(contextErrors).length > 0; if (!hasSectionErrors && !hasContextErrors) { errorsRef.current = undefined; return undefined; } errorsRef.current = { ...(contextErrors !== null && contextErrors !== void 0 ? contextErrors : {}), ...(hasSectionErrors ? sectionErrors : {}) }; return errorsRef.current; }, []); const revealError = (0, _react.useCallback)((path, hasError) => { if (hasError) { hasVisibleErrorRef.current.set(path, hasError); } else { hasVisibleErrorRef.current.delete(path); } forceUpdate(); }, []); const submitStateRef = (0, _react.useRef)({}); const setSubmitState = (0, _react.useCallback)(state => { submitStateRef.current = { ...submitStateRef.current, ...state }; forceUpdate(); }, []); const formStateRef = (0, _react.useRef)(); const activeSubmitButtonIdRef = (0, _react.useRef)(); const keepPending = (0, _react.useRef)(false); const setFormState = (0, _react.useCallback)((formState, options = {}) => { if (typeof (options === null || options === void 0 ? void 0 : options.keepPending) === 'boolean') { keepPending.current = options === null || options === void 0 ? void 0 : options.keepPending; } formStateRef.current = formState; forceUpdate(); }, []); const setActiveSubmitButtonId = (0, _react.useCallback)(id => { activeSubmitButtonIdRef.current = id; forceUpdate(); }, []); const fieldErrorRef = (0, _react.useRef)({}); const fieldStateRef = (0, _react.useRef)({}); const validationVersionRef = (0, _react.useRef)(0); const bumpValidationVersionRef = (0, _react.useRef)(() => null); const initialData = (0, _react.useMemo)(() => { if (sessionStorageId && typeof window !== 'undefined') { var _window$sessionStorag; const sessionDataJSON = (_window$sessionStorag = window.sessionStorage) === null || _window$sessionStorag === void 0 ? void 0 : _window$sessionStorag.getItem(sessionStorageId); if (sessionDataJSON) { try { return (0, _parse.default)(sessionDataJSON); } catch (e) { var _window$sessionStorag2; (_window$sessionStorag2 = window.sessionStorage) === null || _window$sessionStorag2 === void 0 || _window$sessionStorag2.removeItem(sessionStorageId); } } } return data !== null && data !== void 0 ? data : defaultData; }, []); const internalDataRef = (0, _react.useRef)(initialData); const isEmptyDataRef = (0, _react.useRef)(false); const ajvValidatorRef = (0, _react.useRef)(); const sectionSchemasRef = (0, _react.useRef)(new Map()); const sectionSchemaPathsRef = (0, _react.useRef)(new Set()); const createUnifiedValidator = (0, _react.useCallback)(schema => { if ((0, _index2.isZodSchema)(schema)) { const zodValidator = (0, _index2.createZodValidator)(schema); const unifiedValidator = value => { const result = zodValidator(value); if (result === true) { return true; } else { unifiedValidator.errors = result.issues; return false; } }; return unifiedValidator; } else { var _getAjvInstance; return (_getAjvInstance = getAjvInstance()) === null || _getAjvInstance === void 0 ? void 0 : _getAjvInstance.compile(schema); } }, []); (0, _react.useMemo)(() => { if (schema) { ajvValidatorRef.current = createUnifiedValidator(schema); } }, [schema, createUnifiedValidator]); const executeAjvValidator = (0, _react.useCallback)(() => { if (!ajvValidatorRef.current) { errorsRef.current = undefined; return undefined; } const validationResult = ajvValidatorRef.current(internalDataRef.current); if (!validationResult) { const errors = ajvValidatorRef.current.errors; if (errors && Array.isArray(errors)) { if (errors.length > 0 && errors[0] && typeof errors[0] === 'object' && 'code' in errors[0]) { errorsRef.current = (0, _index2.zodErrorsToFormErrors)(errors); } else { errorsRef.current = (0, _index2.ajvErrorsToFormErrors)(errors, internalDataRef.current); } return errorsRef.current; } errorsRef.current = undefined; return undefined; } errorsRef.current = undefined; return undefined; }, []); const validateData = (0, _react.useCallback)(() => { const contextErrors = executeAjvValidator(); executeSectionValidators(contextErrors); forceUpdate(); }, [executeAjvValidator, executeSectionValidators, forceUpdate]); const checkFieldStateFor = (0, _react.useCallback)((path, state) => { var _errorsRef$current; return Boolean(state === 'error' ? ((_errorsRef$current = errorsRef.current) === null || _errorsRef$current === void 0 ? void 0 : _errorsRef$current[path]) instanceof Error || fieldErrorRef.current[path] instanceof Error : fieldStateRef.current[path] === state); }, []); const hasFieldState = (0, _react.useCallback)(state => { return Array.from(mountedFieldsRef.current.entries()).some(([path, item]) => { return item.isMounted && checkFieldStateFor(path, state); }); }, [checkFieldStateFor]); const hasFieldError = (0, _react.useCallback)(path => { return Array.from(mountedFieldsRef.current.entries()).some(([p, item]) => { return item.isMounted && p === path && checkFieldStateFor(path, 'error'); }); }, [checkFieldStateFor]); const hasErrors = (0, _react.useCallback)(() => { return hasFieldState('error'); }, [hasFieldState]); const setFieldError = (0, _react.useCallback)((path, error) => { if (error) { fieldErrorRef.current[path] = error; } else { delete fieldErrorRef.current[path]; } bumpValidationVersionRef.current(); for (const item of fieldEventListenersRef.current) { const { type, callback } = item; if (type === 'onSetFieldError') { callback(); } } }, []); const setFieldState = (0, _react.useCallback)((path, fieldState) => { if (fieldState !== fieldStateRef.current[path]) { fieldStateRef.current[path] = fieldState; forceUpdate(); bumpValidationVersionRef.current(); } }, []); const getDataPathHandlerParameters = (0, _react.useCallback)((path, data = internalDataRef.current) => { var _fieldInternalsRef$cu; const value = _index.default.has(data, path) ? _index.default.get(data, path) : undefined; const { value: displayValue } = fieldDisplayValueRef.current[path] || {}; const props = ((_fieldInternalsRef$cu = fieldInternalsRef.current[path]) === null || _fieldInternalsRef$cu === void 0 ? void 0 : _fieldInternalsRef$cu.props) || {}; const label = props === null || props === void 0 ? void 0 : props['label']; const error = fieldErrorRef.current[path]; return { path, value, displayValue, label, props, data: internalDataRef.current, error, internal: { error } }; }, []); const mutateDataHandler = (0, _react.useCallback)((data, handler, { remove = false, mutate = true, fireHandlerWhen = null } = {}) => { const freshData = {}; const mutateEntry = (path, result) => { if (remove) { if (result === false) { data = (0, _structuredClone.structuredClone)(data); _index.default.remove(data, path); } } else { if (typeof result !== 'undefined') { if (mutate) { data = (0, _structuredClone.structuredClone)(data); _index.default.set(data, path, result); } else { _index.default.set(freshData, path, result); } } } }; if (typeof handler === 'function') { const run = path => { const { type } = fieldDisplayValueRef.current[path] || {}; if ((fireHandlerWhen === null || fireHandlerWhen === void 0 ? void 0 : fireHandlerWhen({ type })) !== false) { const result = handler(getDataPathHandlerParameters(path, data)); mutateEntry(path, result); } }; for (const path in fieldInternalsRef.current) { const exists = _index.default.has(data, path); if (exists) { run(path); } } _index.default.walk(internalDataRef.current, (value, path) => { if (fieldInternalsRef.current[path] === undefined) { run(path); } }); if (!mutate) { return freshData; } return data; } else if (handler) { const runFilter = ({ path, condition }) => { const exists = _index.default.has(data, path); if (exists) { const result = typeof condition === 'function' ? condition(getDataPathHandlerParameters(path, data)) : condition; mutateEntry(path, result); } }; const wildcardPaths = []; Object.entries(handler).forEach(([path, condition]) => { if (path.includes('*')) { const parts = path.split(/\/\*/g); const exists = _index.default.has(data, parts[0]); if (exists) { const traverse = (subData, subPath, idx) => { if (idx === parts.length - 1) { (0, _push.default)(wildcardPaths).call(wildcardPaths, { path: subPath, condition }); return; } const list = _index.default.get(subData, subPath); if (Array.isArray(list)) { list.forEach((_, i) => { traverse(list[i], `${subPath}/${i}${parts[idx + 1]}`, idx + 1); }); } }; traverse(data, parts[0], 0); } } else { runFilter({ path, condition }); } }); wildcardPaths.forEach(runFilter); return data; } return data; }, [getDataPathHandlerParameters]); const visibleDataHandler = (0, _react.useCallback)((data = internalDataRef.current, { keepPaths, removePaths } = {}) => { const visibleData = {}; mountedFieldsRef.current.forEach((item, path) => { if (item && item.isVisible !== false && (item.isPreMounted !== false || item.wasStepChange === true) && (removePaths ? !removePaths.includes(path) : true) && _index.default.has(data, path)) { _index.default.set(visibleData, path, _index.default.get(data, path)); } }); if (keepPaths) { keepPaths.forEach(path => { if (_index.default.has(data, path)) { _index.default.set(visibleData, path, _index.default.get(data, path)); } }); } return visibleData; }, []); const filterDataHandler = (0, _react.useCallback)((data, filter) => { if (filter) { return mutateDataHandler(data, filter, { remove: true }); } return data; }, [mutateDataHandler]); const filterData = (0, _react.useCallback)((filter, data = internalDataRef.current) => { return filterDataHandler(data, filter); }, [filterDataHandler]); const fieldDisplayValueRef = (0, _react.useRef)({}); const fieldConnectionsRef = (0, _react.useRef)({}); const fieldStatusRef = (0, _react.useRef)({}); const setFieldConnection = (0, _react.useCallback)((path, connections) => { fieldConnectionsRef.current[path] = connections; }, []); const fieldInternalsRef = (0, _react.useRef)({}); const setFieldInternals = (0, _react.useCallback)((path, internals) => { fieldInternalsRef.current[path] = Object.assign(fieldInternalsRef.current[path] || {}, internals); }, []); const valueInternalsRef = (0, _react.useRef)({}); const setValueInternals = (0, _react.useCallback)((path, props) => { valueInternalsRef.current[path] = Object.assign(valueInternalsRef.current[path] || {}, { props }); }, []); const hasFieldWithAsyncValidator = (0, _react.useCallback)(() => { for (const path in fieldInternalsRef.current) { const fieldInternals = fieldInternalsRef.current[path] || {}; const { enableAsyncMode, props } = fieldInternals; if (enableAsyncMode || (0, _isAsync.isAsync)(props === null || props === void 0 ? void 0 : props.onChangeValidator) || (0, _isAsync.isAsync)(props === null || props === void 0 ? void 0 : props.onBlurValidator)) { return true; } } return false; }, []); const sharedData = (0, _useSharedState.useSharedState)(id); const sharedAttachments = (0, _useSharedState.useSharedState)(id ? (0, _useSharedState.createReferenceKey)(id, 'attachments') : undefined); const sharedDataContext = (0, _useSharedState.useSharedState)(id ? (0, _useSharedState.createReferenceKey)(id, 'data-context') : undefined); const setSharedData = sharedData.set; const extendSharedData = sharedData.extend; const extendAttachment = sharedAttachments.extend; const rerenderUseDataHook = (_sharedAttachments$da = sharedAttachments.data) === null || _sharedAttachments$da === void 0 ? void 0 : _sharedAttachments$da.rerenderUseDataHook; bumpValidationVersionRef.current = () => { if (id) { validationVersionRef.current += 1; extendAttachment({ validationVersion: validationVersionRef.current }, { preventSyncOfSameInstance: true }); } }; const hasHydratedFieldErrorRef = (0, _react.useRef)(false); if (!hasHydratedFieldErrorRef.current) { var _sharedAttachments$da2; const sharedFieldErrorRef = (_sharedAttachments$da2 = sharedAttachments.data) === null || _sharedAttachments$da2 === void 0 ? void 0 : _sharedAttachments$da2.fieldErrorRef; if (sharedFieldErrorRef !== null && sharedFieldErrorRef !== void 0 && sharedFieldErrorRef.current) { fieldErrorRef.current = sharedFieldErrorRef.current; hasHydratedFieldErrorRef.current = true; } } const cacheRef = (0, _react.useRef)({ data, schema, shared: sharedData.data, hasUsedInitialData: false }); const internalData = (0, _react.useMemo)(() => { if (id && initialData && !sharedData.data) { sharedData.update(initialData); } if (id && initialData && sharedData.data && cacheRef.current.shared === sharedData.data && internalDataRef.current === initialData && typeof internalDataRef.current === 'object') { return { ...internalDataRef.current, ...(sharedData.data || {}) }; } if (id && !initialData && !internalDataRef.current && sharedData.data && cacheRef.current.shared === sharedData.data) { return sharedData.data; } if (id && sharedData.data && cacheRef.current.shared !== sharedData.data && sharedData.data !== internalDataRef.current && typeof internalDataRef.current === 'object') { cacheRef.current.shared = sharedData.data; if (isEmptyDataRef.current) { return Array.isArray(internalDataRef.current) ? [] : clearedData; } return { ...internalDataRef.current, ...(sharedData.data || {}) }; } if (data !== cacheRef.current.data) { cacheRef.current.data = data; return data; } return internalDataRef.current; }, [id, initialData, sharedData, data]); internalDataRef.current = props.path && _index.default.has(internalData, props.path) ? _index.default.get(internalData, props.path) : internalData; const clearData = (0, _react.useCallback)(() => { var _ref, _requestAnimationFram; isEmptyDataRef.current = true; internalDataRef.current = (_ref = typeof emptyData === 'function' ? emptyData(internalDataRef.current) : emptyData) !== null && _ref !== void 0 ? _ref : Array.isArray(internalDataRef.current) ? [] : clearedData; if (id) { setSharedData(internalDataRef.current); } forceUpdate(); onClear === null || onClear === void 0 || onClear(); (_requestAnimationFram = requestAnimationFrame) === null || _requestAnimationFram === void 0 || _requestAnimationFram(() => { isEmptyDataRef.current = false; }); }, [emptyData, id, onClear, setSharedData]); (0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(() => { const hasNoErrors = errorsRef.current === undefined; const contextErrors = executeAjvValidator(); executeSectionValidators(contextErrors); if (hasNoErrors && errorsRef.current !== undefined) { forceUpdate(); } }, [internalDataRef.current, executeAjvValidator, executeSectionValidators]); const registerSectionSchema = (0, _react.useCallback)(registration => { const normalizedPath = registration.path && registration.path !== '/' ? registration.path : '/'; const validator = createUnifiedValidator(registration.schema); sectionSchemasRef.current.set(registration.id, { path: normalizedPath, schema: registration.schema, validator }); sectionSchemaPathsRef.current.add(normalizedPath); validateData(); return () => { const entry = sectionSchemasRef.current.get(registration.id); if (!entry) { return; } sectionSchemasRef.current.delete(registration.id); const stillUsesPath = Array.from(sectionSchemasRef.current.values()).some(item => item.path === entry.path); if (!stillUsesPath) { sectionSchemaPathsRef.current.delete(entry.path); } validateData(); }; }, [createUnifiedValidator, validateData]); const storeInSession = (0, _react.useMemo)(() => { return (0, _helpers.debounce)(() => { var _window$sessionStorag3; (_window$sessionStorag3 = window.sessionStorage) === null || _window$sessionStorag3 === void 0 || _window$sessionStorag3.setItem(sessionStorageId, JSON.stringify(internalDataRef.current)); }, process.env.NODE_ENV === 'test' ? 1 : 800); }, [sessionStorageId]); const setData = (0, _react.useCallback)((newData, { preventUpdate = false } = {}) => { if (transformIn) { newData = mutateDataHandler(newData, transformIn); } internalDataRef.current = newData; if (id) { extendSharedData(newData, { preventSyncOfSameInstance: true }); if (filterSubmitData) { rerenderUseDataHook === null || rerenderUseDataHook === void 0 || rerenderUseDataHook(); } } if (sessionStorageId && typeof window !== 'undefined') { storeInSession(); } if (!preventUpdate) { forceUpdate(); } }, [extendSharedData, filterSubmitData, id, mutateDataHandler, rerenderUseDataHook, sessionStorageId, storeInSession, transformIn]); const updateDataValue = (0, _react.useCallback)((path, value, { preventUpdate } = {}) => { var _internalDataRef$curr; if (!path) { return; } const givenData = path === '/' ? value : (_internalDataRef$curr = internalDataRef.current) !== null && _internalDataRef$curr !== void 0 ? _internalDataRef$curr : path.match(isArrayJsonPointer) ? [] : {}; let newData = null; try { newData = (0, _structuredClone.structuredClone)(givenData); } catch (e) { newData = givenData; } if (path !== '/') { _index.default.set(newData, path, value); } setData(newData, { preventUpdate }); onUpdateDataValue === null || onUpdateDataValue === void 0 || onUpdateDataValue(path, value, { preventUpdate }); }, [onUpdateDataValue, setData]); const handlePathChangeUnvalidated = (0, _react.useCallback)(async (path, value) => { if (!path) { return null; } updateDataValue(path, value); if ((0, _isAsync.isAsync)(onPathChange)) { await (onPathChange === null || onPathChange === void 0 ? void 0 : onPathChange(path, value)); } else { onPathChange === null || onPathChange === void 0 || onPathChange(path, value); } for (const itm of fieldEventListenersRef.current) { if (itm.type === 'onPathChange' && itm.path === path) { const { callback } = itm; if ((0, _isAsync.isAsync)(callback)) { await callback({ value }); } else { callback({ value }); } } } }, [onPathChange, updateDataValue]); const handlePathChange = (0, _react.useCallback)(async (path, value = '_undefined_') => { if (!path) { return null; } if (value !== '_undefined_') { handlePathChangeUnvalidated(path, value); } showAllErrorsRef.current = false; validateData(); const data = internalDataRef.current; const options = { filterData }; const transformedData = transformOut ? mutateDataHandler(data, transformOut) : data; for (const cb of changeHandlerStackRef.current) { if ((0, _isAsync.isAsync)(onChange)) { await cb(transformedData, options); } else { cb(transformedData, options); } } if ((0, _isAsync.isAsync)(onChange)) { return await onChange(transformedData, options); } return onChange === null || onChange === void 0 ? void 0 : onChange(transformedData, options); }, [filterData, handlePathChangeUnvalidated, mutateDataHandler, onChange, transformOut, validateData]); const changeHandlerStackRef = (0, _react.useRef)([]); const addOnChangeHandler = (0, _react.useCallback)(callback => { const exists = changeHandlerStackRef.current.some(cb => { return callback === cb; }); if (!exists) { var _context; (0, _push.default)(_context = changeHandlerStackRef.current).call(_context, callback); } }, []); const setMountedFieldState = (0, _react.useCallback)((path, state) => { const currentState = mountedFieldsRef.current.get(path) || {}; mountedFieldsRef.current.set(path, { ...currentState, ...state }); const hasChanges = Object.keys(state).some(key => { return currentState[key] !== state[key]; }); if (hasChanges) { Promise.resolve().then(() => { bumpValidationVersionRef.current(); }); } for (const itm of fieldEventListenersRef.current) { if (itm.type === 'onMount' && itm.path === path) { const { callback } = itm; callback(); } } }, []); const scrollToTop = (0, _react.useCallback)(() => { if (typeof window !== 'undefined') { var _window, _window$scrollTo; (_window = window) === null || _window === void 0 || (_window$scrollTo = _window.scrollTo) === null || _window$scrollTo === void 0 || _window$scrollTo.call(_window, { top: 0, behavior: 'smooth' }); } }, []); const resolveStateResult = (0, _react.useCallback)(async fn => { try { const result = await fn(); if (result instanceof Error) { throw result; } return result; } catch (error) { return { error: error }; } }, []); const applySubmitState = (0, _react.useCallback)(result => { if (result !== null && result !== void 0 && result.error || result !== null && result !== void 0 && result.warning || result !== null && result !== void 0 && result.info || result !== null && result !== void 0 && result.customStatus) { setSubmitState(result); } }, [setSubmitState]); const handleSubmitCall = (0, _react.useCallback)(async args => { const { onSubmit, enableAsyncBehavior, skipFieldValidation, skipErrorCheck } = args; setSubmitState({ error: undefined, warning: undefined, info: undefined, customStatus: undefined }); const asyncBehaviorIsEnabled = (skipErrorCheck ? enableAsyncBehavior : !hasErrors() || hasFieldState('pending')) && (enableAsyncBehavior || hasFieldWithAsyncValidator()); if (asyncBehaviorIsEnabled) { setFormState('pending'); } if (!skipFieldValidation) { for (const item of fieldEventListenersRef.current) { var _mountedFieldsRef$cur; const { path, type, callback } = item; if (type === 'onSubmitCall' && (_mountedFieldsRef$cur = mountedFieldsRef.current.get(path)) !== null && _mountedFieldsRef$cur !== void 0 && _mountedFieldsRef$cur.isMounted) { if (asyncBehaviorIsEnabled) { await callback(); } else { callback(); } } } } let result; if (!(skipErrorCheck ? false : hasErrors()) && !hasFieldState('pending') && (skipFieldValidation ? true : !hasFieldState('error'))) { var _result2; result = await resolveStateResult(async () => { if (isolate) { for (const item of fieldEventListenersRef.current) { const { type, callback } = item; if (type === 'onBeforeCommit') { callback(); } } const commitResult = await (onCommit === null || onCommit === void 0 ? void 0 : onCommit(internalDataRef.current, { clearData })); for (const item of fieldEventListenersRef.current) { const { type, callback } = item; if (type === 'onAfterCommit') { callback(); } } return commitResult; } else { return await onSubmit(); } }); if (asyncBehaviorIsEnabled) { var _result; if ((_result = result) !== null && _result !== void 0 && _result.error) { setFormState('abort'); } else if (keepPending.current !== true) { setFormState('complete'); } } if ((_result2 = result) !== null && _result2 !== void 0 && _result2['status']) { var _result3; setFormState((_result3 = result) === null || _result3 === void 0 ? void 0 : _result3['status']); } applySubmitState(result); } else { if (asyncBehaviorIsEnabled) { await new Promise(resolve => window.requestAnimationFrame(resolve)); setFormState(undefined); if (!skipFieldValidation) { onSubmitContinueRef.current = () => { window.requestAnimationFrame(() => { handleSubmitCall({ ...args, skipFieldValidation: true }); }); }; } } setShowAllErrors(true); const submitRequestResult = await resolveStateResult(() => onSubmitRequest === null || onSubmitRequest === void 0 ? void 0 : onSubmitRequest({ getErrors: () => Object.keys(fieldErrorRef.current).map(path => { return getDataPathHandlerParameters(path); }).filter(({ error }) => error) })); applySubmitState(submitRequestResult); if (submitRequestResult) { result = submitRequestResult; } for (const itm of fieldEventListenersRef.current) { if (itm.type === 'onSubmitRequest') { itm.callback(); } } } return result; }, [applySubmitState, clearData, getDataPathHandlerParameters, hasErrors, hasFieldState, hasFieldWithAsyncValidator, isolate, onCommit, onSubmitRequest, resolveStateResult, setFormState, setShowAllErrors]); const getSubmitData = (0, _react.useCallback)(() => { const data = internalDataRef.current; const mutatedData = transformOut ? mutateDataHandler(data, transformOut) : data; const filteredData = filterSubmitData ? filterDataHandler(mutatedData, filterSubmitData) : mutatedData; return filteredData; }, [filterDataHandler, filterSubmitData, mutateDataHandler, transformOut]); const getSubmitParams = (0, _react.useCallback)(() => { const reduceToVisibleFields = (data, options) => { return visibleDataHandler(transformOut ? mutateDataHandler(data, transformOut) : data, options); }; const transformData = (data, handler) => { return mutateDataHandler(data, handler, { mutate: false, fireHandlerWhen: ({ type }) => type === 'field' }); }; const formElement = formElementRef.current; const params = { filterData, reduceToVisibleFields, transformData, resetForm: () => { var _formElement$reset; formElement === null || formElement === void 0 || (_formElement$reset = formElement.reset) === null || _formElement$reset === void 0 || _formElement$reset.call(formElement); if (typeof window !== 'undefined') { if (sessionStorageId) { window.sessionStorage.removeItem(sessionStorageId); } } forceUpdate(); }, clearData }; return params; }, [clearData, filterData, mutateDataHandler, sessionStorageId, transformOut, visibleDataHandler]); const handleSubmit = (0, _react.useCallback)(async () => { for (const item of fieldEventListenersRef.current) { const { type, callback } = item; if (type === 'onBeforeSubmit') { callback(); } } return await handleSubmitCall({ enableAsyncBehavior: (0, _isAsync.isAsync)(onSubmit), onSubmit: async () => { let stop = false; const preventSubmit = () => stop = true; for (const item of fieldEventListenersRef.current) { const { type, callback } = item; if (type === 'onSubmit') { if ((0, _isAsync.isAsync)(callback)) { await callback({ preventSubmit }); } else { callback({ preventSubmit }); } } } if (stop) { return; } const data = getSubmitData(); const options = getSubmitParams(); let result = undefined; if ((0, _isAsync.isAsync)(onSubmit)) { result = await onSubmit(data, options); } else { result = onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit(data, options); } const completeResult = await (onSubmitComplete === null || onSubmitComplete === void 0 ? void 0 : onSubmitComplete(data, result)); if (completeResult) { result = Object.keys(result).length > 0 ? { ...result, ...completeResult } : completeResult; } if (scrollTopOnSubmit) { scrollToTop(); } return result; } }); }, [getSubmitData, getSubmitParams, handleSubmitCall, onSubmit, onSubmitComplete, scrollToTop, scrollTopOnSubmit]); const fieldEventListenersRef = (0, _react.useRef)([]); const setFieldEventListener = (0, _react.useCallback)((path, type, callback, { remove = false } = {}) => { fieldEventListenersRef.current = fieldEventListenersRef.current.filter(({ path: p, type: t, callback: c }) => { return !(p === path && t === type && c === callback); }); if (!remove) { var _context2; (0, _push.default)(_context2 = fieldEventListenersRef.current).call(_context2, { path, type, callback }); } }, []); const onSubmitContinueRef = (0, _react.useRef)(null); if (!hasFieldState('pending')) { var _onSubmitContinueRef$; (_onSubmitContinueRef$ = onSubmitContinueRef.current) === null || _onSubmitContinueRef$ === void 0 || _onSubmitContinueRef$.call(onSubmitContinueRef); onSubmitContinueRef.current = null; } (0, _useUpdateEffect.default)(() => { if (schema && schema !== cacheRef.current.schema) { cacheRef.current.schema = schema; ajvValidatorRef.current = createUnifiedValidator(schema); validateData(); forceUpdate(); } }, [schema, validateData, forceUpdate, createUnifiedValidator]); const onTimeout = (0, _react.useCallback)(() => { setFormState(undefined); setSubmitState({ info: undefined, warning: undefined, error: undefined, customStatus: undefined }); }, [setFormState, setSubmitState]); (0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(() => { if (id) { if (initialData && !sharedData.data) { extendSharedData(initialData, { preventSyncOfSameInstance: true }); } } }, [id, initialData, extendSharedData, sharedData.data]); (0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(() => { if (id) { extendAttachment({ visibleDataHandler, filterDataHandler, validationVersion: validationVersionRef.current, hasErrors, hasFieldError, setShowAllErrors, setSubmitState, clearData, setData, updateDataValue, fieldConnectionsRef, fieldStatusRef, fieldErrorRef, internalDataRef }, { preventSyncOfSameInstance: true }); if (filterSubmitData) { rerenderUseDataHook === null || rerenderUseDataHook === void 0 || rerenderUseDataHook(); } } }, [clearData, extendAttachment, filterDataHandler, filterSubmitData, hasErrors, hasFieldError, id, rerenderUseDataHook, setData, setShowAllErrors, setSubmitState, updateDataValue, visibleDataHandler]); const { bufferedFormState: formState } = useFormStatusBuffer({ formState: formStateRef.current, waitFor: hasFieldState('pending'), minimumAsyncBehaviorTime, asyncSubmitTimeout, onTimeout }); const submitState = submitStateRef.current; const disabled = typeof (rest === null || rest === void 0 ? void 0 : rest['disabled']) === 'boolean' ? rest === null || rest === void 0 ? void 0 : rest['disabled'] : formState === 'pending' ? true : undefined; const contextErrorMessages = (errorMessages === null || errorMessages === void 0 ? void 0 : errorMessages[locale !== null && locale !== void 0 ? locale : sharedLocale]) || errorMessages; const getSourceValue = (0, _react.useCallback)(value => { const data = internalDataRef.current; if (String(value).startsWith('/') && _index.default.has(data, String(value))) { return _index.default.get(data, String(value)); } return value; }, []); const contextValue = { handlePathChange, handlePathChangeUnvalidated, handleSubmit, setMountedFieldState, handleSubmitCall, setFormState, setSubmitState, setShowAllErrors, revealError, setFieldEventListener, setFieldState, setFieldError, setFieldConnection, setFieldInternals, setValueInternals, hasErrors, hasFieldError, hasFieldState, hasFieldWithAsyncValidator, validateData, updateDataValue, setData, clearData, visibleDataHandler, filterDataHandler, getSubmitData, getSubmitParams, addOnChangeHandler, scrollToTop, registerSectionSchema, schema, disabled, required, formState, activeSubmitButtonId: activeSubmitButtonIdRef.current, submitState, setActiveSubmitButtonId, contextErrorMessages, hasContext: true, errors: errorsRef.current, showAllErrors: showAllErrorsRef.current, hasVisibleError: hasVisibleErrorRef.current.size > 0, addSetShowAllErrorsRef, fieldConnectionsRef, fieldDisplayValueRef, fieldInternalsRef, valueInternalsRef, mountedFieldsRef, snapshotsRef, existingFieldsRef, formElementRef, isEmptyDataRef, fieldErrorRef, errorsRef, sectionSchemaPathsRef, getAjvInstance, countryCode: countryCode ? getSourceValue(countryCode) : undefined, id, data: internalDataRef.current, internalDataRef, props, ...rest }; if (id) { sharedDataContext.set(contextValue); } const show = Boolean(showAllErrorsRef.current); const resolvedLocale = locale || sharedLocale; const customErrorSummaryTitle = translations === null || translations === void 0 || (_translations$resolve = translations[resolvedLocale]) === null || _translations$resolve === void 0 || (_translations$resolve = _translations$resolve.Field) === null || _translations$resolve === void 0 ? void 0 : _translations$resolve.errorSummaryTitle; const formStatusConfig = (0, _react.useMemo)(() => { var _ref2, _status$stack$0$title, _status$stack$; const status = show ? _GlobalStatusProvider.default.get(globalStatusId) : null; return { globalStatus: { show, id: globalStatusId, title: (_ref2 = (_status$stack$0$title = status === null || status === void 0 || (_status$stack$ = status.stack[0]) === null || _status$stack$ === void 0 ? void 0 : _status$stack$.title) !== null && _status$stack$0$title !== void 0 ? _status$stack$0$title : customErrorSummaryTitle) !== null && _ref2 !== void 0 ? _ref2 : translation.errorSummaryTitle } }; }, [globalStatusId, show, customErrorSummaryTitle, translation.errorSummaryTitle]); return _react.default.createElement(_Context2.default.Provider, { value: contextValue }, _react.default.createElement(_index3.default, { FormStatus: formStatusConfig, formElement: disabled ? { disabled: true } : undefined, locale: locale ? locale : undefined, translations: translations ? translations : undefined }, children)); } function useFormStatusBuffer(props) { const { formState, waitFor, minimumAsyncBehaviorTime, asyncSubmitTimeout, onTimeout } = props || {}; const [, forceUpdate] = (0, _react.useReducer)(() => ({}), {}); const stateRef = (0, _react.useRef)(); const nowRef = (0, _react.useRef)(null); const timeoutRef = (0, _react.useRef)({}); const setState = (0, _react.useCallback)(state => { stateRef.current = state; forceUpdate(); }, []); const clear = (0, _react.useCallback)(() => { for (const key in timeoutRef.current) { clearTimeout(timeoutRef.current[key]); } }, []); const hadCompleteRef = (0, _react.useRef)(false); const activeElementRef = (0, _react.useRef)(null); (0, _react.useEffect)(() => { const isTest = process.env.NODE_ENV === 'test'; const minimum = minimumAsyncBehaviorTime !== null && minimumAsyncBehaviorTime !== void 0 ? minimumAsyncBehaviorTime : isTest ? 1 : 1000; if (stateRef.current && formState === 'error') { clear(); setState(undefined); return; } if (formState === 'abort') { clear(); setState('abort'); timeoutRef.current.reset = setTimeout(() => { nowRef.current = 0; setState(undefined); }, minimum); return; } if (formState === 'complete') { hadCompleteRef.current = true; } if (formState === 'pending' && stateRef.current !== 'pending') { activeElementRef.current = document.activeElement; clear(); nowRef.current = Date.now(); hadCompleteRef.current = false; setState('pending'); } else if (stateRef.current === 'pending') { const offset = Math.max(Date.now() - nowRef.current); const delay = isTest ? minimum : Math.max(minimum - offset, 0); if (!waitFor) { timeoutRef.current.complete = setTimeout(() => { if (hadCompleteRef.current) { setState('complete'); } window.requestAnimationFrame(() => { var _activeElementRef$cur, _activeElementRef$cur2; (_activeElementRef$cur = activeElementRef.current) === null || _activeElementRef$cur === void 0 || (_activeElementRef$cur2 = _activeElementRef$cur.focus) === null || _activeElementRef$cur2 === void 0 || _activeElementRef$cur2.call(_activeElementRef$cur); }); }, delay); timeoutRef.current.reset = setTimeout(() => { nowRef.current = 0; setState(undefined); clear(); }, delay + minimum); } } if (stateRef.current === 'pending') { timeoutRef.current.timeout = setTimeout(() => { clear(); setState(undefined); onTimeout === null || onTimeout === void 0 || onTimeout(); }, asyncSubmitTimeout !== null && asyncSubmitTimeout !== void 0 ? asyncSubmitTimeout : 30000); } return clear; }, [clear, minimumAsyncBehaviorTime, formState, setState, waitFor, asyncSubmitTimeout, onTimeout]); return { bufferedFormState: stateRef.current }; } const clearedData = exports.clearedData = Object.freeze({}); //# sourceMappingURL=Provider.js.map