@cloud-ru/uikit-product-fields-predefined 2.4.7 → 2.4.8-preview-f8642e85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +25 -0
  2. package/dist/cjs/components/FieldCode/FieldCode.d.ts +42 -0
  3. package/dist/cjs/components/FieldCode/FieldCode.js +47 -0
  4. package/dist/cjs/components/FieldCode/components/Cell/Cell.d.ts +5 -0
  5. package/dist/cjs/components/FieldCode/components/Cell/Cell.js +27 -0
  6. package/dist/cjs/components/FieldCode/components/Cell/index.d.ts +1 -0
  7. package/dist/cjs/components/FieldCode/components/Cell/index.js +17 -0
  8. package/dist/cjs/components/FieldCode/components/Cell/styles.module.css +3 -0
  9. package/dist/cjs/components/FieldCode/components/ResendCode/ResendCode.d.ts +8 -0
  10. package/dist/cjs/components/FieldCode/components/ResendCode/ResendCode.js +28 -0
  11. package/dist/cjs/components/FieldCode/components/ResendCode/index.d.ts +1 -0
  12. package/dist/cjs/components/FieldCode/components/ResendCode/index.js +17 -0
  13. package/dist/cjs/components/FieldCode/components/ResendCode/utils.d.ts +1 -0
  14. package/dist/cjs/components/FieldCode/components/ResendCode/utils.js +8 -0
  15. package/dist/cjs/components/FieldCode/components/index.d.ts +2 -0
  16. package/dist/cjs/components/FieldCode/components/index.js +18 -0
  17. package/dist/cjs/components/FieldCode/constants.d.ts +14 -0
  18. package/dist/cjs/components/FieldCode/constants.js +10 -0
  19. package/dist/cjs/components/FieldCode/hooks/index.d.ts +3 -0
  20. package/dist/cjs/components/FieldCode/hooks/index.js +19 -0
  21. package/dist/cjs/components/FieldCode/hooks/useCodeInput.d.ts +22 -0
  22. package/dist/cjs/components/FieldCode/hooks/useCodeInput.js +98 -0
  23. package/dist/cjs/components/FieldCode/hooks/useFieldHelpers.d.ts +13 -0
  24. package/dist/cjs/components/FieldCode/hooks/useFieldHelpers.js +34 -0
  25. package/dist/cjs/components/FieldCode/hooks/useFocusCell.d.ts +5 -0
  26. package/dist/cjs/components/FieldCode/hooks/useFocusCell.js +22 -0
  27. package/dist/cjs/components/FieldCode/index.d.ts +1 -0
  28. package/dist/cjs/components/FieldCode/index.js +17 -0
  29. package/dist/cjs/components/FieldCode/styles.module.css +30 -0
  30. package/dist/cjs/components/FieldCode/utils.d.ts +6 -0
  31. package/dist/cjs/components/FieldCode/utils.js +21 -0
  32. package/dist/cjs/components/index.d.ts +1 -0
  33. package/dist/cjs/components/index.js +1 -0
  34. package/dist/esm/components/FieldCode/FieldCode.d.ts +42 -0
  35. package/dist/esm/components/FieldCode/FieldCode.js +40 -0
  36. package/dist/esm/components/FieldCode/components/Cell/Cell.d.ts +5 -0
  37. package/dist/esm/components/FieldCode/components/Cell/Cell.js +21 -0
  38. package/dist/esm/components/FieldCode/components/Cell/index.d.ts +1 -0
  39. package/dist/esm/components/FieldCode/components/Cell/index.js +1 -0
  40. package/dist/esm/components/FieldCode/components/Cell/styles.module.css +3 -0
  41. package/dist/esm/components/FieldCode/components/ResendCode/ResendCode.d.ts +8 -0
  42. package/dist/esm/components/FieldCode/components/ResendCode/ResendCode.js +25 -0
  43. package/dist/esm/components/FieldCode/components/ResendCode/index.d.ts +1 -0
  44. package/dist/esm/components/FieldCode/components/ResendCode/index.js +1 -0
  45. package/dist/esm/components/FieldCode/components/ResendCode/utils.d.ts +1 -0
  46. package/dist/esm/components/FieldCode/components/ResendCode/utils.js +5 -0
  47. package/dist/esm/components/FieldCode/components/index.d.ts +2 -0
  48. package/dist/esm/components/FieldCode/components/index.js +2 -0
  49. package/dist/esm/components/FieldCode/constants.d.ts +14 -0
  50. package/dist/esm/components/FieldCode/constants.js +7 -0
  51. package/dist/esm/components/FieldCode/hooks/index.d.ts +3 -0
  52. package/dist/esm/components/FieldCode/hooks/index.js +3 -0
  53. package/dist/esm/components/FieldCode/hooks/useCodeInput.d.ts +22 -0
  54. package/dist/esm/components/FieldCode/hooks/useCodeInput.js +95 -0
  55. package/dist/esm/components/FieldCode/hooks/useFieldHelpers.d.ts +13 -0
  56. package/dist/esm/components/FieldCode/hooks/useFieldHelpers.js +31 -0
  57. package/dist/esm/components/FieldCode/hooks/useFocusCell.d.ts +5 -0
  58. package/dist/esm/components/FieldCode/hooks/useFocusCell.js +19 -0
  59. package/dist/esm/components/FieldCode/index.d.ts +1 -0
  60. package/dist/esm/components/FieldCode/index.js +1 -0
  61. package/dist/esm/components/FieldCode/styles.module.css +30 -0
  62. package/dist/esm/components/FieldCode/utils.d.ts +6 -0
  63. package/dist/esm/components/FieldCode/utils.js +13 -0
  64. package/dist/esm/components/index.d.ts +1 -0
  65. package/dist/esm/components/index.js +1 -0
  66. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  67. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  68. package/package.json +6 -3
  69. package/src/components/FieldCode/FieldCode.tsx +115 -0
  70. package/src/components/FieldCode/components/Cell/Cell.tsx +32 -0
  71. package/src/components/FieldCode/components/Cell/index.ts +1 -0
  72. package/src/components/FieldCode/components/Cell/styles.module.scss +5 -0
  73. package/src/components/FieldCode/components/ResendCode/ResendCode.tsx +33 -0
  74. package/src/components/FieldCode/components/ResendCode/index.ts +1 -0
  75. package/src/components/FieldCode/components/ResendCode/utils.ts +5 -0
  76. package/src/components/FieldCode/components/index.ts +2 -0
  77. package/src/components/FieldCode/constants.ts +20 -0
  78. package/src/components/FieldCode/hooks/index.ts +3 -0
  79. package/src/components/FieldCode/hooks/useCodeInput.ts +147 -0
  80. package/src/components/FieldCode/hooks/useFieldHelpers.ts +52 -0
  81. package/src/components/FieldCode/hooks/useFocusCell.ts +29 -0
  82. package/src/components/FieldCode/index.ts +1 -0
  83. package/src/components/FieldCode/styles.module.scss +40 -0
  84. package/src/components/FieldCode/utils.ts +23 -0
  85. package/src/components/index.ts +1 -0
