@cloud-ru/uikit-product-fields-predefined 0.13.11 → 0.14.1

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 (86) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +161 -0
  3. package/dist/cjs/components/FieldAi/FieldAi.d.ts +2 -2
  4. package/dist/cjs/components/FieldAi/components/MobileFieldAi/MobileFieldAi.d.ts +1 -1
  5. package/dist/cjs/components/FieldDescription/FieldDescription.d.ts +12 -0
  6. package/dist/cjs/components/FieldDescription/FieldDescription.js +68 -0
  7. package/dist/cjs/components/FieldDescription/FieldDescriptionRHF.d.ts +11 -0
  8. package/dist/cjs/components/FieldDescription/FieldDescriptionRHF.js +62 -0
  9. package/dist/cjs/components/FieldDescription/components/FieldWithAddButton.d.ts +7 -0
  10. package/dist/cjs/components/FieldDescription/components/FieldWithAddButton.js +21 -0
  11. package/dist/cjs/components/FieldDescription/components/index.d.ts +1 -0
  12. package/dist/cjs/components/FieldDescription/components/index.js +5 -0
  13. package/dist/cjs/components/FieldDescription/constants.d.ts +1 -0
  14. package/dist/cjs/components/FieldDescription/constants.js +4 -0
  15. package/dist/cjs/components/FieldDescription/index.d.ts +3 -0
  16. package/dist/cjs/components/FieldDescription/index.js +7 -0
  17. package/dist/cjs/components/FieldDescription/types.d.ts +16 -0
  18. package/dist/cjs/components/FieldDescription/types.js +2 -0
  19. package/dist/cjs/components/FieldName/FieldName.d.ts +12 -0
  20. package/dist/cjs/components/FieldName/FieldName.js +95 -0
  21. package/dist/cjs/components/FieldName/FieldNameRHF.d.ts +11 -0
  22. package/dist/cjs/components/FieldName/FieldNameRHF.js +81 -0
  23. package/dist/cjs/components/FieldName/constants.d.ts +1 -0
  24. package/dist/cjs/components/FieldName/constants.js +4 -0
  25. package/dist/cjs/components/FieldName/index.d.ts +3 -0
  26. package/dist/cjs/components/FieldName/index.js +7 -0
  27. package/dist/cjs/components/FieldName/types.d.ts +15 -0
  28. package/dist/cjs/components/FieldName/types.js +2 -0
  29. package/dist/cjs/components/FieldPhone/FieldPhone.d.ts +1 -1
  30. package/dist/cjs/components/index.d.ts +2 -0
  31. package/dist/cjs/components/index.js +2 -0
  32. package/dist/cjs/hooks/index.d.ts +1 -0
  33. package/dist/cjs/hooks/index.js +1 -0
  34. package/dist/cjs/hooks/useCustomFieldValidation.d.ts +12 -0
  35. package/dist/cjs/hooks/useCustomFieldValidation.js +32 -0
  36. package/dist/esm/components/FieldAi/FieldAi.d.ts +2 -2
  37. package/dist/esm/components/FieldAi/components/MobileFieldAi/MobileFieldAi.d.ts +1 -1
  38. package/dist/esm/components/FieldDescription/FieldDescription.d.ts +12 -0
  39. package/dist/esm/components/FieldDescription/FieldDescription.js +62 -0
  40. package/dist/esm/components/FieldDescription/FieldDescriptionRHF.d.ts +11 -0
  41. package/dist/esm/components/FieldDescription/FieldDescriptionRHF.js +56 -0
  42. package/dist/esm/components/FieldDescription/components/FieldWithAddButton.d.ts +7 -0
  43. package/dist/esm/components/FieldDescription/components/FieldWithAddButton.js +18 -0
  44. package/dist/esm/components/FieldDescription/components/index.d.ts +1 -0
  45. package/dist/esm/components/FieldDescription/components/index.js +1 -0
  46. package/dist/esm/components/FieldDescription/constants.d.ts +1 -0
  47. package/dist/esm/components/FieldDescription/constants.js +1 -0
  48. package/dist/esm/components/FieldDescription/index.d.ts +3 -0
  49. package/dist/esm/components/FieldDescription/index.js +2 -0
  50. package/dist/esm/components/FieldDescription/types.d.ts +16 -0
  51. package/dist/esm/components/FieldDescription/types.js +1 -0
  52. package/dist/esm/components/FieldName/FieldName.d.ts +12 -0
  53. package/dist/esm/components/FieldName/FieldName.js +89 -0
  54. package/dist/esm/components/FieldName/FieldNameRHF.d.ts +11 -0
  55. package/dist/esm/components/FieldName/FieldNameRHF.js +75 -0
  56. package/dist/esm/components/FieldName/constants.d.ts +1 -0
  57. package/dist/esm/components/FieldName/constants.js +1 -0
  58. package/dist/esm/components/FieldName/index.d.ts +3 -0
  59. package/dist/esm/components/FieldName/index.js +2 -0
  60. package/dist/esm/components/FieldName/types.d.ts +15 -0
  61. package/dist/esm/components/FieldName/types.js +1 -0
  62. package/dist/esm/components/FieldPhone/FieldPhone.d.ts +1 -1
  63. package/dist/esm/components/index.d.ts +2 -0
  64. package/dist/esm/components/index.js +2 -0
  65. package/dist/esm/hooks/index.d.ts +1 -0
  66. package/dist/esm/hooks/index.js +1 -0
  67. package/dist/esm/hooks/useCustomFieldValidation.d.ts +12 -0
  68. package/dist/esm/hooks/useCustomFieldValidation.js +28 -0
  69. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  70. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  71. package/package.json +13 -11
  72. package/src/components/FieldDescription/FieldDescription.tsx +97 -0
  73. package/src/components/FieldDescription/FieldDescriptionRHF.tsx +93 -0
  74. package/src/components/FieldDescription/components/FieldWithAddButton.tsx +43 -0
  75. package/src/components/FieldDescription/components/index.ts +1 -0
  76. package/src/components/FieldDescription/constants.ts +1 -0
  77. package/src/components/FieldDescription/index.ts +3 -0
  78. package/src/components/FieldDescription/types.ts +23 -0
  79. package/src/components/FieldName/FieldName.tsx +125 -0
  80. package/src/components/FieldName/FieldNameRHF.tsx +112 -0
  81. package/src/components/FieldName/constants.ts +1 -0
  82. package/src/components/FieldName/index.ts +3 -0
  83. package/src/components/FieldName/types.ts +22 -0
  84. package/src/components/index.ts +2 -0
  85. package/src/hooks/index.ts +1 -0
  86. package/src/hooks/useCustomFieldValidation.ts +38 -0
