@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
442 lines (441 loc) • 19 kB
JavaScript
;
"use client";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.getMessagesFromError = getMessagesFromError;
exports.states = void 0;
var _push = _interopRequireDefault(require("core-js-pure/stable/instance/push.js"));
var _react = _interopRequireWildcard(require("react"));
var _classnames = _interopRequireDefault(require("classnames"));
var _FieldBlockContext = _interopRequireDefault(require("./FieldBlockContext.js"));
var _Context = _interopRequireDefault(require("../DataContext/Context.js"));
var _index = require("../../../components/index.js");
var _index2 = require("../../../elements/index.js");
var _componentHelper = require("../../../shared/component-helper.js");
var _useId = _interopRequireDefault(require("../../../shared/helpers/useId.js"));
var _HelpButtonInline = _interopRequireWildcard(require("../../../components/help-button/HelpButtonInline.js"));
var _SubmitIndicator = _interopRequireDefault(require("../Form/SubmitIndicator/SubmitIndicator.js"));
var _useSharedState = require("../../../shared/helpers/useSharedState.js");
var _useTranslation = _interopRequireDefault(require("../hooks/useTranslation.js"));
var _index3 = require("../utils/index.js");
var _useIterateItemNo = require("../Iterate/ItemNo/useIterateItemNo.js");
var _br;
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 }; }
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); }
const states = exports.states = ['error', 'info', 'warning'];
function FieldBlock(props) {
var _props$id;
const dataContext = (0, _react.useContext)(_Context.default);
const fieldBlockContext = (0, _react.useContext)(_FieldBlockContext.default);
const nestedFieldBlockContext = !(fieldBlockContext !== null && fieldBlockContext !== void 0 && fieldBlockContext.disableStatusSummary) ? fieldBlockContext : null;
const id = (0, _useId.default)((_props$id = props.id) !== null && _props$id !== void 0 ? _props$id : props.forId);
const sharedData = (0, _useSharedState.createSharedState)('field-block-props-' + id);
const {
className,
forId,
layout = 'vertical',
layoutOptions,
composition,
label: labelProp,
labelDescription,
labelDescriptionInline,
labelSuffix,
labelSrOnly,
labelSize,
labelHeight,
help,
hideHelpButton,
statusPosition,
asFieldset,
required,
info,
warning,
error,
disableStatusSummary,
fieldState,
disabled,
width,
contentWidth,
align,
contentClassName,
fieldsetRole,
children,
...rest
} = Object.assign({}, sharedData.data, props);
const hasCustomWidth = /\d(rem)$/.test(String(width));
const hasCustomContentWidth = /\d(rem)$/.test(String(contentWidth));
const infoRef = (0, _react.useRef)();
const warningRef = (0, _react.useRef)();
const errorRef = (0, _react.useRef)();
const blockId = (0, _useId.default)(props.id);
const [salt, forceUpdate] = (0, _react.useReducer)(() => ({}), {});
const mountedFieldsRef = (0, _react.useRef)(new Map());
const fieldStateRef = (0, _react.useRef)(null);
const stateRecordRef = (0, _react.useRef)({});
const fieldStateIdsRef = (0, _react.useRef)(null);
const contentsRef = (0, _react.useRef)(null);
const hasInitiallyErrorPropRef = (0, _react.useRef)(Boolean(error));
const label = (0, _useIterateItemNo.useIterateItemNo)({
label: labelProp,
labelSuffix,
required
});
const setInternalRecord = (0, _react.useCallback)(props => {
const {
stateId,
identifier,
type
} = props;
if (!stateRecordRef.current[identifier]) {
stateRecordRef.current[identifier] = [];
}
fieldStateIdsRef.current = {
error: null,
warning: null,
info: null
};
const existingIndex = stateRecordRef.current[identifier].findIndex(item => {
return item.stateId === stateId && item.type === type;
});
if (existingIndex > -1) {
stateRecordRef.current[identifier][existingIndex] = {
...stateRecordRef.current[identifier][existingIndex],
...props
};
} else {
var _context;
(0, _push.default)(_context = stateRecordRef.current[identifier]).call(_context, props);
}
}, []);
const setBlockRecordNested = nestedFieldBlockContext === null || nestedFieldBlockContext === void 0 ? void 0 : nestedFieldBlockContext.setBlockRecord;
const setBlockRecord = (0, _react.useCallback)(props => {
if (setBlockRecordNested) {
setBlockRecordNested(props);
return;
}
setInternalRecord(props);
forceUpdate();
}, [setBlockRecordNested, setInternalRecord]);
const setFieldState = (0, _react.useCallback)((identifier, fieldState) => {
if (fieldState !== fieldStateRef.current) {
fieldStateRef.current = fieldState;
forceUpdate();
}
}, []);
const showFieldError = (0, _react.useCallback)((identifier, show) => {
if (nestedFieldBlockContext) {
nestedFieldBlockContext.showFieldError(identifier, show);
return;
}
if (stateRecordRef.current[identifier]) {
stateRecordRef.current[identifier] = stateRecordRef.current[identifier].map(item => {
if (item.showInitially) {
return item;
}
return {
...item,
show
};
});
forceUpdate();
}
}, [nestedFieldBlockContext]);
const statusContent = (0, _react.useMemo)(() => {
if (typeof error !== 'undefined' || errorRef.current && !error) {
errorRef.current = error;
setInternalRecord({
identifier: blockId,
showInitially: hasInitiallyErrorPropRef.current,
type: 'error',
content: error
});
}
if (typeof warning !== 'undefined' || warningRef.current !== warning) {
warningRef.current = warning;
setInternalRecord({
identifier: blockId,
showInitially: true,
type: 'warning',
content: warning
});
}
if (typeof info !== 'undefined' || infoRef.current !== info) {
infoRef.current = info;
setInternalRecord({
identifier: blockId,
showInitially: true,
type: 'info',
content: info
});
}
const statesWithMessages = Object.entries(stateRecordRef.current).flatMap(([identifier, states]) => states.map(props => {
return {
identifier,
...props
};
})).reduce((acc, cur) => {
const existing = acc.find(item => {
return item.type === cur.type;
});
const messages = getMessagesFromError(cur).map(message => {
return {
...cur,
message
};
});
if (existing) {
var _context2;
(0, _push.default)(_context2 = existing.messages).call(_context2, ...messages);
} else {
(0, _push.default)(acc).call(acc, {
...cur,
content: undefined,
messages
});
}
return acc;
}, []);
return states.reduce((acc, type) => {
const id = `${props.id || forId || blockId}-form-status--${type}`;
acc[type] = {
id,
label,
state: type === 'warning' ? 'warn' : type,
width_element: contentsRef,
no_animation: process.env.NODE_ENV === 'test' ? true : typeof globalThis !== 'undefined' ? globalThis.IS_TEST === true : false
};
const found = statesWithMessages.find(item => {
return item.type === type;
});
if (found !== null && found !== void 0 && found.messages) {
const messages = found.messages.map(msg => {
if (msg.type === 'error') {
if (!msg.showInitially && !msg.show) {
msg.message = null;
}
}
return msg;
}).filter(({
message
}) => message).reduce((acc, msg, i, arr) => {
const existingIndex = arr.findIndex(item => {
return (0, _componentHelper.convertJsxToString)(item.message) === (0, _componentHelper.convertJsxToString)(msg.message);
});
if (existingIndex === i) {
(0, _push.default)(acc).call(acc, msg);
}
return acc;
}, []);
if (messages.length > 0) {
acc[type] = {
...acc[type],
children: _react.default.createElement(CombineMessages, {
type: type,
messages: messages
})
};
fieldStateIdsRef.current[type] = id;
} else {
fieldStateIdsRef.current[type] = undefined;
}
}
return acc;
}, salt);
}, [error, warning, info, salt, setInternalRecord, blockId, props.id, forId, label]);
(0, _react.useEffect)(() => {
if (!nestedFieldBlockContext) {
showFieldError(blockId, Boolean(error));
}
}, [error, blockId, showFieldError, nestedFieldBlockContext]);
(0, _react.useEffect)(() => () => {
mountedFieldsRef.current = new Map();
stateRecordRef.current = {};
}, []);
const mainClasses = (0, _classnames.default)('dnb-forms-field-block', className, composition && `dnb-forms-field-block__composition dnb-forms-field-block__composition--${composition === true ? 'horizontal' : composition}`, width && `dnb-forms-field-block--width-${hasCustomWidth ? 'custom' : width}`, contentWidth && `dnb-forms-field-block--content-width-${hasCustomContentWidth ? 'custom' : contentWidth}`, labelHeight && `dnb-forms-field-block--label-height-${labelHeight}`, statusPosition === 'above' && 'dnb-forms-field-block--status-position-above');
const gridClasses = `dnb-forms-field-block__grid dnb-forms-field-block--layout-${layout}`;
const enableFieldset = useEnableFieldset({
label,
asFieldset,
children,
nestedFieldBlockContext
});
const labelProps = {
id: `${id}-label`,
className: 'dnb-forms-field-block__label',
element: enableFieldset ? 'legend' : 'label',
forId: enableFieldset ? undefined : forId,
srOnly: labelSrOnly,
space: 0,
size: labelSize,
disabled
};
const mainStyle = (0, _react.useMemo)(() => {
var _lO$minWidth, _lO$maxWidth;
const style = {};
if (hasCustomWidth) {
style['--dnb-forms-field-block-width'] = width;
}
if (hasCustomContentWidth) {
style['--dnb-forms-field-block-content-width'] = contentWidth;
}
const lO = layoutOptions || {};
const min = getFieldWidth((_lO$minWidth = lO.minWidth) !== null && _lO$minWidth !== void 0 ? _lO$minWidth : lO.width);
const max = getFieldWidth((_lO$maxWidth = lO.maxWidth) !== null && _lO$maxWidth !== void 0 ? _lO$maxWidth : lO.width);
if (typeof min === 'string') {
style['--dnb-forms-field-block-layout-width-min'] = min;
}
if (typeof max === 'string') {
style['--dnb-forms-field-block-layout-width-max'] = max;
}
return style;
}, [contentWidth, hasCustomContentWidth, hasCustomWidth, layoutOptions, width]);
if (dataContext !== null && dataContext !== void 0 && dataContext.prerenderFieldProps) {
return null;
}
const hasLabelDescription = isFragment(labelDescription) ? fragmentHasChildren(labelDescription) && !fragmentHasOnlyUndefinedChildren(labelDescription) : labelDescription;
const hasHelp = (help === null || help === void 0 ? void 0 : help.title) || (help === null || help === void 0 ? void 0 : help.content);
const hasOnlyLabelDescription = !label && hasLabelDescription;
return _react.default.createElement(_FieldBlockContext.default.Provider, {
value: {
setBlockRecord,
setFieldState,
showFieldError,
hasErrorProp: Boolean(error),
fieldStateIdsRef,
mountedFieldsRef,
composition,
disableStatusSummary
}
}, _react.default.createElement(_index.Space, _extends({
element: enableFieldset ? 'fieldset' : 'div',
style: mainStyle,
className: mainClasses,
"aria-labelledby": enableFieldset ? labelProps.id : undefined,
role: enableFieldset ? fieldsetRole : undefined
}, rest), _react.default.createElement("div", {
className: gridClasses
}, (label || labelDescription || hasHelp) && _react.default.createElement(_index.FormLabel, labelProps, _react.default.createElement("span", null, label && _react.default.createElement("span", {
className: "dnb-forms-field-block__label__content"
}, label), hasHelp && !hasOnlyLabelDescription && !hideHelpButton && _react.default.createElement("span", {
className: "dnb-help-button__word-joiner"
}, _react.default.createElement(_HelpButtonInline.default, {
contentId: `${id}-help`,
help: help
})), label && hasLabelDescription && !labelDescriptionInline && (_br || (_br = _react.default.createElement("br", null))), hasLabelDescription && _react.default.createElement("span", {
className: "dnb-forms-field-block__label__description"
}, labelDescription), hasHelp && hasOnlyLabelDescription && !hideHelpButton && _react.default.createElement("span", {
className: "dnb-help-button__word-joiner"
}, _react.default.createElement(_HelpButtonInline.default, {
contentId: `${id}-help`,
help: help
})))), hasHelp && _react.default.createElement(_HelpButtonInline.HelpButtonInlineContent, {
contentId: `${id}-help`,
className: "dnb-forms-field-block__help",
help: help,
breakout: layout === 'vertical' && !(nestedFieldBlockContext !== null && nestedFieldBlockContext !== void 0 && nestedFieldBlockContext.composition),
outset: layout !== 'horizontal'
}), _react.default.createElement("div", {
className: 'dnb-forms-field-block__status' + (contentWidth && contentWidth !== 'small' && contentWidth !== 'medium' && !(parseFloat(contentWidth) <= 11) ? ` dnb-forms-field-block__contents--width-${hasCustomContentWidth ? 'custom' : contentWidth}` : "")
}, _react.default.createElement(_index.FormStatus, statusContent === null || statusContent === void 0 ? void 0 : statusContent.error), _react.default.createElement(_index.FormStatus, statusContent === null || statusContent === void 0 ? void 0 : statusContent.warning), _react.default.createElement(_index.FormStatus, statusContent === null || statusContent === void 0 ? void 0 : statusContent.info)), _react.default.createElement("div", {
className: (0, _classnames.default)('dnb-forms-field-block__contents', contentClassName, contentWidth && `dnb-forms-field-block__contents--width-${hasCustomContentWidth ? 'custom' : contentWidth}`, align && `dnb-forms-field-block__contents--align-${align}`),
ref: contentsRef
}, children), _react.default.createElement(_SubmitIndicator.default, {
state: fieldState !== null && fieldState !== void 0 ? fieldState : fieldStateRef.current,
className: "dnb-forms-field-block__indicator dnb-forms-submit-indicator--inline-wrap"
}))));
}
function useEnableFieldset({
label,
asFieldset,
children,
nestedFieldBlockContext
}) {
return (0, _react.useMemo)(() => {
if (asFieldset === false) {
return false;
}
let result = asFieldset;
if (label && !result && !nestedFieldBlockContext) {
let count = 0;
(0, _componentHelper.findElementInChildren)(children, child => {
var _child$props, _child$type;
if (child !== null && child !== void 0 && (_child$props = child.props) !== null && _child$props !== void 0 && _child$props.label || (child === null || child === void 0 || (_child$type = child.type) === null || _child$type === void 0 ? void 0 : _child$type['_formElement']) === true) {
count++;
}
if (count > 1) {
return result = true;
}
});
}
return Boolean(result);
}, [asFieldset, children, label, nestedFieldBlockContext]);
}
function CombineMessages({
type,
messages
}) {
const translations = (0, _useTranslation.default)().Field;
if (messages.length === 1) {
return _react.default.createElement(_react.default.Fragment, null, messages[0].message);
}
return _react.default.createElement(_react.default.Fragment, null, type === 'error' ? translations.errorSummary : translations.stateSummary, _react.default.createElement(_index2.Ul, null, messages.map(({
message
}, i) => {
return _react.default.createElement(_index2.Li, {
key: i
}, message);
})));
}
function getMessage(error) {
if (error instanceof _index3.FormError) {
var _error$formattedMessa;
return (_error$formattedMessa = error.formattedMessage) !== null && _error$formattedMessa !== void 0 ? _error$formattedMessa : error.message;
}
return error.message;
}
function getMessagesFromError(item) {
const {
content
} = item;
if (content instanceof _index3.FormError && Array.isArray(content.errors)) {
return content.errors.map(content => {
return getMessage(content);
});
}
if (Array.isArray(content)) {
return content.map(content => {
return content instanceof _index3.FormError || content instanceof Error ? getMessage(content) : content;
});
}
if (content instanceof _index3.FormError || content instanceof Error) {
return [getMessage(content)];
}
return [(_react.default.isValidElement(content) ? content : content === null || content === void 0 ? void 0 : content.toString()) || content];
}
function isFragment(fragment) {
return _react.default.isValidElement(fragment) && fragment.type === _react.default.Fragment;
}
function fragmentHasChildren(fragment) {
return _react.default.isValidElement(fragment) && _react.default.Children.count(fragment.props.children) > 0;
}
function fragmentHasOnlyUndefinedChildren(fragment) {
const isUndefined = child => child === undefined;
return _react.default.isValidElement(fragment) && _react.default.Children.toArray(fragment.props.children).every(isUndefined);
}
FieldBlock._supportsSpacingProps = true;
var _default = exports.default = FieldBlock;
function getFieldWidth(width) {
switch (width) {
case 'small':
return 'var(--forms-field-width--small)';
case 'medium':
return 'var(--forms-field-width--medium)';
case 'large':
return 'var(--forms-field-width--large)';
}
return width;
}
//# sourceMappingURL=FieldBlock.js.map