@massds/mayflower-react
Version:
React versions of Mayflower design system UI components
372 lines (370 loc) • 15.6 kB
JavaScript
"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;