@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
394 lines (393 loc) • 15.9 kB
JavaScript
"use strict";
"use client";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _classnames = _interopRequireDefault(require("classnames"));
var _index = require("../../../../components/index.js");
var _componentHelper = require("../../../../shared/component-helper.js");
var _isAsync = require("../../../../shared/helpers/isAsync.js");
var _useId = _interopRequireDefault(require("../../../../shared/helpers/useId.js"));
var _WizardContext = _interopRequireDefault(require("../Context/WizardContext.js"));
var _Context = _interopRequireDefault(require("../../DataContext/Context.js"));
var _useEventListener = _interopRequireDefault(require("../../DataContext/Provider/useEventListener.js"));
var _Handler = _interopRequireDefault(require("../../Form/Handler/Handler.js"));
var _useSharedState = require("../../../../shared/helpers/useSharedState.js");
var _useHandleLayoutEffect = _interopRequireDefault(require("./useHandleLayoutEffect.js"));
var _useStepAnimation = _interopRequireDefault(require("./useStepAnimation.js"));
var _useVisibility = _interopRequireDefault(require("../../Form/Visibility/useVisibility.js"));
var _DisplaySteps = require("./DisplaySteps.js");
var _IterateOverSteps = require("./IterateOverSteps.js");
var _PrerenderFieldPropsOfOtherSteps = require("./PrerenderFieldPropsOfOtherSteps.js");
var _useIsomorphicLayoutEffect = require("../../../../shared/helpers/useIsomorphicLayoutEffect.js");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
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 _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
function handleDeprecatedProps(props) {
const {
variant,
sidebarId,
...rest
} = props;
return rest;
}
function WizardContainer(props) {
const {
className,
id: idProp,
mode = 'strict',
initialActiveIndex = 0,
omitScrollManagement,
omitFocusManagement,
onStepChange,
children,
noAnimation = false,
expandedInitially = false,
prerenderFieldProps = true,
keepInDOM,
validationMode,
outset = true,
...rest
} = handleDeprecatedProps(props);
const dataContext = (0, _react.useContext)(_Context.default);
const {
hasContext,
setFormState,
handleSubmitCall,
setShowAllErrors,
setSubmitState,
hasFieldState
} = dataContext;
const id = (0, _useId.default)(idProp);
const [, forceUpdate] = (0, _react.useReducer)(() => ({}), {});
const activeIndexRef = (0, _react.useRef)(initialActiveIndex);
const totalStepsRef = (0, _react.useRef)(NaN);
const visitedStepsRef = (0, _react.useRef)(new Map());
const fieldErrorRef = (0, _react.useRef)(new Map());
const storeStepStateRef = (0, _react.useRef)(new Map());
const onStepChangeEventsRef = (0, _react.useRef)(new Set());
const hasErrorInOtherStepRef = (0, _react.useRef)(false);
const elementRef = (0, _react.useRef)();
const stepElementRef = (0, _react.useRef)();
const preventNextStepRef = (0, _react.useRef)(false);
const stepsRef = (0, _react.useRef)(new Map());
const tmpStepsRef = (0, _react.useRef)();
const stepIndexRef = (0, _react.useRef)(-1);
const updateTitlesRef = (0, _react.useRef)();
const prerenderFieldPropsRef = (0, _react.useRef)({});
const bypassOnNavigation = validationMode === 'bypassOnNavigation';
const sharedStateRef = (0, _react.useRef)();
sharedStateRef.current = (0, _useSharedState.useSharedState)(hasContext && id ? (0, _useSharedState.createReferenceKey)(id, 'wizard') : undefined);
const hasFieldErrorInStep = (0, _react.useCallback)(index => {
return Array.from(fieldErrorRef.current.values()).some(({
index: i,
hasError
}) => {
return i === index && hasError;
});
}, []);
const setStepAsVisited = (0, _react.useCallback)(index => {
visitedStepsRef.current.set(index, true);
}, []);
(0, _react.useEffect)(() => {
if (!initialActiveIndex) {
setStepAsVisited(activeIndexRef.current);
}
}, [initialActiveIndex, setStepAsVisited]);
const syncStepsState = (0, _react.useCallback)((index = undefined, forStates = ['unknown', 'error']) => {
const checkUnknown = forStates.includes('unknown');
const checkError = forStates.includes('error');
for (let i = 0; i < totalStepsRef.current; i++) {
if (index !== undefined && index !== i) {
continue;
}
let result = undefined;
if (checkUnknown) {
const state = i < activeIndexRef.current && visitedStepsRef.current.get(i) === undefined;
if (state) {
result = 'unknown';
}
}
if (checkError) {
const state = hasFieldErrorInStep(i);
const existingState = storeStepStateRef.current.get(i);
if (state) {
result = 'error';
} else if (existingState === 'error') {
if (i === activeIndexRef.current) {
result = undefined;
} else {
result = existingState;
}
}
}
storeStepStateRef.current.set(i, result);
}
}, [hasFieldErrorInStep]);
const hasInvalidStepsState = (0, _react.useCallback)((index = undefined, forStates = ['unknown', 'error']) => {
syncStepsState();
const checkUnknown = forStates.includes('unknown');
const checkError = forStates.includes('error');
for (let i = 0; i < totalStepsRef.current; i++) {
if (index !== undefined && index !== i) {
continue;
}
const state = storeStepStateRef.current.get(i);
if (checkUnknown) {
if (state === 'unknown') {
return true;
}
}
if (checkError) {
if (state === 'error') {
return true;
}
}
}
return false;
}, [syncStepsState]);
const setFieldError = (0, _react.useCallback)((index, path, hasError) => {
fieldErrorRef.current.set(path, {
index,
hasError
});
}, []);
const preventNavigation = (0, _react.useCallback)((shouldPrevent = true) => {
preventNextStepRef.current = shouldPrevent;
}, []);
const getStepChangeOptions = (0, _react.useCallback)(index => {
var _stepsRef$current$get, _stepsRef$current$get2;
const previousIndex = activeIndexRef.current;
const totalSteps = Number.isNaN(totalStepsRef.current) ? stepsRef.current.size : totalStepsRef.current;
const options = {
preventNavigation,
totalSteps,
previousStep: {
index: previousIndex
}
};
const id = (_stepsRef$current$get = stepsRef.current.get(index)) === null || _stepsRef$current$get === void 0 ? void 0 : _stepsRef$current$get.id;
if (id) {
Object.assign(options, {
id
});
}
const previousId = (_stepsRef$current$get2 = stepsRef.current.get(previousIndex)) === null || _stepsRef$current$get2 === void 0 ? void 0 : _stepsRef$current$get2.id;
if (previousId) {
Object.assign(options.previousStep, {
id: previousId
});
}
return options;
}, [preventNavigation]);
const callOnStepChange = (0, _react.useCallback)(async (index, mode) => {
if ((0, _isAsync.isAsync)(onStepChange)) {
return await onStepChange(index, mode, getStepChangeOptions(index));
}
return onStepChange === null || onStepChange === void 0 ? void 0 : onStepChange(index, mode, getStepChangeOptions(index));
}, [getStepChangeOptions, onStepChange]);
const {
setFocus,
scrollToTop,
isInteractionRef
} = (0, _useHandleLayoutEffect.default)({
elementRef,
stepElementRef
});
const executeLayoutAnimationRef = (0, _react.useRef)();
(0, _useStepAnimation.default)({
activeIndexRef,
stepElementRef,
executeLayoutAnimationRef
});
const handleLayoutEffect = (0, _react.useCallback)(() => {
if (!omitFocusManagement) {
setFocus();
}
if (!omitScrollManagement) {
scrollToTop();
}
}, [omitScrollManagement, omitFocusManagement, setFocus, scrollToTop]);
const handleStepChange = (0, _react.useCallback)(async ({
index,
skipErrorCheck,
skipStepChangeCall,
skipStepChangeCallBeforeMounted,
skipStepChangeCallFromHook,
mode
}) => {
let didSubmit = false;
const onSubmit = async () => {
if (!skipStepChangeCallFromHook) {
var _onStepChangeEventsRe;
onStepChangeEventsRef === null || onStepChangeEventsRef === void 0 || (_onStepChangeEventsRe = onStepChangeEventsRef.current) === null || _onStepChangeEventsRe === void 0 || _onStepChangeEventsRe.forEach(onStepChange => {
if (typeof onStepChange === 'function') {
onStepChange(index, mode, getStepChangeOptions(index));
}
});
}
let result = undefined;
if (!skipStepChangeCall && !(skipStepChangeCallBeforeMounted && !isInteractionRef.current)) {
result = await callOnStepChange(index, mode);
}
setFormState('abort');
setShowAllErrors(bypassOnNavigation ? false : hasInvalidStepsState(index, ['error']));
if (!preventNextStepRef.current && !(result instanceof Error)) {
handleLayoutEffect();
activeIndexRef.current = index;
setStepAsVisited(activeIndexRef.current);
forceUpdate();
}
preventNextStepRef.current = false;
didSubmit = true;
return result;
};
await handleSubmitCall({
skipErrorCheck,
skipFieldValidation: skipErrorCheck,
enableAsyncBehavior: (0, _isAsync.isAsync)(onStepChange),
onSubmit: bypassOnNavigation ? () => null : onSubmit
});
if (!didSubmit) {
if (bypassOnNavigation) {
await onSubmit();
} else {
if (mode === 'next') {
if (!hasInvalidStepsState(activeIndexRef.current) && !(hasFieldState !== null && hasFieldState !== void 0 && hasFieldState('pending'))) {
await onSubmit();
}
}
}
}
}, [bypassOnNavigation, callOnStepChange, getStepChangeOptions, handleLayoutEffect, handleSubmitCall, hasFieldState, hasInvalidStepsState, isInteractionRef, onStepChange, setFormState, setShowAllErrors, setStepAsVisited]);
const setActiveIndex = (0, _react.useCallback)((index, options) => {
if (index === activeIndexRef.current) {
return;
}
const mode = index > activeIndexRef.current ? 'next' : 'previous';
handleStepChange({
index,
skipErrorCheck: mode === 'previous',
mode,
...options
});
}, [handleStepChange]);
const handlePrevious = (0, _react.useCallback)(() => {
setActiveIndex(activeIndexRef.current - 1);
}, [setActiveIndex]);
const handleNext = (0, _react.useCallback)(() => {
setActiveIndex(activeIndexRef.current + 1);
}, [setActiveIndex]);
const handleChange = (0, _react.useCallback)(({
current_step
}) => {
setActiveIndex(current_step, mode === 'loose' ? {
skipErrorCheck: true
} : undefined);
}, [mode, setActiveIndex]);
const setFormError = (0, _react.useCallback)(error => {
setSubmitState === null || setSubmitState === void 0 || setSubmitState({
error
});
}, [setSubmitState]);
const handleSubmit = (0, _react.useCallback)(({
preventSubmit
}) => {
if (hasInvalidStepsState(undefined, ['error'])) {
return preventSubmit();
}
if (activeIndexRef.current + 1 < totalStepsRef.current) {
handleNext();
preventSubmit();
}
}, [hasInvalidStepsState, handleNext]);
(0, _useEventListener.default)('onSubmit', handleSubmit);
const {
check
} = (0, _useVisibility.default)();
const mapOverChildrenRef = (0, _react.useRef)(false);
const enableMapOverChildren = (0, _react.useCallback)(() => {
mapOverChildrenRef.current = true;
}, []);
const activeIndex = activeIndexRef.current;
const providerValue = (0, _react.useMemo)(() => {
return {
id,
activeIndex,
initialActiveIndex,
stepElementRef,
stepsRef,
updateTitlesRef,
activeIndexRef,
stepIndexRef,
totalStepsRef,
prerenderFieldProps,
prerenderFieldPropsRef,
hasErrorInOtherStepRef,
onStepChangeEventsRef,
keepInDOM,
enableMapOverChildren,
mapOverChildrenRef,
check,
setActiveIndex,
handlePrevious,
hasInvalidStepsState,
setFieldError,
handleNext,
setFormError
};
}, [id, activeIndex, initialActiveIndex, prerenderFieldProps, keepInDOM, enableMapOverChildren, check, setActiveIndex, handlePrevious, hasInvalidStepsState, setFieldError, handleNext, setFormError]);
(0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(() => {
if (id && hasContext) {
sharedStateRef.current.extend(providerValue);
}
}, [hasContext, id, providerValue]);
(0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(() => {
var _updateTitlesRef$curr;
(_updateTitlesRef$curr = updateTitlesRef.current) === null || _updateTitlesRef$curr === void 0 || _updateTitlesRef$curr.call(updateTitlesRef);
}, [stepsRef.current]);
const stepsLengthDidChange = (0, _react.useCallback)(() => {
const tmpCount = tmpStepsRef.current;
if (tmpCount === undefined) {
return false;
}
const count = totalStepsRef.current;
return count !== 0 && tmpCount !== 0 && count !== tmpCount;
}, []);
(0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(() => {
if (stepsLengthDidChange()) {
var _executeLayoutAnimati;
callOnStepChange(activeIndexRef.current, 'stepListModified');
(_executeLayoutAnimati = executeLayoutAnimationRef.current) === null || _executeLayoutAnimati === void 0 || _executeLayoutAnimati.call(executeLayoutAnimationRef);
}
tmpStepsRef.current = totalStepsRef.current;
}, [totalStepsRef.current, callOnStepChange, stepsLengthDidChange]);
if (!hasContext) {
(0, _componentHelper.warn)('You may wrap Wizard.Container in Form.Handler');
return _react.default.createElement(_Handler.default, null, _react.default.createElement(WizardContainer, _extends({}, props, {
id: id
})));
}
return _react.default.createElement(_WizardContext.default.Provider, {
value: providerValue
}, _react.default.createElement(_index.Space, _extends({
className: (0, _classnames.default)('dnb-forms-wizard-layout', className),
innerRef: elementRef
}, rest), _react.default.createElement(_DisplaySteps.DisplaySteps, {
mode: mode,
noAnimation: noAnimation,
expandedInitially: expandedInitially,
handleChange: handleChange,
outset: outset
}), _react.default.createElement("div", {
className: "dnb-forms-wizard-layout__contents"
}, _react.default.createElement(_IterateOverSteps.IterateOverSteps, null, children))), prerenderFieldProps && !keepInDOM && _react.default.createElement(_PrerenderFieldPropsOfOtherSteps.PrerenderFieldPropsOfOtherSteps, {
prerenderFieldPropsRef: prerenderFieldPropsRef,
stepsRef: stepsRef
}));
}
WizardContainer._supportsSpacingProps = true;
var _default = exports.default = WizardContainer;
//# sourceMappingURL=WizardContainer.js.map