@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
1,022 lines (1,021 loc) • 38.4 kB
JavaScript
"use client";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
const _excluded = ["id", "globalStatusId", "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"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
import "core-js/modules/web.dom-collections.iterator.js";
import React, { useRef, useMemo, useCallback, useReducer, useEffect, useContext } from 'react';
import pointer from '../../utils/json-pointer';
import { makeAjvInstance, ajvErrorsToFormErrors } from '../../utils';
import { debounce } from '../../../../shared/helpers';
import FieldPropsProvider from '../../Field/Provider';
import useUpdateEffect from '../../../../shared/helpers/useUpdateEffect';
import { isAsync } from '../../../../shared/helpers/isAsync';
import { createReferenceKey, useSharedState } from '../../../../shared/helpers/useSharedState';
import SharedContext from '../../../../shared/Context';
import useTranslation from '../../hooks/useTranslation';
import DataContext from '../Context';
import structuredClone from '@ungap/structured-clone';
const useLayoutEffect = typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect;
const isArrayJsonPointer = /^\/\d+(\/|$)/;
export default function Provider(props) {
var _sharedAttachments$da;
const [, forceUpdate] = 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
} = props,
rest = _objectWithoutProperties(props, _excluded);
if (data !== undefined && sessionStorageId !== undefined) {
throw new Error('Use "defaultData" instead of "data" when using sessionStorageId');
}
const {
hasContext
} = useContext(DataContext) || {};
if (hasContext && !isolate) {
throw new Error('DataContext (Form.Handler) cannot be nested');
}
const formElementRef = useRef(null);
const {
locale: sharedLocale
} = useContext(SharedContext) || {};
const translation = useTranslation().Field;
const ajvRef = useRef(makeAjvInstance(ajvInstance));
const mountedFieldsRef = useRef(new Map());
const snapshotsRef = useRef(new Map());
const existingFieldsRef = useRef(new Map());
const hasVisibleErrorRef = useRef(new Map());
const errorsRef = useRef();
const addSetShowAllErrorsRef = useRef([]);
const showAllErrorsRef = useRef(false);
const setShowAllErrors = useCallback(showAllErrors => {
showAllErrorsRef.current = showAllErrors ? Date.now() : showAllErrors;
forceUpdate();
addSetShowAllErrorsRef.current.forEach(fn => fn === null || fn === void 0 ? void 0 : fn(showAllErrors));
}, []);
const revealError = useCallback((path, hasError) => {
if (hasError) {
hasVisibleErrorRef.current.set(path, hasError);
} else {
hasVisibleErrorRef.current.delete(path);
}
forceUpdate();
}, []);
const submitStateRef = useRef({});
const setSubmitState = useCallback(state => {
submitStateRef.current = _objectSpread(_objectSpread({}, submitStateRef.current), state);
forceUpdate();
}, []);
const formStateRef = useRef();
const keepPending = useRef(false);
const setFormState = useCallback(function (formState) {
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
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 fieldErrorRef = useRef({});
const fieldStateRef = useRef({});
const initialData = 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) {
return JSON.parse(sessionDataJSON);
}
}
return data !== null && data !== void 0 ? data : defaultData;
}, []);
const internalDataRef = useRef(initialData);
const isEmptyDataRef = useRef(false);
const ajvValidatorRef = useRef();
const executeAjvValidator = useCallback(() => {
var _ajvValidatorRef$curr;
if (!ajvValidatorRef.current) {
return;
}
if (!((_ajvValidatorRef$curr = ajvValidatorRef.current) !== null && _ajvValidatorRef$curr !== void 0 && _ajvValidatorRef$curr.call(ajvValidatorRef, internalDataRef.current))) {
errorsRef.current = ajvErrorsToFormErrors(ajvValidatorRef.current.errors, internalDataRef.current);
} else {
errorsRef.current = undefined;
}
}, []);
const validateData = useCallback(() => {
if (!ajvValidatorRef.current) {
return;
}
executeAjvValidator();
forceUpdate();
}, [executeAjvValidator]);
const checkFieldStateFor = 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 = useCallback(state => {
return Array.from(mountedFieldsRef.current.entries()).some(_ref => {
let [path, item] = _ref;
return item.isMounted && checkFieldStateFor(path, state);
});
}, [checkFieldStateFor]);
const hasFieldError = useCallback(path => {
return Array.from(mountedFieldsRef.current.entries()).some(_ref2 => {
let [p, item] = _ref2;
return item.isMounted && p === path && checkFieldStateFor(path, 'error');
});
}, [checkFieldStateFor]);
const hasErrors = useCallback(() => {
return hasFieldState('error');
}, [hasFieldState]);
const setFieldError = useCallback((path, error) => {
if (error) {
fieldErrorRef.current[path] = error;
} else {
delete fieldErrorRef.current[path];
}
for (const item of fieldEventListenersRef.current) {
const {
type,
callback
} = item;
if (type === 'onSetFieldError') {
callback();
}
}
}, []);
const setFieldState = useCallback((path, fieldState) => {
if (fieldState !== fieldStateRef.current[path]) {
fieldStateRef.current[path] = fieldState;
forceUpdate();
}
}, []);
const getDataPathHandlerParameters = useCallback(function (path) {
var _fieldInternalsRef$cu;
let data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : internalDataRef.current;
const value = pointer.has(data, path) ? pointer.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 = useCallback(function (data, handler) {
let {
remove = false,
mutate = true,
fireHandlerWhen = null
} = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
const freshData = {};
const mutateEntry = (path, result) => {
if (remove) {
if (result === false) {
data = structuredClone(data);
pointer.remove(data, path);
}
} else {
if (typeof result !== 'undefined') {
if (mutate) {
data = structuredClone(data);
pointer.set(data, path, result);
} else {
pointer.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 = pointer.has(data, path);
if (exists) {
run(path);
}
}
pointer.walk(internalDataRef.current, (value, path) => {
if (fieldInternalsRef.current[path] === undefined) {
run(path);
}
});
if (!mutate) {
return freshData;
}
return data;
} else if (handler) {
const runFilter = _ref3 => {
let {
path,
condition
} = _ref3;
const exists = pointer.has(data, path);
if (exists) {
const result = typeof condition === 'function' ? condition(getDataPathHandlerParameters(path, data)) : condition;
mutateEntry(path, result);
}
};
const wildcardPaths = [];
Object.entries(handler).forEach(_ref4 => {
let [path, condition] = _ref4;
if (path.includes('*')) {
const parts = path.split(/\/\*/g);
const exists = pointer.has(data, parts[0]);
if (exists) {
const traverse = (subData, subPath, idx) => {
if (idx === parts.length - 1) {
wildcardPaths.push({
path: subPath,
condition
});
return;
}
const list = pointer.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 = useCallback(function () {
let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : internalDataRef.current;
let {
keepPaths,
removePaths
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
const visibleData = {};
mountedFieldsRef.current.forEach((item, path) => {
if (item && item.isVisible !== false && (item.isPreMounted !== false || item.wasStepChange === true) && (removePaths ? !removePaths.includes(path) : true) && pointer.has(data, path)) {
pointer.set(visibleData, path, pointer.get(data, path));
}
});
if (keepPaths) {
keepPaths.forEach(path => {
if (pointer.has(data, path)) {
pointer.set(visibleData, path, pointer.get(data, path));
}
});
}
return visibleData;
}, []);
const filterDataHandler = useCallback((data, filter) => {
if (filter) {
return mutateDataHandler(data, filter, {
remove: true
});
}
return data;
}, [mutateDataHandler]);
const filterData = useCallback(function (filter) {
let data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : internalDataRef.current;
return filterDataHandler(data, filter);
}, [filterDataHandler]);
const fieldDisplayValueRef = useRef({});
const fieldConnectionsRef = useRef({});
const setFieldConnection = useCallback((path, connections) => {
fieldConnectionsRef.current[path] = connections;
}, []);
const fieldInternalsRef = useRef({});
const setFieldInternals = useCallback((path, internals) => {
fieldInternalsRef.current[path] = Object.assign(fieldInternalsRef.current[path] || {}, internals);
}, []);
const valueInternalsRef = useRef({});
const setValueInternals = useCallback((path, props) => {
valueInternalsRef.current[path] = Object.assign(valueInternalsRef.current[path] || {}, {
props
});
}, []);
const hasFieldWithAsyncValidator = useCallback(() => {
for (const path in fieldInternalsRef.current) {
var _mountedFieldsRef$cur;
if ((_mountedFieldsRef$cur = mountedFieldsRef.current.get(path)) !== null && _mountedFieldsRef$cur !== void 0 && _mountedFieldsRef$cur.isMounted) {
var _fieldInternalsRef$cu2;
const props = (_fieldInternalsRef$cu2 = fieldInternalsRef.current[path]) === null || _fieldInternalsRef$cu2 === void 0 ? void 0 : _fieldInternalsRef$cu2.props;
if (isAsync(props === null || props === void 0 ? void 0 : props.onChangeValidator) || isAsync(props === null || props === void 0 ? void 0 : props.onBlurValidator)) {
return true;
}
}
}
return false;
}, []);
const sharedData = useSharedState(id);
const sharedAttachments = useSharedState(createReferenceKey(id, 'attachments'));
const sharedDataContext = useSharedState(createReferenceKey(id, 'data-context'));
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;
const cacheRef = useRef({
data,
schema,
shared: sharedData.data,
hasUsedInitialData: false
});
const internalData = 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 _objectSpread(_objectSpread({}, 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 _objectSpread(_objectSpread({}, 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 && pointer.has(internalData, props.path) ? pointer.get(internalData, props.path) : internalData;
const clearData = useCallback(() => {
var _ref5, _requestAnimationFram;
isEmptyDataRef.current = true;
internalDataRef.current = (_ref5 = typeof emptyData === 'function' ? emptyData(internalDataRef.current) : emptyData) !== null && _ref5 !== void 0 ? _ref5 : Array.isArray(internalDataRef.current) ? [] : clearedData;
if (id) {
setSharedData(internalDataRef.current);
}
forceUpdate();
onClear === null || onClear === void 0 ? void 0 : onClear();
(_requestAnimationFram = requestAnimationFrame) === null || _requestAnimationFram === void 0 ? void 0 : _requestAnimationFram(() => {
isEmptyDataRef.current = false;
});
}, [emptyData, id, onClear, setSharedData]);
useMemo(() => {
executeAjvValidator();
}, [internalDataRef.current]);
const storeInSession = useMemo(() => {
return debounce(() => {
var _window$sessionStorag2;
(_window$sessionStorag2 = window.sessionStorage) === null || _window$sessionStorag2 === void 0 ? void 0 : _window$sessionStorag2.setItem(sessionStorageId, JSON.stringify(internalDataRef.current));
}, process.env.NODE_ENV === 'test' ? 1 : 800);
}, [sessionStorageId]);
const setData = useCallback(function (newData) {
let {
preventUpdate = false
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (transformIn) {
newData = mutateDataHandler(newData, transformIn);
}
internalDataRef.current = newData;
if (id) {
extendSharedData(newData, {
preventSyncOfSameInstance: true
});
if (filterSubmitData) {
rerenderUseDataHook === null || rerenderUseDataHook === void 0 ? void 0 : rerenderUseDataHook();
}
}
if (sessionStorageId && typeof window !== 'undefined') {
storeInSession();
}
if (!preventUpdate) {
forceUpdate();
}
}, [extendSharedData, filterSubmitData, id, mutateDataHandler, rerenderUseDataHook, sessionStorageId, storeInSession, transformIn]);
const updateDataValue = useCallback(function (path, value) {
var _internalDataRef$curr;
let {
preventUpdate
} = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
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 = structuredClone(givenData);
} catch (e) {
newData = givenData;
}
if (path !== '/') {
pointer.set(newData, path, value);
}
setData(newData, {
preventUpdate
});
onUpdateDataValue === null || onUpdateDataValue === void 0 ? void 0 : onUpdateDataValue(path, value, {
preventUpdate
});
}, [onUpdateDataValue, setData]);
const handlePathChangeUnvalidated = useCallback(async (path, value) => {
if (!path) {
return null;
}
updateDataValue(path, value);
if (isAsync(onPathChange)) {
await (onPathChange === null || onPathChange === void 0 ? void 0 : onPathChange(path, value));
} else {
onPathChange === null || onPathChange === void 0 ? void 0 : onPathChange(path, value);
}
for (const itm of fieldEventListenersRef.current) {
if (itm.type === 'onPathChange' && itm.path === path) {
const {
callback
} = itm;
if (isAsync(callback)) {
await callback({
value
});
} else {
callback({
value
});
}
}
}
}, [onPathChange, updateDataValue]);
const handlePathChange = useCallback(async function (path) {
let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '_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 (isAsync(onChange)) {
await cb(transformedData, options);
} else {
cb(transformedData, options);
}
}
if (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 = useRef([]);
const addOnChangeHandler = useCallback(callback => {
const exists = changeHandlerStackRef.current.some(cb => {
return callback === cb;
});
if (!exists) {
changeHandlerStackRef.current.push(callback);
}
}, []);
const setMountedFieldState = useCallback((path, state) => {
mountedFieldsRef.current.set(path, _objectSpread(_objectSpread({}, mountedFieldsRef.current.get(path)), state));
for (const itm of fieldEventListenersRef.current) {
if (itm.type === 'onMount' && itm.path === path) {
const {
callback
} = itm;
callback();
}
}
}, []);
const scrollToTop = useCallback(() => {
if (typeof window !== 'undefined') {
var _window, _window$scrollTo;
(_window = window) === null || _window === void 0 ? void 0 : (_window$scrollTo = _window.scrollTo) === null || _window$scrollTo === void 0 ? void 0 : _window$scrollTo.call(_window, {
top: 0,
behavior: 'smooth'
});
}
}, []);
const handleSubmitCall = useCallback(async args => {
const {
onSubmit,
enableAsyncBehavior,
skipFieldValidation,
skipErrorCheck
} = args;
setSubmitState({
error: undefined,
customStatus: undefined
});
const asyncBehaviorIsEnabled = (skipErrorCheck ? true : !hasErrors() || hasFieldState('pending')) && (enableAsyncBehavior || hasFieldWithAsyncValidator());
if (asyncBehaviorIsEnabled) {
setFormState('pending');
}
if (!skipFieldValidation) {
for (const item of fieldEventListenersRef.current) {
var _mountedFieldsRef$cur2;
const {
path,
type,
callback
} = item;
if (type === 'onSubmitCall' && (_mountedFieldsRef$cur2 = mountedFieldsRef.current.get(path)) !== null && _mountedFieldsRef$cur2 !== void 0 && _mountedFieldsRef$cur2.isMounted) {
if (asyncBehaviorIsEnabled) {
await callback();
} else {
callback();
}
}
}
}
let result;
if (!(skipErrorCheck ? false : hasErrors()) && !hasFieldState('pending') && (skipFieldValidation ? true : !hasFieldState('error'))) {
var _result2, _result4, _result5, _result6, _result7;
let submitResult;
try {
if (isolate) {
for (const item of fieldEventListenersRef.current) {
const {
type,
callback
} = item;
if (type === 'onBeforeCommit') {
callback();
}
}
submitResult = await (onCommit === null || onCommit === void 0 ? void 0 : onCommit(internalDataRef.current, {
clearData
}));
} else {
submitResult = await onSubmit();
}
if (submitResult instanceof Error) {
throw submitResult;
}
} catch (error) {
submitResult = {
error
};
}
result = submitResult;
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']);
}
if ((_result4 = result) !== null && _result4 !== void 0 && _result4.error || (_result5 = result) !== null && _result5 !== void 0 && _result5.warning || (_result6 = result) !== null && _result6 !== void 0 && _result6.info || (_result7 = result) !== null && _result7 !== void 0 && _result7.customStatus) {
setSubmitState(result);
}
} else {
if (asyncBehaviorIsEnabled) {
await new Promise(resolve => window.requestAnimationFrame(resolve));
setFormState(undefined);
if (!skipFieldValidation) {
onSubmitContinueRef.current = () => {
window.requestAnimationFrame(() => {
handleSubmitCall(_objectSpread(_objectSpread({}, args), {}, {
skipFieldValidation: true
}));
});
};
}
}
setShowAllErrors(true);
onSubmitRequest === null || onSubmitRequest === void 0 ? void 0 : onSubmitRequest({
getErrors: () => Object.keys(fieldErrorRef.current).map(path => {
return getDataPathHandlerParameters(path);
}).filter(_ref6 => {
let {
error
} = _ref6;
return error;
})
});
for (const itm of fieldEventListenersRef.current) {
if (itm.type === 'onSubmitRequest') {
itm.callback();
}
}
}
return result;
}, [clearData, getDataPathHandlerParameters, hasErrors, hasFieldState, hasFieldWithAsyncValidator, isolate, onCommit, onSubmitRequest, setFormState, setShowAllErrors, setSubmitState]);
const getSubmitData = 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 = useCallback(() => {
const reduceToVisibleFields = (data, options) => {
return visibleDataHandler(transformOut ? mutateDataHandler(data, transformOut) : data, options);
};
const transformData = (data, handler) => {
return mutateDataHandler(data, handler, {
mutate: false,
fireHandlerWhen: _ref7 => {
let {
type
} = _ref7;
return type === 'field';
}
});
};
const formElement = formElementRef.current;
const params = {
filterData,
reduceToVisibleFields,
transformData,
resetForm: () => {
var _formElement$reset;
formElement === null || formElement === void 0 ? void 0 : (_formElement$reset = formElement.reset) === null || _formElement$reset === void 0 ? 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 = useCallback(async () => {
for (const item of fieldEventListenersRef.current) {
const {
type,
callback
} = item;
if (type === 'onBeforeSubmit') {
callback();
}
}
return await handleSubmitCall({
enableAsyncBehavior: 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 (isAsync(callback)) {
await callback({
preventSubmit
});
} else {
callback({
preventSubmit
});
}
}
}
if (stop) {
return;
}
const data = getSubmitData();
const options = getSubmitParams();
let result = undefined;
if (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 ? _objectSpread(_objectSpread({}, result), completeResult) : completeResult;
}
if (scrollTopOnSubmit) {
scrollToTop();
}
return result;
}
});
}, [getSubmitData, getSubmitParams, handleSubmitCall, onSubmit, onSubmitComplete, scrollToTop, scrollTopOnSubmit]);
const fieldEventListenersRef = useRef([]);
const setFieldEventListener = useCallback(function (path, type, callback) {
let {
remove = false
} = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
fieldEventListenersRef.current = fieldEventListenersRef.current.filter(_ref8 => {
let {
path: p,
type: t,
callback: c
} = _ref8;
return !(p === path && t === type && c === callback);
});
if (!remove) {
fieldEventListenersRef.current.push({
path,
type,
callback
});
}
}, []);
const onSubmitContinueRef = useRef(null);
if (!hasFieldState('pending')) {
var _onSubmitContinueRef$;
(_onSubmitContinueRef$ = onSubmitContinueRef.current) === null || _onSubmitContinueRef$ === void 0 ? void 0 : _onSubmitContinueRef$.call(onSubmitContinueRef);
onSubmitContinueRef.current = null;
}
useLayoutEffect(() => {
if (schema) {
var _ajvRef$current;
ajvValidatorRef.current = (_ajvRef$current = ajvRef.current) === null || _ajvRef$current === void 0 ? void 0 : _ajvRef$current.compile(schema);
}
validateData();
}, [schema, validateData]);
useUpdateEffect(() => {
if (schema && schema !== cacheRef.current.schema) {
var _ajvRef$current2;
cacheRef.current.schema = schema;
ajvValidatorRef.current = (_ajvRef$current2 = ajvRef.current) === null || _ajvRef$current2 === void 0 ? void 0 : _ajvRef$current2.compile(schema);
validateData();
forceUpdate();
}
}, [schema, validateData, forceUpdate]);
const onTimeout = useCallback(() => {
setFormState(undefined);
setSubmitState({
info: undefined,
warning: undefined,
error: undefined,
customStatus: undefined
});
}, [setFormState, setSubmitState]);
useLayoutEffect(() => {
if (id) {
if (initialData && !sharedData.data) {
extendSharedData(initialData, {
preventSyncOfSameInstance: true
});
}
}
}, [id, initialData, extendSharedData, sharedData.data]);
useLayoutEffect(() => {
if (id) {
extendAttachment({
visibleDataHandler,
filterDataHandler,
hasErrors,
hasFieldError,
setShowAllErrors,
setSubmitState,
clearData,
setData,
updateDataValue,
fieldConnectionsRef,
internalDataRef
}, {
preventSyncOfSameInstance: true
});
if (filterSubmitData) {
rerenderUseDataHook === null || rerenderUseDataHook === void 0 ? 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 ? true : undefined;
const contextErrorMessages = (errorMessages === null || errorMessages === void 0 ? void 0 : errorMessages[locale !== null && locale !== void 0 ? locale : sharedLocale]) || errorMessages;
const getSourceValue = useCallback(value => {
const data = internalDataRef.current;
if (String(value).startsWith('/') && pointer.has(data, String(value))) {
return pointer.get(data, String(value));
}
return value;
}, []);
const contextValue = _objectSpread({
handlePathChange,
handlePathChangeUnvalidated,
handleSubmit,
setMountedFieldState,
handleSubmitCall,
setFormState,
setSubmitState,
setShowAllErrors,
revealError,
setFieldEventListener,
setFieldState,
setFieldError,
setFieldConnection,
setFieldInternals,
setValueInternals,
hasErrors,
hasFieldError,
hasFieldState,
validateData,
updateDataValue,
setData,
clearData,
visibleDataHandler,
filterDataHandler,
getSubmitData,
getSubmitParams,
addOnChangeHandler,
scrollToTop,
schema,
disabled,
required,
formState,
submitState,
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,
ajvInstance: ajvRef.current,
countryCode: countryCode ? getSourceValue(countryCode) : undefined,
id,
data: internalDataRef.current,
internalDataRef,
props
}, rest);
if (id) {
sharedDataContext.set(contextValue);
}
return React.createElement(DataContext.Provider, {
value: contextValue
}, React.createElement(FieldPropsProvider, {
FormStatus: globalStatusId ? {
globalStatus: {
id: globalStatusId,
title: translation.errorSummaryTitle,
show: Boolean(showAllErrorsRef.current)
}
} : undefined,
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] = useReducer(() => ({}), {});
const stateRef = useRef();
const nowRef = useRef(null);
const timeoutRef = useRef({});
const setState = useCallback(state => {
stateRef.current = state;
forceUpdate();
}, [forceUpdate]);
const clear = useCallback(() => {
for (const key in timeoutRef.current) {
clearTimeout(timeoutRef.current[key]);
}
}, []);
const hadCompleteRef = useRef(false);
const activeElementRef = useRef(null);
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 ? void 0 : (_activeElementRef$cur2 = _activeElementRef$cur.focus) === null || _activeElementRef$cur2 === void 0 ? 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 ? void 0 : onTimeout();
}, asyncSubmitTimeout !== null && asyncSubmitTimeout !== void 0 ? asyncSubmitTimeout : 30000);
}
return clear;
}, [clear, minimumAsyncBehaviorTime, formState, setState, waitFor, asyncSubmitTimeout, onTimeout]);
return {
bufferedFormState: stateRef.current
};
}
export const clearedData = Object.freeze({});
//# sourceMappingURL=Provider.js.map