package/README.md CHANGED
@@ -351,6 +351,31 @@
351
351
  | onChange | `(value: string, mask: InputMask<Record<string, unknown>>) => void` | - | |
352
352
  | ref | `LegacyRef<HTMLInputElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs} |
353
353
  | key | `Key` | - | |
354
+ ## FieldCode
355
+ ### Props
356
+ | name | type | default value | description |
357
+ |------|------|---------------|-------------|
358
+ | codeLength* | `number` | - | Количество цифр в коде |
359
+ | className | `string` | - | CSS-класс компонента |
360
+ | cellClassName | `string` | - | CSS-класс ячейки кода |
361
+ | spacing | `number[]` | - | Позиции, после которых нужно вставить пробел (индексы символов, после которых будет пробел) |
362
+ | showEmptyChars | `boolean` | - | Подсветить пустые символы кода |
363
+ | resendCode | `ResendCodeProps` | - | Компонент отправки нового кода |
364
+ | focusEffects | `readonly FieldCodeFocusEffect[]` | - | Сценарии автофокуса; по умолчанию — первая ячейка при монтировании и после сброса (см. `FieldCodeFocusEffect`) |
365
+ | value | `string` | - | Значение кода |
366
+ | onChange | `(code: string) => void` | - | Колбек изменения значения |
367
+ | onComplete | `(code: string) => void` | - | Колбек достижения ввода всех символов кода |
368
+ | disabled | `boolean` | - | Деактивирован ли элемент Является ли поле деактивированным |
369
+ | label | `string` | - | Лейбл |
370
+ | size | enum Size: `"s"`, `"m"`, `"l"` | - | Размер |
371
+ | error | `string` | - | |
372
+ | ref | `LegacyRef<HTMLInputElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs} |
373
+ | key | `Key` | - | |
374
+ ## FieldCodeFocusEffect
375
+ Когда дергать `moveFocus` у `FieldCode` (массив `focusEffects`, порядок не важен).
376
+ ### Props
377
+ | name | type | default value | description |
378
+ |------|------|---------------|-------------|
354
379
 
