OTPInput.js 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. "use client";
  2. var __rest = this && this.__rest || function (s, e) {
  3. var t = {};
  4. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  5. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  6. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  7. }
  8. return t;
  9. };
  10. import * as React from 'react';
  11. import classNames from 'classnames';
  12. import raf from "rc-util/es/raf";
  13. import { ConfigContext } from '../../config-provider';
  14. import Input from '../Input';
  15. const OTPInput = /*#__PURE__*/React.forwardRef((props, ref) => {
  16. const {
  17. className,
  18. value,
  19. onChange,
  20. onActiveChange,
  21. index,
  22. mask
  23. } = props,
  24. restProps = __rest(props, ["className", "value", "onChange", "onActiveChange", "index", "mask"]);
  25. const {
  26. getPrefixCls
  27. } = React.useContext(ConfigContext);
  28. const prefixCls = getPrefixCls('otp');
  29. const maskValue = typeof mask === 'string' ? mask : value;
  30. // ========================== Ref ===========================
  31. const inputRef = React.useRef(null);
  32. React.useImperativeHandle(ref, () => inputRef.current);
  33. // ========================= Input ==========================
  34. const onInternalChange = e => {
  35. onChange(index, e.target.value);
  36. };
  37. // ========================= Focus ==========================
  38. const syncSelection = () => {
  39. raf(() => {
  40. var _a;
  41. const inputEle = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.input;
  42. if (document.activeElement === inputEle && inputEle) {
  43. inputEle.select();
  44. }
  45. });
  46. };
  47. // ======================== Keyboard ========================
  48. const onInternalKeyDown = event => {
  49. const {
  50. key,
  51. ctrlKey,
  52. metaKey
  53. } = event;
  54. if (key === 'ArrowLeft') {
  55. onActiveChange(index - 1);
  56. } else if (key === 'ArrowRight') {
  57. onActiveChange(index + 1);
  58. } else if (key === 'z' && (ctrlKey || metaKey)) {
  59. event.preventDefault();
  60. } else if (key === 'Backspace' && !value) {
  61. onActiveChange(index - 1);
  62. }
  63. syncSelection();
  64. };
  65. // ========================= Render =========================
  66. return /*#__PURE__*/React.createElement("span", {
  67. className: `${prefixCls}-input-wrapper`,
  68. role: "presentation"
  69. }, mask && value !== '' && value !== undefined && (/*#__PURE__*/React.createElement("span", {
  70. className: `${prefixCls}-mask-icon`,
  71. "aria-hidden": "true"
  72. }, maskValue)), /*#__PURE__*/React.createElement(Input, Object.assign({
  73. "aria-label": `OTP Input ${index + 1}`,
  74. type: mask === true ? 'password' : 'text'
  75. }, restProps, {
  76. ref: inputRef,
  77. value: value,
  78. onInput: onInternalChange,
  79. onFocus: syncSelection,
  80. onKeyDown: onInternalKeyDown,
  81. onMouseDown: syncSelection,
  82. onMouseUp: syncSelection,
  83. className: classNames(className, {
  84. [`${prefixCls}-mask-input`]: mask
  85. })
  86. })));
  87. });
  88. export default OTPInput;