UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

381 lines (380 loc) 15.5 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _index = require("../../../../components/index.js"); var _NumberUtils = require("../../../../components/number-format/NumberUtils.js"); var _Context = _interopRequireDefault(require("../../../../shared/Context.js")); var _FieldBlockContext = _interopRequireDefault(require("../../FieldBlock/FieldBlockContext.js")); var _classnames = _interopRequireDefault(require("classnames")); var _index2 = _interopRequireDefault(require("../../FieldBlock/index.js")); var _index3 = require("../../hooks/index.js"); var _utils = require("../../../../components/flex/utils.js"); var _clamp = require("../../../../shared/helpers/clamp.js"); var _Context2 = _interopRequireDefault(require("../../DataContext/Context.js")); var z = _interopRequireWildcard(require("zod")); 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); } const defaultMinimum = Number.MIN_SAFE_INTEGER; const defaultMaximum = Number.MAX_SAFE_INTEGER; function NumberComponent(props) { var _props$width, _props$innerRef, _dataContext$props2, _sharedContext$transl, _sharedContext$transl2; const dataContext = (0, _react.useContext)(_Context2.default); const fieldBlockContext = (0, _react.useContext)(_FieldBlockContext.default); const sharedContext = (0, _react.useContext)(_Context.default); const locale = sharedContext === null || sharedContext === void 0 ? void 0 : sharedContext.locale; const validateContinuouslyRef = (0, _react.useRef)(props === null || props === void 0 ? void 0 : props.validateContinuously); const { currency, currencyDisplay, percent, mask, step = 1, decimalLimit = 12, allowNegative = true, disallowLeadingZeroes = false, prefix: prefixProp, suffix: suffixProp, showStepControls } = props; const schema = (0, _react.useMemo)(() => { var _props$schema; return ((_props$schema = props.schema) !== null && _props$schema !== void 0 ? _props$schema : p => { const formatValidationValue = value => { const formatOptions = { locale }; if (p.currency) { formatOptions.currency = p.currency; } if (p.percent) { formatOptions.percent = true; } if (p.decimalLimit !== undefined) { formatOptions.decimals = p.decimalLimit; } return (0, _NumberUtils.format)(value, formatOptions); }; return z.number().nullish().superRefine((val, ctx) => { if (val === null || val === undefined) { return; } if ((p.minimum === undefined || p.minimum < defaultMinimum) && val < defaultMinimum) { ctx.addIssue({ code: 'too_small', minimum: defaultMinimum, type: 'number', inclusive: true, message: 'NumberField.errorMinimum', messageValues: { minimum: formatValidationValue(defaultMinimum) }, origin: 'number', locale }); } if ((p.maximum === undefined || p.maximum > defaultMaximum) && val > defaultMaximum) { ctx.addIssue({ code: 'too_big', maximum: defaultMaximum, type: 'number', inclusive: true, message: 'NumberField.errorMaximum', messageValues: { maximum: formatValidationValue(defaultMaximum) }, origin: 'number', locale }); } if (p.minimum !== undefined && val < p.minimum) { ctx.addIssue({ code: 'too_small', minimum: p.minimum, type: 'number', inclusive: true, message: 'NumberField.errorMinimum', messageValues: { minimum: formatValidationValue(p.minimum) }, origin: 'number', locale }); } if (p.maximum !== undefined && val > p.maximum) { ctx.addIssue({ code: 'too_big', maximum: p.maximum, type: 'number', inclusive: true, message: 'NumberField.errorMaximum', messageValues: { maximum: formatValidationValue(p.maximum) }, origin: 'number', locale }); } if (p.exclusiveMinimum !== undefined && val <= p.exclusiveMinimum) { ctx.addIssue({ code: 'too_small', minimum: p.exclusiveMinimum, type: 'number', inclusive: false, message: 'NumberField.errorExclusiveMinimum', messageValues: { exclusiveMinimum: formatValidationValue(p.exclusiveMinimum) }, origin: 'number', exclusiveMinimum: p.exclusiveMinimum, locale }); } if (p.exclusiveMaximum !== undefined && val >= p.exclusiveMaximum) { ctx.addIssue({ code: 'too_big', maximum: p.exclusiveMaximum, type: 'number', inclusive: false, message: 'NumberField.errorExclusiveMaximum', messageValues: { exclusiveMaximum: formatValidationValue(p.exclusiveMaximum) }, origin: 'number', exclusiveMaximum: p.exclusiveMaximum, locale }); } if (p.multipleOf !== undefined && val % p.multipleOf !== 0) { ctx.addIssue({ code: 'custom', message: 'NumberField.errorMultipleOf', messageValues: { multipleOf: formatValidationValue(p.multipleOf) }, origin: 'number', multipleOf: p.multipleOf, locale }); } }); } ); }, [props.schema, props.minimum, props.maximum, props.exclusiveMinimum, props.exclusiveMaximum, props.multipleOf, props.currency, props.percent, props.decimalLimit, locale]); const toInput = (0, _react.useCallback)(external => { if (external === undefined || external === null) { return null; } if (typeof external !== 'number' || isNaN(external)) { return ''; } return external; }, []); const fromInput = (0, _react.useCallback)(({ value, numberValue }) => { if (value === '') { return props.emptyValue; } if (allowNegative && Object.is(numberValue, -0)) { return props.emptyValue; } return numberValue; }, [props.emptyValue, allowNegative]); const ref = (0, _react.useRef)(); const preparedProps = { valueType: 'number', validateContinuously: validateContinuouslyRef.current, ...props, schema, toInput, fromInput, width: (_props$width = props.width) !== null && _props$width !== void 0 ? _props$width : fieldBlockContext !== null && fieldBlockContext !== void 0 && fieldBlockContext.composition ? 'stretch' : 'medium', innerRef: (_props$innerRef = props.innerRef) !== null && _props$innerRef !== void 0 ? _props$innerRef : ref }; const { id, name, className, innerRef, inputClassName, autoComplete, placeholder, value, startWith = null, minimum = defaultMinimum, maximum = defaultMaximum, disabled, htmlAttributes, hasError, size, width, align, handleFocus, handleBlur, handleChange, setDisplayValue } = (0, _index3.useFieldProps)(preparedProps); (0, _react.useEffect)(() => { var _innerRef$current; setDisplayValue((_innerRef$current = innerRef.current) === null || _innerRef$current === void 0 ? void 0 : _innerRef$current.value); }, [innerRef, setDisplayValue, value]); const { handleSubmit } = dataContext !== null && dataContext !== void 0 ? dataContext : {}; const onKeyDownHandler = (0, _react.useCallback)(e => { var _dataContext$props; const { event } = e; if (dataContext !== null && dataContext !== void 0 && (_dataContext$props = dataContext.props) !== null && _dataContext$props !== void 0 && _dataContext$props.isolate && event.key === 'Enter') { var _event$preventDefault; handleSubmit(); (_event$preventDefault = event.preventDefault) === null || _event$preventDefault === void 0 || _event$preventDefault.call(event); } if (!showStepControls) { return; } let numberValue = null; switch (event.key) { case 'ArrowUp': numberValue = (0, _clamp.clamp)((value !== null && value !== void 0 ? value : startWith) + step, minimum, maximum); break; case 'ArrowDown': numberValue = (0, _clamp.clamp)((value !== null && value !== void 0 ? value : startWith) - step, minimum, maximum); break; } if (numberValue !== null) { event.persist(); event.preventDefault(); handleChange({ numberValue }); } }, [dataContext === null || dataContext === void 0 || (_dataContext$props2 = dataContext.props) === null || _dataContext$props2 === void 0 ? void 0 : _dataContext$props2.isolate, handleChange, handleSubmit, maximum, minimum, showStepControls, startWith, step, value]); const onChangeHandler = (0, _react.useCallback)(args => { handleChange(args); if (typeof (args === null || args === void 0 ? void 0 : args.numberValue) === 'number') { if (args.numberValue > defaultMaximum || args.numberValue < defaultMinimum) { handleBlur(); } } }, [handleChange, handleBlur]); const fieldBlockProps = { forId: id, className: (0, _classnames.default)("dnb-forms-field-number dnb-input__border--tokens", className), contentClassName: (0, _classnames.default)('dnb-forms-field-number__contents', showStepControls && 'dnb-forms-field-number__contents--has-controls', hasError && 'dnb-input__status--error', disabled && 'dnb-input--disabled'), width: (width === 'stretch' || fieldBlockContext !== null && fieldBlockContext !== void 0 && fieldBlockContext.composition) && !showStepControls ? width : undefined, contentWidth: width !== false ? width : undefined, ...(0, _utils.pickSpacingProps)(props) }; const increaseClickHandler = (0, _react.useCallback)(() => { handleChange({ numberValue: (0, _clamp.clamp)((value !== null && value !== void 0 ? value : startWith) + step, minimum, maximum) }); }, [handleChange, maximum, minimum, startWith, step, value]); const increaseProps = showStepControls && { 'aria-hidden': true, className: 'dnb-button--control-after', variant: 'secondary', icon: 'add', size: size || 'small', tabIndex: -1, disabled: disabled || value >= maximum, onClick: increaseClickHandler, title: sharedContext === null || sharedContext === void 0 || (_sharedContext$transl = sharedContext.translation.Slider.addTitle) === null || _sharedContext$transl === void 0 ? void 0 : _sharedContext$transl.replace('%s', String(value + step)) }; const decreaseClickHandler = (0, _react.useCallback)(() => { handleChange({ numberValue: (0, _clamp.clamp)((value !== null && value !== void 0 ? value : startWith) - step, minimum, maximum) }); }, [handleChange, maximum, minimum, startWith, step, value]); const decreaseProps = showStepControls && { ...increaseProps, className: 'dnb-button--control-before', icon: 'subtract', size: size || 'small', disabled: disabled || value <= minimum, onClick: decreaseClickHandler, title: sharedContext === null || sharedContext === void 0 || (_sharedContext$transl2 = sharedContext.translation.Slider.subtractTitle) === null || _sharedContext$transl2 === void 0 ? void 0 : _sharedContext$transl2.replace('%s', String(value - step)) }; const prefix = typeof prefixProp === 'function' ? prefixProp(value) : prefixProp; const suffix = typeof suffixProp === 'function' ? suffixProp(value) : suffixProp; const maskProps = (0, _react.useMemo)(() => { const mask_options = { prefix, suffix, decimalLimit, allowNegative, disallowLeadingZeroes }; if (currency) { return { as_currency: currency, mask_options, currency_mask: { currencyDisplay, decimalLimit } }; } if (percent) { return { as_percent: percent, mask_options }; } return { mask, as_number: mask ? undefined : true, number_mask: mask ? undefined : mask_options }; }, [currency, currencyDisplay, decimalLimit, mask, percent, prefix, suffix, allowNegative, disallowLeadingZeroes]); const ariaParams = showStepControls && { role: 'spinbutton', 'aria-valuemin': String(minimum), 'aria-valuemax': String(maximum), 'aria-valuenow': String(value), 'aria-valuetext': String(value) }; const inputProps = { id, name, inner_ref: innerRef, autoComplete, className: (0, _classnames.default)(`dnb-forms-field-number__input dnb-input--${size}`, inputClassName), step: showStepControls ? step : undefined, placeholder, value, align: showStepControls ? 'center' : align, onKeyDown: onKeyDownHandler, onPaste: handleBlur, onFocus: handleFocus, onBlur: handleBlur, onChange: onChangeHandler, disabled, status: hasError ? 'error' : undefined, stretch: Boolean(width), ...maskProps, ...htmlAttributes, ...ariaParams }; if (showStepControls) { return _react.default.createElement(_index2.default, _extends({}, fieldBlockProps, { asFieldset: false }), _react.default.createElement("span", { className: "dnb-input__border dnb-input__border--root" }, _react.default.createElement(_index.Button, decreaseProps), _react.default.createElement(_index.InputMasked, inputProps), _react.default.createElement(_index.Button, increaseProps))); } return _react.default.createElement(_index2.default, _extends({}, fieldBlockProps, { asFieldset: false }), _react.default.createElement(_index.InputMasked, inputProps)); } NumberComponent._supportsSpacingProps = true; var _default = exports.default = NumberComponent; //# sourceMappingURL=Number.js.map