UNPKG

@massds/mayflower-react

Version:

React versions of Mayflower design system UI components

372 lines (370 loc) 15.6 kB
"use strict"; exports.__esModule = true; exports["default"] = void 0; var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); var _numbro = _interopRequireDefault(require("numbro")); var _languages = _interopRequireDefault(require("numbro/dist/languages.min")); var _is = _interopRequireDefault(require("is")); var _index = _interopRequireDefault(require("../Input/index.js")); var _utility = require("../Input/utility.js"); var _error = _interopRequireDefault(require("../Input/error.js")); var _context = require("../Input/context.js"); var _validate = require("../Input/validate.js"); var _excluded = ["max", "min", "step", "name", "onChange", "onBlur", "placeholder", "width", "maxlength", "format", "language", "showButtons"]; function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return 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); } /** * InputCurrency module. * @module @massds/mayflower-react/InputCurrency * @requires module:@massds/mayflower-assets/scss/01-atoms/_input--button * @requires module:@massds/mayflower-assets/scss/01-atoms/01-atoms/helper-text * @requires ma__input--button('currency'); */ var Currency = function Currency(props) { var ref = /*#__PURE__*/_react["default"].createRef(); return /*#__PURE__*/_react["default"].createElement(_context.InputContext.Consumer, null, function (context) { var upRef = /*#__PURE__*/_react["default"].createRef(); var downRef = /*#__PURE__*/_react["default"].createRef(); var inputClasses = (0, _classnames["default"])({ 'ma__input-currency__control': true, 'js-is-required': props.required, 'ma__input-currency__control--showButtons': props.showButtons }); var toCurrency = function toCurrency(number, decimal) { if (_is["default"].number(number)) { if (props.language) { var i = 0; var langKeys = Object.keys(_languages["default"]); var langMax = langKeys.length; for (; i < langMax; i += 1) { var langKey = langKeys[i]; var lang = _languages["default"][langKey]; _numbro["default"].registerLanguage(lang); } _numbro["default"].setLanguage(props.language); } var currency = (0, _numbro["default"])(number); var format = props.format; if (decimal) { format.mantissa = decimal; } return currency.formatCurrency(format); } return number; }; var hasNumberProperty = function hasNumberProperty(obj, property) { return Object.prototype.hasOwnProperty.call(obj, property) && _is["default"].number(obj[property]); }; var greaterThanMin = function greaterThanMin(val) { return !hasNumberProperty(props, 'min') || val >= props.min; }; var lessThanMax = function lessThanMax(val) { return !hasNumberProperty(props, 'max') || val <= props.max; }; var displayErrorMessage = function displayErrorMessage(val) { var min = props.min, max = props.max, required = props.required; if (required && !_is["default"].number(val)) { var errorMsg = 'Please enter a value.'; return { showError: true, errorMsg: errorMsg }; } if (_is["default"].number(val)) { var _validNumber = (0, _validate.validNumber)(val, min, max), showError = _validNumber.showError, _errorMsg = _validNumber.errorMsg; return { showError: showError, errorMsg: _errorMsg }; } return { showError: false, errorMsg: '' }; }; var handleChange = function handleChange(e) { var type = e.type; var stringValue = ref.current.value; var numberValue = stringValue ? Number(_numbro["default"].unformat(stringValue)) : 0; // If the stringvalue is empty, set to empty string so the required error // message is rendered. Otherwise pass the number value for the min/max check. var updateError = displayErrorMessage(!_is["default"].empty(stringValue) ? numberValue : ''); context.updateState(_extends({ value: stringValue }, updateError), function () { if (_is["default"].fn(props.onChange)) { props.onChange(numberValue, props.id, type); } }); }; var handleAdjust = function handleAdjust(e) { var direction = e.currentTarget === upRef.current ? 'up' : 'down'; var type = e.type; var stringValue = ref.current.value; var numberValue = stringValue ? Number(_numbro["default"].unformat(stringValue)) : 0; var newValue; if (direction === 'up') { newValue = Number((0, _numbro["default"])(numberValue).add(props.step).format({ mantissa: (0, _utility.countDecimals)(props.step) })); } else if (direction === 'down') { newValue = Number((0, _numbro["default"])(numberValue).subtract(props.step).format({ mantissa: (0, _utility.countDecimals)(props.step) })); } if (greaterThanMin(newValue) && lessThanMax(newValue)) { var updateError = displayErrorMessage(!_is["default"].empty(stringValue) ? newValue : ''); context.updateState(_extends({ value: toCurrency(newValue, (0, _utility.countDecimals)(props.step)) }, updateError), function () { if (_is["default"].fn(props.onChange)) { props.onChange(newValue, props.id, type, direction); } }); } }; var handleKeyDown = function handleKeyDown(e) { var type = e.type, key = e.key; var stringValue = ref.current.value; var numberValue = stringValue ? Number(_numbro["default"].unformat(stringValue)) : 0; // default to 0 if defaultValue is NaN if (_is["default"].number(numberValue) && !_is["default"].empty(stringValue)) { var newValue = numberValue; if (key === 'ArrowDown') { newValue = Number((0, _numbro["default"])(numberValue).subtract(props.step).format({ mantissa: (0, _utility.countDecimals)(props.step) })); if (greaterThanMin(newValue) && lessThanMax(newValue)) { var updateError = displayErrorMessage(!_is["default"].empty(stringValue) ? newValue : ''); context.updateState(_extends({ value: toCurrency(newValue, (0, _utility.countDecimals)(props.step)) }, updateError), function () { if (_is["default"].fn(props.onChange)) { props.onChange(newValue, props.id, type, key); } }); } } else if (key === 'ArrowUp') { newValue = Number((0, _numbro["default"])(numberValue).add(props.step).format({ mantissa: (0, _utility.countDecimals)(props.step) })); if (greaterThanMin(newValue) && lessThanMax(newValue)) { var _updateError = displayErrorMessage(!_is["default"].empty(stringValue) ? newValue : ''); context.updateState(_extends({ value: toCurrency(newValue, (0, _utility.countDecimals)(props.step)) }, _updateError), function () { if (_is["default"].fn(props.onChange)) { props.onChange(newValue, props.id, type, key); } }); } } } }; var handleBlur = function handleBlur(e) { var type = e.type; var inputEl = ref.current; var value = inputEl && inputEl.value; var numberValue = value && Number(_numbro["default"].unformat(value.replace('$', ''))); // isNotNumber returns true if value is null, undefined or NaN vs Number.isNaN only checks if value is NaN /* eslint-disable-next-line no-restricted-globals */ var isNotNumber = isNaN(numberValue); if (isNotNumber) { inputEl.setAttribute('placeholder', props.placeholder); } else { var newValue = numberValue; if (hasNumberProperty(props, 'max') && newValue > props.max) { newValue = props.max; } if (hasNumberProperty(props, 'min') && newValue < props.min) { newValue = props.min; } var updateError = displayErrorMessage(newValue); context.updateState(_extends({ value: toCurrency(newValue, (0, _utility.countDecimals)(props.step)) }, updateError), function () { if (_is["default"].fn(props.onBlur)) { props.onBlur(newValue, { id: props.id, type: type }); } }); } }; var handleFocus = function handleFocus() { var inputEl = ref.current; if (_is["default"].empty(inputEl.value)) { inputEl.removeAttribute('placeholder'); } }; var inputAttr = { className: inputClasses, name: props.name, id: props.id, type: 'text', placeholder: props.placeholder, 'data-type': 'text', maxLength: _is["default"].number(props.maxlength) ? Number(props.maxlength) : null, style: !_is["default"].empty(props.width) ? { width: props.width + "px" } : null, ref: ref, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, onKeyDown: handleKeyDown, required: props.required, value: context.getValue(), disabled: props.disabled }; return /*#__PURE__*/_react["default"].createElement("div", { className: "ma__input-currency" }, /*#__PURE__*/_react["default"].createElement("input", inputAttr), props.showButtons && /*#__PURE__*/_react["default"].createElement("div", { className: "ma__input-number__control-buttons" }, /*#__PURE__*/_react["default"].createElement("button", { type: "button", "aria-label": "increase value", className: "ma__input-currency__control-plus", onClick: handleAdjust, disabled: props.disabled, tabIndex: -1, ref: upRef }), /*#__PURE__*/_react["default"].createElement("button", { type: "button", "aria-label": "decrease value", className: "ma__input-currency__control-minus", onClick: handleAdjust, disabled: props.disabled, tabIndex: -1, ref: downRef }))); }); }; Currency.propTypes = process.env.NODE_ENV !== "production" ? { required: _propTypes["default"].bool, showButtons: _propTypes["default"].bool, language: _propTypes["default"].string, /* eslint-disable-next-line react/forbid-prop-types */ format: _propTypes["default"].object, max: _propTypes["default"].number, min: _propTypes["default"].number, onChange: _propTypes["default"].func, onBlur: _propTypes["default"].func, step: _propTypes["default"].number, placeholder: _propTypes["default"].string, id: _propTypes["default"].string.isRequired, name: _propTypes["default"].string.isRequired, maxlength: _propTypes["default"].number, width: _propTypes["default"].number, disabled: _propTypes["default"].bool } : {}; var InputCurrency = function InputCurrency(props) { var max = props.max, min = props.min, step = props.step, name = props.name, onChange = props.onChange, onBlur = props.onBlur, placeholder = props.placeholder, width = props.width, maxlength = props.maxlength, format = props.format, language = props.language, showButtons = props.showButtons, inputProps = _objectWithoutPropertiesLoose(props, _excluded); // Input and Currency share the props.required and props.id values. var currencyProps = { max: max, min: min, step: step, name: name, placeholder: placeholder, width: width, maxlength: maxlength, required: props.required, id: props.id, onChange: onChange, onBlur: onBlur, format: format, language: language, disabled: props.disabled, showButtons: showButtons }; if (!_is["default"].empty(inputProps.defaultValue)) { var currency = (0, _numbro["default"])(inputProps.defaultValue); inputProps.defaultValue = currency.formatCurrency(format); } return /*#__PURE__*/_react["default"].createElement(_index["default"], inputProps, /*#__PURE__*/_react["default"].createElement(Currency, currencyProps), /*#__PURE__*/_react["default"].createElement(_error["default"], { id: props.id })); }; InputCurrency.propTypes = process.env.NODE_ENV !== "production" ? { /** Whether the label should be hidden or not */ hiddenLabel: _propTypes["default"].bool, /** The label text for the input field, can be a string or a component */ labelText: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].object]).isRequired, /** Whether the field is required or not */ required: _propTypes["default"].bool, /** Whether the field is disabled or not */ disabled: _propTypes["default"].bool, /** The unique ID for the input field */ id: _propTypes["default"].string.isRequired, /** The name for the input field */ name: _propTypes["default"].string.isRequired, /** The max acceptable input length */ maxlength: _propTypes["default"].number, /** The pattern to filter input against, e.g. "[0-9]" for numbers only */ pattern: _propTypes["default"].string, /** The number of characters wide to make the input field */ width: _propTypes["default"].number, /** The placeholder text for the input field */ placeholder: _propTypes["default"].string, /** The message to be displayed in the event of an error. */ errorMsg: _propTypes["default"].string, /** Custom change function */ onChange: _propTypes["default"].func, /** Custom onBlur function */ onBlur: _propTypes["default"].func, /** Default input value */ defaultValue: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].number]), /** Max value for the field. */ max: _propTypes["default"].number, /** Min value for the field. */ min: _propTypes["default"].number, /** Using the up/down arrow keys will increment/decrement the input value by this number. */ step: _propTypes["default"].number, /** A language tag that represents what country the currency should display. Comes from IETF BCP 47: https://numbrojs.com/languages.html */ language: _propTypes["default"].string, /** Numbro Formatting options for displaying the currency. See https://numbrojs.com/format.html */ /* eslint-disable-next-line react/forbid-prop-types */ format: _propTypes["default"].object, /** Inline label and input field */ inline: _propTypes["default"].bool, /** Whether to render up/down buttons */ showButtons: _propTypes["default"].bool } : {}; InputCurrency.defaultProps = { hiddenLabel: false, required: false, onChange: null, onBlur: null, language: 'en-US', format: { mantissa: 2, trimMantissa: false, thousandSeparated: true, negative: 'parenthesis' }, step: 0.01, showButtons: true }; var _default = exports["default"] = InputCurrency; module.exports = exports.default;