@helpscout/hsds-react
Version:
React component library for Help Scout's Design System
359 lines (288 loc) • 13 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.default = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose"));
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _getValidProps = _interopRequireDefault(require("@helpscout/react-utils/dist/getValidProps"));
var _classnames = _interopRequireDefault(require("classnames"));
var _VisuallyHidden = _interopRequireDefault(require("../VisuallyHidden"));
var _clipboard = require("../../utilities/clipboard");
var _VerificationCode = require("./VerificationCode.utils");
var _VerificationCode2 = require("./VerificationCode.css");
var _Tooltip = _interopRequireDefault(require("../Tooltip"));
var _jsxRuntime = require("react/jsx-runtime");
var VerificationCode = /*#__PURE__*/function (_React$Component) {
(0, _inheritsLoose2.default)(VerificationCode, _React$Component);
function VerificationCode() {
var _this;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
_this.setVerificationCodeFieldNode = function (node) {
_this.verificationCodeFieldRef = node;
};
_this.setClipboardPlaceholderNode = function (node) {
_this.clipboardPlaceholderRef = node;
};
_this.handleChange = function (value) {
var onChange = _this.props.onChange;
onChange(value);
};
_this.handlePaste = function (e) {
var _this$props = _this.props,
numberOfChars = _this$props.numberOfChars,
autoSubmitPaste = _this$props.autoSubmitPaste,
onEnter = _this$props.onEnter;
var clipboardData = e.clipboardData || window.clipboardData;
var pastedData = clipboardData.getData('Text');
e.stopPropagation();
e.preventDefault();
if (pastedData.length > 0) {
pastedData.slice(0, numberOfChars).split('').forEach(function (char, index, arr) {
if (_this.digitInputNodes.length > 0) {
_this.digitInputNodes[index].value = char;
_this.digitMaskNodes[index].innerText = char;
if (index === arr.length - 1) {
_this.digitInputNodes[index].focus();
}
}
});
var value = (0, _VerificationCode.getCurrentCodeValue)(_this.digitInputNodes);
_this.handleChange(value);
if (autoSubmitPaste && value.length === numberOfChars) {
onEnter(value);
}
}
};
_this.handleKeyDown = function (e) {
var key = e.key,
metaKey = e.metaKey,
ctrlKey = e.ctrlKey;
if ((metaKey || ctrlKey) && key === 'a') {
(0, _VerificationCode.selectAll)(_this.digitInputNodes, _this.digitMaskNodes);
e.preventDefault();
} else if ((metaKey || ctrlKey) && key === 'c') {
var selectionText = _this.digitMaskNodes.map(function (el) {
return el.innerText;
}).join('');
_this.clipboardPlaceholderRef.value = selectionText;
_this.clipboardPlaceholderRef.select();
(0, _clipboard.copyToClipboard)(); // if we trigger selectAll to close of the copy action, it interfere with the value copied over
setTimeout(function () {
return (0, _VerificationCode.selectAll)(_this.digitInputNodes, _this.digitMaskNodes);
}, 50);
} else if (key === 'Enter') {
var onEnter = _this.props.onEnter;
var code = _this.digitInputNodes.map(function (input) {
return input.value;
}).join('').trim();
onEnter(code);
}
};
_this.handleMouseDown = function (e) {
var activeElement = document.activeElement;
var target = e.target;
if (!target.classList.contains('DigitInput') && !activeElement.classList.contains('DigitInput')) {
// First we check if the click a) Wasn't executed directly on the input and b) one of the inputs is already focused
// If that is the case, we focus the first input
// We use a timeout to take the execution of this action out of the event loop so that the browser doesn't focus the body
setTimeout(function () {
_this.digitInputNodes[0].focus();
}, 0);
} else if (!target.classList.contains('DigitInput')) {
// If the click happened anywhere inside but not an input, the browser tries to focus the body (or a parent), we bring the focus
// back to the cached activeElement using a timeout as above
setTimeout(function () {
activeElement.focus();
}, 0);
}
};
_this.handleInputKeyUp = function (index, e) {
var key = e.key;
if (key !== 'Meta') {
var value = e.target.value;
var _this$props2 = _this.props,
numberOfChars = _this$props2.numberOfChars,
autoSubmitKeyUp = _this$props2.autoSubmitKeyUp,
onEnter = _this$props2.onEnter;
var digitMask = _this.digitMaskNodes[index];
if (key === 'Backspace') {
var selectionText = (0, _VerificationCode.getCleanSelectedText)();
if (selectionText.length > 1) {
(0, _VerificationCode.clearAll)(_this.digitInputNodes, _this.digitMaskNodes);
(0, _VerificationCode.showInputDigits)(_this.digitInputNodes, _this.digitMaskNodes);
_this.digitInputNodes[0].focus();
_this.handleChange('');
} else if (value === '' && !digitMask.innerText) {
// Tested ¯\_(ツ)_/¯
var prevIndex = index === 0 ? 0 : index - 1;
var previousDigit = _this.digitInputNodes[prevIndex];
digitMask.innerText = value;
previousDigit && previousDigit.select();
_this.handleChange((0, _VerificationCode.getCurrentCodeValue)(_this.digitInputNodes));
} else {
digitMask.innerText = value;
_this.handleChange((0, _VerificationCode.getCurrentCodeValue)(_this.digitInputNodes));
}
} else if (key === 'ArrowLeft') {
var _prevIndex = index === 0 ? 0 : index - 1;
var _previousDigit = _this.digitInputNodes[_prevIndex];
_previousDigit && _previousDigit.select();
} else if (key === 'ArrowRight') {
var nextIndex = index === numberOfChars - 1 ? numberOfChars : index + 1;
var nextDigit = _this.digitInputNodes[nextIndex];
nextDigit && nextDigit.select();
} else if (key.length === 1) {
// all chars have a length of 1, special keys have more
var _nextIndex = index === numberOfChars - 1 ? numberOfChars : index + 1;
var _nextDigit = _this.digitInputNodes[_nextIndex];
digitMask.innerText = value;
_nextDigit && _nextDigit.select();
var currentCodeValue = (0, _VerificationCode.getCurrentCodeValue)(_this.digitInputNodes);
_this.handleChange(currentCodeValue);
if (autoSubmitKeyUp && currentCodeValue.length === numberOfChars) {
onEnter(currentCodeValue);
}
}
}
};
_this.handleInputClick = function (e) {
(0, _VerificationCode.showInputDigits)(_this.digitInputNodes, _this.digitMaskNodes);
e.target.select();
};
return _this;
}
var _proto = VerificationCode.prototype;
_proto.componentDidMount = function componentDidMount() {
var _this2 = this;
this.digitInputNodes = Array.from(this.verificationCodeFieldRef.querySelectorAll('.DigitInput'));
this.digitMaskNodes = Array.from(this.verificationCodeFieldRef.querySelectorAll('.DigitMask'));
var _this$props3 = this.props,
code = _this$props3.code,
autoFocus = _this$props3.autoFocus,
numberOfChars = _this$props3.numberOfChars;
var startIndex = 0;
if (code) {
code.slice(0, numberOfChars).split('').forEach(function (char, index, arr) {
if (_this2.digitInputNodes.length > 0) {
_this2.digitInputNodes[index].value = char;
_this2.digitMaskNodes[index].innerText = char;
if (char) startIndex = index;
}
});
}
if (autoFocus && this.digitInputNodes[startIndex]) {
this.digitInputNodes[startIndex].focus();
}
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
var _this3 = this;
var _this$props4 = this.props,
code = _this$props4.code,
numberOfChars = _this$props4.numberOfChars;
if (prevProps.code !== code) {
if (code) {
(0, _VerificationCode.clearAll)(this.digitInputNodes, this.digitMaskNodes);
code.slice(0, numberOfChars).split('').forEach(function (char, index, arr) {
if (_this3.digitInputNodes.length > 0) {
_this3.digitInputNodes[index].value = char;
_this3.digitMaskNodes[index].innerText = char;
}
});
}
}
};
_proto.getClassName = function getClassName() {
var _this$props5 = this.props,
className = _this$props5.className,
isValid = _this$props5.isValid;
return (0, _classnames.default)('c-VerificationCode', !isValid && 'not-valid', className);
};
_proto.render = function render() {
var _this4 = this;
var _this$props6 = this.props,
numberOfChars = _this$props6.numberOfChars,
isValid = _this$props6.isValid,
rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props6, ["numberOfChars", "isValid"]);
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_VerificationCode2.VerificationCodeFieldUI, (0, _extends2.default)({}, (0, _getValidProps.default)(rest), {
className: this.getClassName(),
ref: this.setVerificationCodeFieldNode,
onPaste: this.handlePaste,
onKeyDown: this.handleKeyDown,
onMouseDown: this.handleMouseDown,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_VerificationCode2.ClipboardPlaceholderUI, {
readOnly: true,
tabIndex: "-1",
ref: this.setClipboardPlaceholderNode
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_VisuallyHidden.default, {
id: "digitInput",
children: "Code Digit"
}), Array(numberOfChars).fill(0).map(function (_, index) {
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_VerificationCode2.DigitInputWrapperUI, {
className: "DigitInputWrapper",
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_VerificationCode2.DigitMaskUI, {
className: "DigitMask " + _VerificationCode.CLASSNAMES.hidden
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_VerificationCode2.DigitInputUI, {
className: "DigitInput",
"aria-labelledby": "digitInput",
maxLength: "1",
onClick: _this4.handleInputClick,
onKeyUp: function onKeyUp(e) {
_this4.handleInputKeyUp(index, e);
}
})]
}, "DigitInput-" + index);
}), !isValid ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_VerificationCode2.ValidIconUI, {
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
animationDelay: 0,
animationDuration: 0,
appendTo: document.body,
display: "block",
placement: "top-end",
title: "Invalid verification code",
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_VerificationCode2.IconUI, {
name: "alert",
size: 24
})
})
}) : null]
}));
};
return VerificationCode;
}(_react.default.Component);
function noop() {}
VerificationCode.defaultProps = {
autoFocus: false,
autoSubmitPaste: false,
autoSubmitKeyUp: false,
code: '',
'data-cy': 'VerificationCode',
isValid: true,
numberOfChars: 6,
onEnter: noop,
onChange: noop
};
VerificationCode.propTypes = {
autoFocus: _propTypes.default.bool,
autoSubmitPaste: _propTypes.default.bool,
autoSubmitKeyUp: _propTypes.default.bool,
/** If you need to assign a value externally, use this prop. */
code: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),
/** Gives the field invalid stylings */
isValid: _propTypes.default.bool,
/** If you need more or less number of characters */
numberOfChars: _propTypes.default.number,
/** To get the current value on enter press */
onEnter: _propTypes.default.func,
/** To get the current value on change */
onChange: _propTypes.default.func,
/** Data attr for Cypress tests. */
'data-cy': _propTypes.default.string
};
var _default = VerificationCode;
exports.default = _default;
;