@@ -0,0 +1,81 @@
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.FieldNameRHF = void 0;
18
+ const jsx_runtime_1 = require("react/jsx-runtime");
19
+ const merge_refs_1 = __importDefault(require("merge-refs"));
20
+ const react_1 = require("react");
21
+ const react_hook_form_1 = require("react-hook-form");
22
+ const yup_1 = require("yup");
23
+ const uikit_product_locale_1 = require("@cloud-ru/uikit-product-locale");
24
+ const uikit_product_mobile_fields_1 = require("@cloud-ru/uikit-product-mobile-fields");
25
+ const input_private_1 = require("@snack-uikit/input-private");
26
+ const hooks_1 = require("../../hooks");
27
+ const constants_1 = require("./constants");
28
+ /**
29
+ * Поле имя c оберткой для React Hook Form
30
+ */
31
+ exports.FieldNameRHF = (0, react_1.forwardRef)((props, ref) => {
32
+ const { t } = (0, uikit_product_locale_1.useLocale)('FieldsPredefined');
33
+ const { controllerProps, maxLength = constants_1.DEFAULT_MAX_NAME_LENGTH, required = true, customSchema, showLabel = true, size = 'm', allowMoreThanMaxLength = true, error: propError } = props, inputProps = __rest(props, ["controllerProps", "maxLength", "required", "customSchema", "showLabel", "size", "allowMoreThanMaxLength", "error"]);
34
+ const [isFocused, setIsFocused] = (0, react_1.useState)(false);
35
+ const { trigger } = (0, react_hook_form_1.useFormContext)();
36
+ const validationSchema = (0, react_1.useMemo)(() => {
37
+ let baseSchema = (0, yup_1.string)()
38
+ .test('maxLength', t('FieldName.maxSymbols', { max: maxLength }), value => {
39
+ if (!value)
40
+ return true;
41
+ return value.length <= maxLength;
42
+ })
43
+ .matches(/^[a-zA-Z0-9.\-_]*$/, {
44
+ message: t('FieldName.wrongSymbols'),
45
+ name: 'allowedSymbols',
46
+ excludeEmptyString: true,
47
+ });
48
+ if (customSchema) {
49
+ baseSchema = baseSchema.concat(customSchema);
50
+ }
51
+ return required ? baseSchema.required(t('FieldName.required')) : baseSchema;
52
+ }, [customSchema, maxLength, required, t]);
53
+ const { validateRHF } = (0, hooks_1.useCustomFieldValidation)({ schema: validationSchema });
54
+ const handleFocus = value => {
55
+ var _a;
56
+ setIsFocused(true);
57
+ (_a = inputProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(inputProps, value);
58
+ };
59
+ return ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, Object.assign({}, controllerProps, { rules: { validate: validateRHF }, render: ({ field: { value, ref: localRef, onBlur, onChange }, fieldState: { error } }) => {
60
+ var _a, _b;
61
+ const isRequiredError = Boolean(error && ((_a = error.message) === null || _a === void 0 ? void 0 : _a.match(t('FieldName.required'))));
62
+ const shouldShowCounter = error && (((_b = error.message) === null || _b === void 0 ? void 0 : _b.match(t('FieldName.maxSymbols', { max: maxLength }))) || isRequiredError);
63
+ // - Есть ошибка обязательного поля и поле не в фокусе
64
+ // - Или другая ошибка
65
+ // - Или принудительно показываем ошибку
66
+ const showError = error && ((isRequiredError && !isFocused) || !isRequiredError);
67
+ const errorMes = propError !== null && propError !== void 0 ? propError : error === null || error === void 0 ? void 0 : error.message;
68
+ const handleChange = (newValue) => {
69
+ var _a;
70
+ (_a = inputProps.onChange) === null || _a === void 0 ? void 0 : _a.call(inputProps, newValue);
71
+ onChange(newValue);
72
+ };
73
+ const handleBlur = value => {
74
+ var _a;
75
+ (0, input_private_1.runAfterRerender)(() => setIsFocused(false));
76
+ (_a = inputProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(inputProps, value);
77
+ onBlur();
78
+ };
79
+ return ((0, jsx_runtime_1.jsx)(uikit_product_mobile_fields_1.AdaptiveFieldText, Object.assign({}, inputProps, { inputMode: 'text', onClearButtonClick: () => trigger(controllerProps.name), allowMoreThanMaxLength: allowMoreThanMaxLength, ref: (0, merge_refs_1.default)(ref, localRef), value: value, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, validationState: showError ? 'error' : inputProps.validationState, hint: showError ? errorMes : undefined, maxLength: shouldShowCounter && showError ? maxLength : undefined, size: size, label: showLabel ? t('FieldName.label') : undefined, caption: !required ? t('FieldDescription.optional') : undefined })));
80
+ } })));
81
+ });
@@ -0,0 +1 @@
1
+ export declare const DEFAULT_MAX_NAME_LENGTH = 64;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_MAX_NAME_LENGTH = void 0;
4
+ exports.DEFAULT_MAX_NAME_LENGTH = 64;
@@ -0,0 +1,3 @@
1
+ export { FieldName } from './FieldName';
2
+ export { FieldNameRHF } from './FieldNameRHF';
3
+ export type { BaseFieldNameProps, FieldNameRHFProps, FieldNameProps } from './types';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FieldNameRHF = exports.FieldName = void 0;
4
+ var FieldName_1 = require("./FieldName");
5
+ Object.defineProperty(exports, "FieldName", { enumerable: true, get: function () { return FieldName_1.FieldName; } });
6
+ var FieldNameRHF_1 = require("./FieldNameRHF");
7
+ Object.defineProperty(exports, "FieldNameRHF", { enumerable: true, get: function () { return FieldNameRHF_1.FieldNameRHF; } });
@@ -0,0 +1,15 @@
1
+ import { ControllerProps, FieldValues } from 'react-hook-form';
2
+ import { StringSchema, ValidationError } from 'yup';
3
+ import { FieldTextProps } from '@cloud-ru/uikit-product-mobile-fields';
4
+ export type BaseFieldNameProps = Omit<FieldTextProps, 'placeholder' | 'label' | 'footer' | 'type' | 'inputMode' | 'caption' | 'hint'> & {
5
+ showLabel?: boolean;
6
+ customSchema?: StringSchema;
7
+ };
8
+ export type FieldNameProps = BaseFieldNameProps & {
9
+ /** Колбэк, вызываемый при изменении ошибки валидации */
10
+ onValidationError?: (error: ValidationError | null) => void;
11
+ };
12
+ export type FieldNameRHFProps = BaseFieldNameProps & {
13
+ /** Режим контроллера с использованием react-hook-form */
14
+ controllerProps: Omit<ControllerProps<FieldValues>, 'render' | 'rules' | 'disabled'>;
15
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -21,5 +21,5 @@ export declare const FieldPhone: import("react").ForwardRefExoticComponent<Omit<
21
21
  /** options — объект конфигурации для изменения стандартного списка стран */
22
22
  options?: CountrySettings;
23
23
  } & {
24
- layoutType: import("@cloud-ru/uikit-product-utils/.").LayoutType;
24
+ layoutType: import("@cloud-ru/uikit-product-utils").LayoutType;
25
25
  } & import("react").RefAttributes<HTMLInputElement>>;