355
380
 
356
381
  [//]: DOCUMENTATION_SECTION_END
@@ -0,0 +1,42 @@
1
+ import { FieldDecoratorProps } from '@snack-uikit/fields';
2
+ import { type ResendCodeProps } from './components';
3
+ import { type FieldCodeFocusEffect } from './constants';
4
+ import { UseCodeInputParams } from './hooks';
5
+ export type FieldCodeRef = {
6
+ /** Перенести фокус на ячейку с индексом `index` */
7
+ moveFocus: (index: number) => void;
8
+ /** Убрать фокус со всех ячеек кода */
9
+ blurFields: () => void;
10
+ /** Сбросить значение кода */
11
+ resetCode: () => void;
12
+ };
13
+ export type FieldCodeProps = {
14
+ /** CSS-класс компонента */
15
+ className?: string;
16
+ /** CSS-класс ячейки кода */
17
+ cellClassName?: string;
18
+ /** Позиции, после которых нужно вставить пробел (индексы символов, после которых будет пробел) */
19
+ spacing?: number[];
20
+ /** Подсветить пустые символы кода */
21
+ showEmptyChars?: boolean;
22
+ /** Компонент отправки нового кода */
23
+ resendCode?: ResendCodeProps;
24
+ /** Сценарии автофокуса; по умолчанию — первая ячейка при монтировании и после сброса (см. `FieldCodeFocusEffect`) */
25
+ focusEffects?: readonly FieldCodeFocusEffect[];
26
+ } & Omit<UseCodeInputParams, 'moveFocus'> & Pick<FieldDecoratorProps, 'size' | 'disabled' | 'label' | 'error'>;
27
+ export declare const FieldCode: import("react").ForwardRefExoticComponent<{
28
+ /** CSS-класс компонента */
29
+ className?: string;
30
+ /** CSS-класс ячейки кода */
31
+ cellClassName?: string;
32
+ /** Позиции, после которых нужно вставить пробел (индексы символов, после которых будет пробел) */
33
+ spacing?: number[];
34
+ /** Подсветить пустые символы кода */
35
+ showEmptyChars?: boolean;
36
+ /** Компонент отправки нового кода */
37
+ resendCode?: ResendCodeProps;
38
+ /** Сценарии автофокуса; по умолчанию — первая ячейка при монтировании и после сброса (см. `FieldCodeFocusEffect`) */
39
+ focusEffects?: readonly FieldCodeFocusEffect[];
40
+ } & Omit<UseCodeInputParams, "moveFocus"> & Pick<FieldDecoratorProps, "size" | "label" | "error" | "disabled"> & import("react").RefAttributes<FieldCodeRef>>;
41
+ export type { FieldCodeFocusEffect } from './constants';
42
+ export { FIELD_CODE_DEFAULT_FOCUS_EFFECTS } from './constants';
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FIELD_CODE_DEFAULT_FOCUS_EFFECTS = exports.FieldCode = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const classnames_1 = __importDefault(require("classnames"));
9
+ const react_1 = require("react");
10
+ const fields_1 = require("@snack-uikit/fields");
11
+ const components_1 = require("./components");
12
+ const constants_1 = require("./constants");
13
+ const hooks_1 = require("./hooks");
14
+ const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
15
+ const utils_1 = require("./utils");
16
+ exports.FieldCode = (0, react_1.forwardRef)(function FieldCode(props, ref) {
17
+ var _a;
18
+ const { codeLength, className, cellClassName, value, onChange, spacing, onComplete, size, disabled, label, error, showEmptyChars, resendCode, focusEffects = constants_1.FIELD_CODE_DEFAULT_FOCUS_EFFECTS, } = props;
19
+ const { inputsRef, moveFocus, blurFields } = (0, hooks_1.useFocusCell)(codeLength);
20
+ const { code, cellHandlers, onChangeCode } = (0, hooks_1.useCodeInput)({ value, onChange, codeLength, moveFocus, onComplete });
21
+ const { resetCode } = (0, hooks_1.useFieldHelpers)({
22
+ onChangeCode,
23
+ focusEffects,
24
+ moveFocus,
25
+ showEmptyChars,
26
+ code,
27
+ codeLength,
28
+ });
29
+ (0, react_1.useImperativeHandle)(ref, () => ({
30
+ moveFocus,
31
+ blurFields,
32
+ resetCode,
33
+ }), [moveFocus, blurFields, resetCode]);
34
+ const resolvedDecoratorProps = {
35
+ label,
36
+ disabled,
37
+ size,
38
+ error,
39
+ };
40
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(styles_module_scss_1.default.fieldCode, className), children: [(0, jsx_runtime_1.jsx)(fields_1.FieldDecorator, Object.assign({}, resolvedDecoratorProps, { children: (0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.codeContainer, "data-size": size, children: code.map((char, index) => ((0, jsx_runtime_1.jsx)(components_1.Cell, { ref: inputRef => {
41
+ if (inputRef) {
42
+ inputsRef.current[index] = inputRef;
43
+ }
44
+ }, className: (0, classnames_1.default)((spacing === null || spacing === void 0 ? void 0 : spacing.includes(index)) && styles_module_scss_1.default.cellSpacing, cellClassName), size: size, value: char, disabled: disabled, autoComplete: index === 0 ? 'one-time-code' : undefined, onKeyDown: e => cellHandlers.onKeyDown(e, index), onPaste: cellHandlers.onPaste, onChange: e => cellHandlers.onChange(e, index), validationState: (0, utils_1.getCellValidationState)(char, showEmptyChars, Boolean(error)) }, index))) }) })), resendCode ? (0, jsx_runtime_1.jsx)(components_1.ResendCode, Object.assign({}, resendCode, { size: (_a = resendCode.size) !== null && _a !== void 0 ? _a : size })) : null] }));
45
+ });
46
+ var constants_2 = require("./constants");
47
+ Object.defineProperty(exports, "FIELD_CODE_DEFAULT_FOCUS_EFFECTS", { enumerable: true, get: function () { return constants_2.FIELD_CODE_DEFAULT_FOCUS_EFFECTS; } });
@@ -0,0 +1,5 @@
1
+ import { FieldTextProps } from '@snack-uikit/fields';
2
+ export declare const Cell: import("react").ForwardRefExoticComponent<{
3
+ /** CSS-класс ячейки кода */
4
+ className?: string;
5
+ } & Pick<FieldTextProps, "size" | "onPaste" | "onChange" | "onKeyDown" | "value" | "disabled" | "autoComplete" | "validationState"> & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,27 @@
1
+ "use strict";
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)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.Cell = void 0;
18
+ const jsx_runtime_1 = require("react/jsx-runtime");
19
+ const classnames_1 = __importDefault(require("classnames"));
20
+ const react_1 = require("react");
21
+ const fields_1 = require("@snack-uikit/fields");
22
+ const constants_1 = require("../../constants");
23
+ const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
24
+ exports.Cell = (0, react_1.forwardRef)((props, ref) => {
25
+ const { className, size, value } = props, fieldCellProps = __rest(props, ["className", "size", "value"]);
26
+ return ((0, jsx_runtime_1.jsx)(fields_1.FieldText, Object.assign({ inputMode: 'numeric', ref: ref, className: (0, classnames_1.default)(styles_module_scss_1.default.cell, className), "data-size": size, showClearButton: false, value: value === constants_1.ZERO_WIDTH_SPACE ? '' : value, size: size }, fieldCellProps)));
27
+ });
@@ -0,0 +1 @@
1
+ export * from './Cell';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./Cell"), exports);
@@ -0,0 +1,3 @@
1
+ .cell input{
2
+ text-align:center;
3
+ }
@@ -0,0 +1,8 @@
1
+ import { ButtonFunctionProps } from '@snack-uikit/button';
2
+ export type ResendCodeProps = {
3
+ /** Колбек отправки нового кода */
4
+ onResend: () => void;
5
+ /** Количество секунд до следующего отправления кода */
6
+ secondsToNextResend: number;
7
+ } & Pick<ButtonFunctionProps, 'size' | 'disabled'>;
8
+ export declare function ResendCode(props: ResendCodeProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,28 @@
1
+ "use strict";
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)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.ResendCode = ResendCode;
15
+ const jsx_runtime_1 = require("react/jsx-runtime");
16
+ const uikit_product_icons_1 = require("@cloud-ru/uikit-product-icons");
17
+ const uikit_product_locale_1 = require("@cloud-ru/uikit-product-locale");
18
+ const button_1 = require("@snack-uikit/button");
19
+ const utils_1 = require("./utils");
20
+ function ResendCode(props) {
21
+ const { onResend, secondsToNextResend } = props, buttonProps = __rest(props, ["onResend", "secondsToNextResend"]);
22
+ const { t } = (0, uikit_product_locale_1.useLocale)('FieldsPredefined');
23
+ return ((0, jsx_runtime_1.jsx)(button_1.ButtonFunction, Object.assign({ label: secondsToNextResend > 0
24
+ ? t('FieldCode.resendCodeButtons.resendCodeWithVia', {
25
+ timer: (0, utils_1.formatSecondsAsMmSs)(secondsToNextResend),
26
+ })
27
+ : t('FieldCode.resendCodeButtons.resendCode'), onClick: onResend, icon: (0, jsx_runtime_1.jsx)(uikit_product_icons_1.UpdateSVG, {}), iconPosition: 'before' }, buttonProps)));
28
+ }
@@ -0,0 +1 @@
1
+ export * from './ResendCode';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./ResendCode"), exports);
@@ -0,0 +1 @@
1
+ export declare function formatSecondsAsMmSs(totalSeconds: number): string;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatSecondsAsMmSs = formatSecondsAsMmSs;
4
+ function formatSecondsAsMmSs(totalSeconds) {
5
+ const minutes = Math.floor(totalSeconds / 60);
6
+ const seconds = totalSeconds % 60;
7
+ return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
8
+ }
@@ -0,0 +1,2 @@
1
+ export * from './Cell';
2
+ export * from './ResendCode';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./Cell"), exports);
18
+ __exportStar(require("./ResendCode"), exports);
@@ -0,0 +1,14 @@
1
+ export declare const ZERO_WIDTH_SPACE = "\u200B";
2
+ /**
3
+ * Когда дергать `moveFocus` у `FieldCode` (массив `focusEffects`, порядок не важен).
4
+ * @see {@link FIELD_CODE_DEFAULT_FOCUS_EFFECTS}
5
+ */
6
+ export type FieldCodeFocusEffect =
7
+ /** После монтирования — ячейка `0`. */
8
+ 'firstCellOnMount'
9
+ /** После `ref.resetCode()` — ячейка `0`. */
10
+ | 'firstCellOnReset'
11
+ /** При включении `showEmptyChars` — первая пустая (все заполнены — последняя); не на каждый ввод. */
12
+ | 'firstCellWhenShowEmptyChars';
13
+ /** Дефолтный набор для `focusEffects`. */
14
+ export declare const FIELD_CODE_DEFAULT_FOCUS_EFFECTS: readonly FieldCodeFocusEffect[];
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FIELD_CODE_DEFAULT_FOCUS_EFFECTS = exports.ZERO_WIDTH_SPACE = void 0;
4
+ exports.ZERO_WIDTH_SPACE = '\u200B';
5
+ /** Дефолтный набор для `focusEffects`. */
6
+ exports.FIELD_CODE_DEFAULT_FOCUS_EFFECTS = [
7
+ 'firstCellOnMount',
8
+ 'firstCellOnReset',
9
+ 'firstCellWhenShowEmptyChars',
10
+ ];
@@ -0,0 +1,3 @@
1
+ export * from './useCodeInput';
2
+ export * from './useFocusCell';
3
+ export * from './useFieldHelpers';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./useCodeInput"), exports);
18
+ __exportStar(require("./useFocusCell"), exports);
19
+ __exportStar(require("./useFieldHelpers"), exports);
@@ -0,0 +1,22 @@
1
+ import { ClipboardEvent, KeyboardEvent } from 'react';
2
+ export type UseCodeInputParams = {
3
+ /** Количество цифр в коде */
4
+ codeLength: number;
5
+ /** Значение кода */
6
+ value?: string;
7
+ /** Колбек изменения значения */
8
+ onChange?: (code: string) => void;
9
+ /** Функция фокуса */
10
+ moveFocus: (index: number) => void;
11
+ /** Колбек достижения ввода всех символов кода */
12
+ onComplete?: (code: string) => void;
13
+ };
14
+ export declare function useCodeInput(params: UseCodeInputParams): {
15
+ code: string[];
16
+ cellHandlers: {
17
+ onKeyDown: (e: KeyboardEvent<HTMLInputElement>, index: number) => void;
18
+ onPaste: (e: ClipboardEvent<HTMLInputElement>) => void;
19
+ onChange: (code: string, index: number) => void;
20
+ };
21
+ onChangeCode: (value: any, ...args: any[]) => any | void;
22
+ };
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useCodeInput = useCodeInput;
4
+ const reactuse_1 = require("@siberiacancode/reactuse");
5
+ const react_1 = require("react");
6
+ const utils_1 = require("@snack-uikit/utils");
7
+ const constants_1 = require("../constants");
8
+ const utils_2 = require("../utils");
9
+ const buildCodeArray = (str, codeLength) => Array.from({ length: codeLength }, (_, idx) => str[idx] || constants_1.ZERO_WIDTH_SPACE);
10
+ function useCodeInput(params) {
11
+ const { value: valueProp, onChange: onChangeProp, codeLength, moveFocus, onComplete } = params;
12
+ const [value = '', onChange] = (0, utils_1.useValueControl)({
13
+ value: valueProp,
14
+ onChange: onChangeProp,
15
+ defaultValue: '',
16
+ });
17
+ const codeRef = (0, reactuse_1.useRefState)(buildCodeArray(value, codeLength));
18
+ const updateCodeByIndex = (0, react_1.useCallback)((index, newChar) => {
19
+ codeRef.current[index] = newChar;
20
+ onChange === null || onChange === void 0 ? void 0 : onChange(codeRef.current.join(''));
21
+ }, [codeRef, onChange]);
22
+ const updateFullCode = (0, react_1.useCallback)((newCode) => {
23
+ codeRef.current = newCode.split('');
24
+ onChange === null || onChange === void 0 ? void 0 : onChange(newCode);
25
+ moveFocus(codeLength - 1);
26
+ onComplete === null || onComplete === void 0 ? void 0 : onComplete(newCode);
27
+ }, [codeLength, codeRef, moveFocus, onChange, onComplete]);
28
+ const handleAfterCellUpdate = (0, react_1.useCallback)((index) => {
29
+ const normalizedCode = codeRef.current.join('');
30
+ const isLastInput = index === codeLength - 1;
31
+ const isAllInputsFilled = (0, utils_2.isStringCodeLength)(normalizedCode, codeLength);
32
+ if (!isLastInput) {
33
+ moveFocus(index + 1);
34
+ }
35
+ else if (isAllInputsFilled) {
36
+ onComplete === null || onComplete === void 0 ? void 0 : onComplete(normalizedCode);
37
+ }
38
+ }, [codeLength, codeRef, moveFocus, onComplete]);
39
+ const deleteChar = (0, react_1.useCallback)((index) => {
40
+ if (codeRef.current[index] && !(0, utils_2.isZeroWidthSpace)(codeRef.current[index])) {
41
+ updateCodeByIndex(index, constants_1.ZERO_WIDTH_SPACE);
42
+ }
43
+ else if (index > 0) {
44
+ moveFocus(index - 1);
45
+ }
46
+ }, [codeRef, moveFocus, updateCodeByIndex]);
47
+ const onAutoCompleteInput = (0, react_1.useCallback)((code, index) => {
48
+ if ((0, utils_2.isStringCodeLength)(code, codeLength)) {
49
+ updateFullCode(code);
50
+ return;
51
+ }
52
+ if (!(0, utils_2.isNumberChar)(code)) {
53
+ return;
54
+ }
55
+ updateCodeByIndex(index, code);
56
+ handleAfterCellUpdate(index);
57
+ }, [codeLength, handleAfterCellUpdate, updateCodeByIndex, updateFullCode]);
58
+ const onKeyDown = (0, react_1.useCallback)((e, index) => {
59
+ switch (e.key) {
60
+ case 'ArrowLeft':
61
+ moveFocus(index - 1);
62
+ break;
63
+ case 'ArrowRight':
64
+ moveFocus(index + 1);
65
+ break;
66
+ case 'Backspace':
67
+ deleteChar(index);
68
+ break;
69
+ default:
70
+ if ((0, utils_2.isNumberChar)(e.key)) {
71
+ e.preventDefault();
72
+ updateCodeByIndex(index, e.key);
73
+ handleAfterCellUpdate(index);
74
+ }
75
+ break;
76
+ }
77
+ }, [deleteChar, handleAfterCellUpdate, moveFocus, updateCodeByIndex]);
78
+ const onPaste = (0, react_1.useCallback)((e) => {
79
+ var _a;
80
+ const codeInput = (_a = e === null || e === void 0 ? void 0 : e.clipboardData.getData('text')) !== null && _a !== void 0 ? _a : '';
81
+ if (!(0, utils_2.isStringCodeLength)(codeInput, codeLength)) {
82
+ return;
83
+ }
84
+ updateFullCode(codeInput);
85
+ }, [codeLength, updateFullCode]);
86
+ (0, react_1.useEffect)(() => {
87
+ codeRef.current = buildCodeArray(value, codeLength);
88
+ }, [codeLength, codeRef, value]);
89
+ return {
90
+ code: codeRef.current,
91
+ cellHandlers: {
92
+ onKeyDown,
93
+ onPaste,
94
+ onChange: onAutoCompleteInput,
95
+ },
96
+ onChangeCode: onChange,
97
+ };
98
+ }
@@ -0,0 +1,13 @@
1
+ import { type FieldCodeFocusEffect } from '../constants';
2
+ type UseFieldHelpersParams = {
3
+ onChangeCode: (code: string) => void;
4
+ moveFocus: (index: number) => void;
5
+ focusEffects: readonly FieldCodeFocusEffect[];
6
+ showEmptyChars?: boolean;
7
+ code: readonly string[];
8
+ codeLength: number;
9
+ };
10
+ export declare function useFieldHelpers(params: UseFieldHelpersParams): {
11
+ resetCode: () => void;
12
+ };
13
+ export {};
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useFieldHelpers = useFieldHelpers;
4
+ const react_1 = require("react");
5
+ const utils_1 = require("../utils");
6
+ function useFieldHelpers(params) {
7
+ const { onChangeCode, moveFocus, focusEffects: focusEffectsProp, showEmptyChars, code, codeLength } = params;
8
+ const focusEffectsKey = [...focusEffectsProp].sort().join(',');
9
+ const focusEffects = (0, react_1.useMemo)(() => [...focusEffectsProp],
10
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11
+ [focusEffectsKey]);
12
+ const resetCode = (0, react_1.useCallback)(() => {
13
+ onChangeCode('');
14
+ if (focusEffects.includes('firstCellOnReset')) {
15
+ moveFocus(0);
16
+ }
17
+ }, [focusEffects, moveFocus, onChangeCode]);
18
+ (0, react_1.useEffect)(() => {
19
+ if (focusEffects.includes('firstCellOnMount')) {
20
+ moveFocus(0);
21
+ }
22
+ }, [focusEffects, moveFocus]);
23
+ (0, react_1.useEffect)(() => {
24
+ if (!focusEffects.includes('firstCellWhenShowEmptyChars') || !showEmptyChars) {
25
+ return;
26
+ }
27
+ const emptyIndex = (0, utils_1.getFirstEmptyCellIndex)(code);
28
+ if (emptyIndex >= 0) {
29
+ moveFocus(emptyIndex);
30
+ }
31
+ // eslint-disable-next-line react-hooks/exhaustive-deps
32
+ }, [showEmptyChars, focusEffects, moveFocus, codeLength]);
33
+ return { resetCode };
34
+ }
@@ -0,0 +1,5 @@
1
+ export declare function useFocusCell(codeLength: number): {
2
+ inputsRef: import("react").MutableRefObject<HTMLInputElement[]>;
3
+ moveFocus: (newIndex: number) => void;
4
+ blurFields: () => void;
5
+ };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useFocusCell = useFocusCell;
4
+ const react_1 = require("react");
5
+ function useFocusCell(codeLength) {
6
+ const inputsRef = (0, react_1.useRef)([]);
7
+ const focusInput = (0, react_1.useCallback)((index) => {
8
+ var _a;
9
+ (_a = inputsRef.current[index]) === null || _a === void 0 ? void 0 : _a.focus();
10
+ }, [inputsRef]);
11
+ const moveFocus = (0, react_1.useCallback)((newIndex) => {
12
+ if (newIndex >= 0 && newIndex < codeLength) {
13
+ focusInput(newIndex);
14
+ }
15
+ }, [codeLength, focusInput]);
16
+ const blurFields = (0, react_1.useCallback)(() => {
17
+ inputsRef.current.forEach(input => {
18
+ input === null || input === void 0 ? void 0 : input.blur();
19
+ });
20
+ }, [inputsRef]);
21
+ return { inputsRef, moveFocus, blurFields };
22
+ }
@@ -0,0 +1 @@
1
+ export * from './FieldCode';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./FieldCode"), exports);
@@ -0,0 +1,30 @@
1
+ .fieldCode{
2
+ display:flex;
3
+ flex-direction:column;
4
+ align-items:center;
5
+ gap:8px;
6
+ }
7
+
8
+ .codeContainer{
9
+ display:flex;
10
+ justify-content:center;
11
+ }
12
+ .codeContainer[data-size=s]{
13
+ gap:8px;
14
+ }
15
+ .codeContainer[data-size=m]{
16
+ gap:8px;
17
+ }
18
+ .codeContainer[data-size=l]{
19
+ gap:12px;
20
+ }
21
+
22
+ .cellSpacing[data-size=s]{
23
+ margin-right:2px;
24
+ }
25
+ .cellSpacing[data-size=m]{
26
+ margin-right:8px;
27
+ }
28
+ .cellSpacing[data-size=l]{
29
+ margin-right:12px;
30
+ }
@@ -0,0 +1,6 @@
1
+ import { FieldTextProps } from '@snack-uikit/fields';
2
+ export declare const isNumberChar: (char: string) => boolean;
3
+ export declare const isStringCodeLength: (input: string, codeLength: number) => boolean;
4
+ export declare const isZeroWidthSpace: (value: string) => value is "​";
5
+ export declare function getFirstEmptyCellIndex(code: readonly string[]): number;
6
+ export declare const getCellValidationState: (value: string, showEmptyChars?: boolean, error?: boolean) => FieldTextProps["validationState"];
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCellValidationState = exports.isZeroWidthSpace = exports.isStringCodeLength = exports.isNumberChar = void 0;
4
+ exports.getFirstEmptyCellIndex = getFirstEmptyCellIndex;
5
+ const constants_1 = require("./constants");
6
+ const isNumberChar = (char) => /^\d$/.test(char);
7
+ exports.isNumberChar = isNumberChar;
8
+ const isStringCodeLength = (input, codeLength) => new RegExp(`^\\d{${codeLength}}$`).test(input);
9
+ exports.isStringCodeLength = isStringCodeLength;
10
+ const isZeroWidthSpace = (value) => value === constants_1.ZERO_WIDTH_SPACE;
11
+ exports.isZeroWidthSpace = isZeroWidthSpace;
12
+ function getFirstEmptyCellIndex(code) {
13
+ return code.findIndex(exports.isZeroWidthSpace);
14
+ }
15
+ const getCellValidationState = (value, showEmptyChars, error) => {
16
+ if (showEmptyChars) {
17
+ return (0, exports.isZeroWidthSpace)(value) ? 'error' : 'default';
18
+ }
19
+ return error ? 'error' : 'default';
20
+ };
21
+ exports.getCellValidationState = getCellValidationState;
@@ -6,3 +6,4 @@ export * from './AIDisclaimer';
6
6
  export * from './FieldName';
7
7
  export * from './FieldDescription';
8
8
  export * from './FieldMask';
9
+ export * from './FieldCode';
@@ -22,3 +22,4 @@ __exportStar(require("./AIDisclaimer"), exports);
22
22
  __exportStar(require("./FieldName"), exports);
23
23
  __exportStar(require("./FieldDescription"), exports);
24
24
  __exportStar(require("./FieldMask"), exports);
25
+ __exportStar(require("./FieldCode"), exports);