@@ -3,3 +3,5 @@ export * from './SelectCreate';
3
3
  export * from './FieldAi';
4
4
  export * from './FieldChat';
5
5
  export * from './AIDisclaimer';
6
+ export * from './FieldName';
7
+ export * from './FieldDescription';
@@ -19,3 +19,5 @@ __exportStar(require("./SelectCreate"), exports);
19
19
  __exportStar(require("./FieldAi"), exports);
20
20
  __exportStar(require("./FieldChat"), exports);
21
21
  __exportStar(require("./AIDisclaimer"), exports);
22
+ __exportStar(require("./FieldName"), exports);
23
+ __exportStar(require("./FieldDescription"), exports);
@@ -1 +1,2 @@
1
1
  export * from './useOpen';
2
+ export * from './useCustomFieldValidation';
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./useOpen"), exports);
18
+ __exportStar(require("./useCustomFieldValidation"), exports);
@@ -0,0 +1,12 @@
1
+ import { AnySchema, ValidationError } from 'yup';
2
+ export type UseFieldValidationProps = {
3
+ schema: AnySchema;
4
+ };
5
+ export declare const useCustomFieldValidation: ({ schema }: UseFieldValidationProps) => {
6
+ validate: (value: string) => {
7
+ error: null;
8
+ } | {
9
+ error: ValidationError;
10
+ };
11
+ validateRHF: (value: string) => string | true | undefined;
12
+ };
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useCustomFieldValidation = void 0;
4
+ const react_1 = require("react");
5
+ const yup_1 = require("yup");
6
+ const useCustomFieldValidation = ({ schema }) => {
7
+ const validate = (0, react_1.useCallback)((value) => {
8
+ try {
9
+ schema.validateSync(value);
10
+ return { error: null };
11
+ }
12
+ catch (err) {
13
+ if (err instanceof yup_1.ValidationError) {
14
+ return { error: err };
15
+ }
16
+ return { error: null };
17
+ }
18
+ }, [schema]);
19
+ const validateRHF = (0, react_1.useCallback)((value) => {
20
+ try {
21
+ schema.validateSync(value);
22
+ return true;
23
+ }
24
+ catch (err) {
25
+ if (err instanceof yup_1.ValidationError)
26
+ return err.message;
27
+ return;
28
+ }
29
+ }, [schema]);
30
+ return { validate, validateRHF };
31
+ };
32
+ exports.useCustomFieldValidation = useCustomFieldValidation;
@@ -8,7 +8,7 @@ export type FieldAiProps = WithLayoutType<Omit<FieldTextAreaProps, 'placeholder'
8
8
  /** Действие при клике по кнопке сброса контекста */
9
9
  onResetContextClick?(): void;
10
10
  }>;
11
- export declare const FieldAi: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "size" | "placeholder" | "label" | "spellCheck" | "labelTooltip" | "required" | "footer"> & {
11
+ export declare const FieldAi: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "size" | "label" | "required" | "placeholder" | "spellCheck" | "labelTooltip" | "footer"> & {
12
12
  /** Режим ввода sensitive данных (пароля, API ключей, токенов, etc) */
13
13
  secure?: boolean | "password";
14
14
  /** Колбек действия при отправке */
@@ -16,5 +16,5 @@ export declare const FieldAi: import("react").ForwardRefExoticComponent<Omit<Fie
16
16
  /** Действие при клике по кнопке сброса контекста */
17
17
  onResetContextClick?(): void;
18
18
  } & {
19
- layoutType: import("@cloud-ru/uikit-product-utils/.").LayoutType;
19
+ layoutType: import("@cloud-ru/uikit-product-utils").LayoutType;
20
20
  } & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -1,5 +1,5 @@
1
1
  import { FieldTextAreaProps } from '@cloud-ru/uikit-product-mobile-fields';
2
- export declare const MobileFieldAi: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "size" | "placeholder" | "label" | "spellCheck" | "labelTooltip" | "required" | "footer"> & {
2
+ export declare const MobileFieldAi: import("react").ForwardRefExoticComponent<Omit<FieldTextAreaProps, "size" | "label" | "required" | "placeholder" | "spellCheck" | "labelTooltip" | "footer"> & {
3
3
  onSubmit(): void;
4
4
  submitEnabled: boolean;
5
5
  } & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,12 @@
1
+ import { ValidationError } from 'yup';
2
+ /**
3
+ * Поле описание c локальным стейтом и валидацией
4
+ */
5
+ export declare const FieldDescription: import("react").ForwardRefExoticComponent<Omit<import("@cloud-ru/uikit-product-mobile-fields").FieldTextAreaProps, "name" | "caption" | "label" | "hint" | "placeholder" | "inputMode" | "searchPlaceholder" | "footer"> & {
6
+ customSchema?: import("yup").StringSchema;
7
+ addButton?: boolean;
8
+ } & {
9
+ onValidationError?: (error: ValidationError | null) => void;
10
+ } & {
11
+ layoutType: import("@cloud-ru/uikit-product-utils").LayoutType;
12
+ } & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,62 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import mergeRefs from 'merge-refs';
14
+ import { forwardRef, useMemo, useRef, useState } from 'react';
15
+ import { string } from 'yup';
16
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
17
+ import { AdaptiveFieldTextArea } from '@cloud-ru/uikit-product-mobile-fields';
18
+ import { useCustomFieldValidation } from '../../hooks';
19
+ import { FieldWithAddButton } from './components';
20
+ import { DEFAULT_MAX_LENGTH } from './constants';
21
+ /**
22
+ * Поле описание c локальным стейтом и валидацией
23
+ */
24
+ export const FieldDescription = forwardRef((_a, ref) => {
25
+ var _b;
26
+ var { size = 'm', required = false, maxLength = DEFAULT_MAX_LENGTH, customSchema, resizable = true, addButton, onValidationError } = _a, props = __rest(_a, ["size", "required", "maxLength", "customSchema", "resizable", "addButton", "onValidationError"]);
27
+ const { t } = useLocale('FieldsPredefined');
28
+ const textareaRef = useRef(null);
29
+ const validationSchema = useMemo(() => {
30
+ let baseSchema = string()
31
+ .trim()
32
+ .max(maxLength, t('FieldDescription.maxSymbols', { max: maxLength }));
33
+ if (customSchema) {
34
+ baseSchema = baseSchema.concat(customSchema);
35
+ }
36
+ return required ? baseSchema.required(t('FieldDescription.required')) : baseSchema;
37
+ }, [customSchema, maxLength, required, t]);
38
+ const { validate } = useCustomFieldValidation({ schema: validationSchema });
39
+ const [value, setValue] = useState('');
40
+ const [error, setError] = useState(null);
41
+ const handleChange = (newValue) => {
42
+ var _a;
43
+ setValue(newValue);
44
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, newValue);
45
+ const result = validate(newValue);
46
+ setError(result.error);
47
+ onValidationError === null || onValidationError === void 0 ? void 0 : onValidationError(result.error);
48
+ };
49
+ const handleBlur = (newValue) => {
50
+ var _a;
51
+ (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, newValue);
52
+ const result = validate(value);
53
+ setError(result.error);
54
+ onValidationError === null || onValidationError === void 0 ? void 0 : onValidationError(result.error);
55
+ };
56
+ const errorMes = (_b = props.error) !== null && _b !== void 0 ? _b : error === null || error === void 0 ? void 0 : error.message;
57
+ const standaloneComponent = (_jsx(AdaptiveFieldTextArea, Object.assign({}, props, { resizable: resizable, label: t('FieldDescription.label'), inputMode: 'text', ref: mergeRefs(ref, textareaRef), size: size, maxLength: maxLength, value: value, onChange: handleChange, onBlur: handleBlur, validationState: errorMes ? 'error' : props.validationState, hint: errorMes, caption: !required ? t('FieldDescription.optional') : undefined })));
58
+ if (addButton && !required) {
59
+ return (_jsx(FieldWithAddButton, { autoFocusRef: textareaRef, size: size, children: standaloneComponent }));
60
+ }
61
+ return standaloneComponent;
62
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Поле описание c оберткой для React Hook Form
3
+ */
4
+ export declare const FieldDescriptionRHF: import("react").ForwardRefExoticComponent<Omit<import("@cloud-ru/uikit-product-mobile-fields").FieldTextAreaProps, "name" | "caption" | "label" | "hint" | "placeholder" | "inputMode" | "searchPlaceholder" | "footer"> & {
5
+ customSchema?: import("yup").StringSchema;
6
+ addButton?: boolean;
7
+ } & {
8
+ controllerProps: Omit<import("react-hook-form").ControllerProps<import("react-hook-form").FieldValues>, "render" | "rules" | "disabled">;
9
+ } & {
10
+ layoutType: import("@cloud-ru/uikit-product-utils").LayoutType;
11
+ } & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,56 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import mergeRefs from 'merge-refs';
14
+ import { forwardRef, useMemo, useRef } from 'react';
15
+ import { Controller } from 'react-hook-form';
16
+ import { string } from 'yup';
17
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
18
+ import { AdaptiveFieldTextArea } from '@cloud-ru/uikit-product-mobile-fields';
19
+ import { useCustomFieldValidation } from '../../hooks';
20
+ import { FieldWithAddButton } from './components/FieldWithAddButton';
21
+ import { DEFAULT_MAX_LENGTH } from './constants';
22
+ /**
23
+ * Поле описание c оберткой для React Hook Form
24
+ */
25
+ export const FieldDescriptionRHF = forwardRef((_a, ref) => {
26
+ var { controllerProps, customSchema, size = 'm', required = false, maxLength = DEFAULT_MAX_LENGTH, addButton, resizable = true } = _a, props = __rest(_a, ["controllerProps", "customSchema", "size", "required", "maxLength", "addButton", "resizable"]);
27
+ const { t } = useLocale('FieldsPredefined');
28
+ const textareaRef = useRef(null);
29
+ const validationSchema = useMemo(() => {
30
+ let baseSchema = string()
31
+ .trim()
32
+ .max(maxLength, t('FieldDescription.maxSymbols', { max: maxLength }));
33
+ if (customSchema) {
34
+ baseSchema = baseSchema.concat(customSchema);
35
+ }
36
+ return required ? baseSchema.required(t('FieldDescription.required')) : baseSchema;
37
+ }, [customSchema, maxLength, required, t]);
38
+ const { validateRHF } = useCustomFieldValidation({ schema: validationSchema });
39
+ const controllerComponent = (_jsx(Controller, Object.assign({}, controllerProps, { rules: { validate: validateRHF }, render: ({ field: { value, ref: localRef, onBlur, onChange }, fieldState: { error } }) => {
40
+ var _a;
41
+ const errorMes = (_a = props.error) !== null && _a !== void 0 ? _a : error === null || error === void 0 ? void 0 : error.message;
42
+ return (_jsx(AdaptiveFieldTextArea, Object.assign({}, props, { resizable: resizable, size: size, label: t('FieldDescription.label'), inputMode: 'text', ref: mergeRefs(ref, localRef, textareaRef), maxLength: maxLength, value: value, onChange: newValue => {
43
+ var _a;
44
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, newValue);
45
+ onChange(newValue);
46
+ }, onBlur: value => {
47
+ var _a;
48
+ (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, value);
49
+ onBlur();
50
+ }, validationState: errorMes ? 'error' : props.validationState, hint: errorMes, caption: !required ? t('FieldDescription.optional') : undefined })));
51
+ } })));
52
+ if (addButton && !required) {
53
+ return (_jsx(FieldWithAddButton, { autoFocusRef: textareaRef, size: size, children: controllerComponent }));
54
+ }
55
+ return controllerComponent;
56
+ });
@@ -0,0 +1,7 @@
1
+ import { RefObject } from 'react';
2
+ import { FieldTextAreaProps } from '@cloud-ru/uikit-product-mobile-fields';
3
+ export declare function FieldWithAddButton({ children, size, autoFocusRef, }: {
4
+ children: React.ReactNode;
5
+ size?: FieldTextAreaProps['size'];
6
+ autoFocusRef: RefObject<HTMLTextAreaElement | null>;
7
+ }): string | number | boolean | import("react/jsx-runtime").JSX.Element | Iterable<import("react").ReactNode> | null | undefined;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { PlusSVG } from '@cloud-ru/uikit-product-icons';
4
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
5
+ import { ButtonFunction } from '@snack-uikit/button';
6
+ export function FieldWithAddButton({ children, size, autoFocusRef, }) {
7
+ const { t } = useLocale('FieldsPredefined');
8
+ const [showField, setShowField] = useState(false);
9
+ useEffect(() => {
10
+ if (showField && autoFocusRef.current) {
11
+ autoFocusRef.current.focus();
12
+ }
13
+ }, [showField, autoFocusRef]);
14
+ if (showField) {
15
+ return children;
16
+ }
17
+ return (_jsx("div", { children: !showField && (_jsx(ButtonFunction, { icon: _jsx(PlusSVG, {}), iconPosition: 'before', label: t('FieldDescription.addButton'), onClick: () => setShowField(true), size: size })) }));
18
+ }
@@ -0,0 +1 @@
1
+ export { FieldWithAddButton } from './FieldWithAddButton';
@@ -0,0 +1 @@
1
+ export { FieldWithAddButton } from './FieldWithAddButton';
@@ -0,0 +1 @@
1
+ export declare const DEFAULT_MAX_LENGTH = 255;
@@ -0,0 +1 @@
1
+ export const DEFAULT_MAX_LENGTH = 255;
@@ -0,0 +1,3 @@
1
+ export { FieldDescription } from './FieldDescription';
2
+ export { FieldDescriptionRHF } from './FieldDescriptionRHF';
3
+ export type { FieldDescriptionProps, FieldDescriptionPropsBase, FieldDescriptionRHFProps } from './types';
@@ -0,0 +1,2 @@
1
+ export { FieldDescription } from './FieldDescription';
2
+ export { FieldDescriptionRHF } from './FieldDescriptionRHF';
@@ -0,0 +1,16 @@
1
+ import { ControllerProps, FieldValues } from 'react-hook-form';
2
+ import { StringSchema, ValidationError } from 'yup';
3
+ import { FieldTextAreaProps } from '@cloud-ru/uikit-product-mobile-fields';
4
+ export type FieldDescriptionPropsBase = Omit<FieldTextAreaProps, 'placeholder' | 'label' | 'footer' | 'searchPlaceholder' | 'hint' | 'inputMode' | 'caption' | 'name'> & {
5
+ customSchema?: StringSchema;
6
+ /** Поле появляется по кнопке "Добавить описание" (только для опционального поля) */
7
+ addButton?: boolean;
8
+ };
9
+ export type FieldDescriptionProps = FieldDescriptionPropsBase & {
10
+ /** Колбэк, вызываемый при изменении ошибки валидации (только в standalone режиме) */
11
+ onValidationError?: (error: ValidationError | null) => void;
12
+ };
13
+ export type FieldDescriptionRHFProps = FieldDescriptionPropsBase & {
14
+ /** Режим контроллера с использованием react-hook-form */
15
+ controllerProps: Omit<ControllerProps<FieldValues>, 'render' | 'rules' | 'disabled'>;
16
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import { ValidationError } from 'yup';
2
+ /**
3
+ * Поле имя c локальным стейтом и валидацией
4
+ */
5
+ export declare const FieldName: import("react").ForwardRefExoticComponent<Omit<import("@cloud-ru/uikit-product-mobile-fields").FieldTextProps, "type" | "caption" | "label" | "hint" | "placeholder" | "inputMode" | "footer"> & {
6
+ showLabel?: boolean;
7
+ customSchema?: import("yup").StringSchema;
8
+ } & {
9
+ onValidationError?: (error: ValidationError | null) => void;
10
+ } & {
11
+ layoutType: import("@cloud-ru/uikit-product-utils").LayoutType;
12
+ } & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,89 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import mergeRefs from 'merge-refs';
14
+ import { forwardRef, useMemo, useRef, useState } from 'react';
15
+ import { string } from 'yup';
16
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
17
+ import { AdaptiveFieldText } from '@cloud-ru/uikit-product-mobile-fields';
18
+ import { runAfterRerender } from '@snack-uikit/input-private';
19
+ import { useCustomFieldValidation } from '../../hooks';
20
+ import { DEFAULT_MAX_NAME_LENGTH } from './constants';
21
+ /**
22
+ * Поле имя c локальным стейтом и валидацией
23
+ */
24
+ export const FieldName = forwardRef((props, ref) => {
25
+ const { t } = useLocale('FieldsPredefined');
26
+ const { value: propValue = '', onChange: propOnChange, onBlur: propOnBlur, error: propError, maxLength = DEFAULT_MAX_NAME_LENGTH, required = true, customSchema, showLabel = true, allowMoreThanMaxLength = true, size = 'm' } = props, inputProps = __rest(props, ["value", "onChange", "onBlur", "error", "maxLength", "required", "customSchema", "showLabel", "allowMoreThanMaxLength", "size"]);
27
+ const [internalValue, setInternalValue] = useState(propValue);
28
+ const [validationError, setValidationError] = useState(null);
29
+ const [isFocused, setIsFocused] = useState(false);
30
+ const inputRef = useRef(null);
31
+ const validationSchema = useMemo(() => {
32
+ let baseSchema = string()
33
+ .test('maxLength', t('FieldName.maxSymbols', { max: maxLength }), value => {
34
+ if (!value)
35
+ return true;
36
+ return value.length <= maxLength;
37
+ })
38
+ .matches(/^[a-zA-Z0-9.\-_]*$/, {
39
+ message: t('FieldName.wrongSymbols'),
40
+ name: 'allowedSymbols',
41
+ excludeEmptyString: true,
42
+ });
43
+ if (customSchema) {
44
+ baseSchema = baseSchema.concat(customSchema);
45
+ }
46
+ return required ? baseSchema.required(t('FieldName.required')) : baseSchema;
47
+ }, [customSchema, maxLength, required, t]);
48
+ const { validate } = useCustomFieldValidation({ schema: validationSchema });
49
+ const currentValue = 'value' in props ? propValue : internalValue;
50
+ const currentError = propError || (validationError === null || validationError === void 0 ? void 0 : validationError.message);
51
+ const isRequiredError = currentError === null || currentError === void 0 ? void 0 : currentError.match(t('FieldName.required'));
52
+ const handleChange = (newValue) => {
53
+ const result = validate(newValue);
54
+ // Если была required-ошибка и пользователь начал ввод, очищаем ее
55
+ if (isRequiredError && !isFocused) {
56
+ setValidationError(null);
57
+ }
58
+ else if (result.error && result.error.message !== t('FieldName.required')) {
59
+ // Любую НЕ required ошибку показываем сразу
60
+ setValidationError(result.error);
61
+ }
62
+ else {
63
+ setValidationError(null);
64
+ }
65
+ setInternalValue(newValue);
66
+ propOnChange === null || propOnChange === void 0 ? void 0 : propOnChange(newValue);
67
+ };
68
+ const handleBlur = (e) => {
69
+ var _a;
70
+ runAfterRerender(() => setIsFocused(false));
71
+ const result = validate(currentValue);
72
+ setValidationError(result.error);
73
+ (_a = props.onValidationError) === null || _a === void 0 ? void 0 : _a.call(props, result.error);
74
+ propOnBlur === null || propOnBlur === void 0 ? void 0 : propOnBlur(e);
75
+ };
76
+ const handleFocus = () => {
77
+ setIsFocused(true);
78
+ };
79
+ const handleClear = () => {
80
+ var _a;
81
+ const result = validate('');
82
+ setValidationError(result.error);
83
+ (_a = props.onValidationError) === null || _a === void 0 ? void 0 : _a.call(props, result.error);
84
+ };
85
+ const shouldShowCounter = currentError && ((currentError === null || currentError === void 0 ? void 0 : currentError.match(t('FieldName.maxSymbols', { max: maxLength }))) || isRequiredError);
86
+ // Ошибка обязательного поля появляется после blur
87
+ const showError = currentError && ((isRequiredError && !isFocused) || !isRequiredError);
88
+ return (_jsx(AdaptiveFieldText, Object.assign({}, inputProps, { inputMode: 'text', onClearButtonClick: handleClear, allowMoreThanMaxLength: allowMoreThanMaxLength, ref: mergeRefs(ref, inputRef), value: currentValue, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, validationState: showError ? 'error' : inputProps.validationState, hint: showError ? currentError : undefined, maxLength: shouldShowCounter && showError ? maxLength : undefined, size: size, label: showLabel ? t('FieldName.label') : undefined, caption: !required ? t('FieldDescription.optional') : undefined })));
89
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Поле имя c оберткой для React Hook Form
3
+ */
4
+ export declare const FieldNameRHF: import("react").ForwardRefExoticComponent<Omit<import("@cloud-ru/uikit-product-mobile-fields").FieldTextProps, "type" | "caption" | "label" | "hint" | "placeholder" | "inputMode" | "footer"> & {
5
+ showLabel?: boolean;
6
+ customSchema?: import("yup").StringSchema;
7
+ } & {
8
+ controllerProps: Omit<import("react-hook-form").ControllerProps<import("react-hook-form").FieldValues>, "render" | "rules" | "disabled">;
9
+ } & {
10
+ layoutType: import("@cloud-ru/uikit-product-utils").LayoutType;
11
+ } & import("react").RefAttributes<HTMLInputElement>>;