@cloud-ru/uikit-product-fields-predefined 2.4.6 → 2.4.8-preview-68cf2382.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 (106) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +12 -294
  3. package/dist/cjs/components/index.d.ts +0 -1
  4. package/dist/cjs/components/index.js +0 -1
  5. package/dist/esm/components/index.d.ts +0 -1
  6. package/dist/esm/components/index.js +0 -1
  7. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  8. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  9. package/package.json +5 -8
  10. package/src/components/index.ts +0 -1
  11. package/dist/cjs/components/FieldAi/FieldAi.d.ts +0 -24
  12. package/dist/cjs/components/FieldAi/FieldAi.js +0 -92
  13. package/dist/cjs/components/FieldAi/components/AlertButton/AlertButton.d.ts +0 -5
  14. package/dist/cjs/components/FieldAi/components/AlertButton/AlertButton.js +0 -12
  15. package/dist/cjs/components/FieldAi/components/AlertButton/index.d.ts +0 -1
  16. package/dist/cjs/components/FieldAi/components/AlertButton/index.js +0 -17
  17. package/dist/cjs/components/FieldAi/components/AlertButton/styles.module.css +0 -17
  18. package/dist/cjs/components/FieldAi/components/CheckItem/CheckItem.d.ts +0 -9
  19. package/dist/cjs/components/FieldAi/components/CheckItem/CheckItem.js +0 -28
  20. package/dist/cjs/components/FieldAi/components/CheckItem/index.d.ts +0 -1
  21. package/dist/cjs/components/FieldAi/components/CheckItem/index.js +0 -17
  22. package/dist/cjs/components/FieldAi/components/CheckItem/styles.module.css +0 -36
  23. package/dist/cjs/components/FieldAi/components/MobileFieldAi/MobileFieldAi.d.ts +0 -5
  24. package/dist/cjs/components/FieldAi/components/MobileFieldAi/MobileFieldAi.js +0 -31
  25. package/dist/cjs/components/FieldAi/components/MobileFieldAi/index.d.ts +0 -1
  26. package/dist/cjs/components/FieldAi/components/MobileFieldAi/index.js +0 -17
  27. package/dist/cjs/components/FieldAi/components/MobileFieldAi/styles.module.css +0 -78
  28. package/dist/cjs/components/FieldAi/components/PasswordValidation/PasswordValidation.d.ts +0 -7
  29. package/dist/cjs/components/FieldAi/components/PasswordValidation/PasswordValidation.js +0 -23
  30. package/dist/cjs/components/FieldAi/components/PasswordValidation/index.d.ts +0 -1
  31. package/dist/cjs/components/FieldAi/components/PasswordValidation/index.js +0 -17
  32. package/dist/cjs/components/FieldAi/components/PasswordValidation/styles.module.css +0 -36
  33. package/dist/cjs/components/FieldAi/components/TextArea/TextArea.d.ts +0 -39
  34. package/dist/cjs/components/FieldAi/components/TextArea/TextArea.js +0 -33
  35. package/dist/cjs/components/FieldAi/components/TextArea/index.d.ts +0 -1
  36. package/dist/cjs/components/FieldAi/components/TextArea/index.js +0 -17
  37. package/dist/cjs/components/FieldAi/components/TextArea/styles.module.css +0 -32
  38. package/dist/cjs/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.d.ts +0 -10
  39. package/dist/cjs/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.js +0 -23
  40. package/dist/cjs/components/FieldAi/components/WithPasswordValidation/index.d.ts +0 -1
  41. package/dist/cjs/components/FieldAi/components/WithPasswordValidation/index.js +0 -17
  42. package/dist/cjs/components/FieldAi/components/WithPasswordValidation/styles.module.css +0 -6
  43. package/dist/cjs/components/FieldAi/index.d.ts +0 -1
  44. package/dist/cjs/components/FieldAi/index.js +0 -17
  45. package/dist/cjs/components/FieldAi/styles.module.css +0 -61
  46. package/dist/cjs/components/FieldAi/utils.d.ts +0 -10
  47. package/dist/cjs/components/FieldAi/utils.js +0 -19
  48. package/dist/esm/components/FieldAi/FieldAi.d.ts +0 -24
  49. package/dist/esm/components/FieldAi/FieldAi.js +0 -86
  50. package/dist/esm/components/FieldAi/components/AlertButton/AlertButton.d.ts +0 -5
  51. package/dist/esm/components/FieldAi/components/AlertButton/AlertButton.js +0 -6
  52. package/dist/esm/components/FieldAi/components/AlertButton/index.d.ts +0 -1
  53. package/dist/esm/components/FieldAi/components/AlertButton/index.js +0 -1
  54. package/dist/esm/components/FieldAi/components/AlertButton/styles.module.css +0 -17
  55. package/dist/esm/components/FieldAi/components/CheckItem/CheckItem.d.ts +0 -9
  56. package/dist/esm/components/FieldAi/components/CheckItem/CheckItem.js +0 -22
  57. package/dist/esm/components/FieldAi/components/CheckItem/index.d.ts +0 -1
  58. package/dist/esm/components/FieldAi/components/CheckItem/index.js +0 -1
  59. package/dist/esm/components/FieldAi/components/CheckItem/styles.module.css +0 -36
  60. package/dist/esm/components/FieldAi/components/MobileFieldAi/MobileFieldAi.d.ts +0 -5
  61. package/dist/esm/components/FieldAi/components/MobileFieldAi/MobileFieldAi.js +0 -25
  62. package/dist/esm/components/FieldAi/components/MobileFieldAi/index.d.ts +0 -1
  63. package/dist/esm/components/FieldAi/components/MobileFieldAi/index.js +0 -1
  64. package/dist/esm/components/FieldAi/components/MobileFieldAi/styles.module.css +0 -78
  65. package/dist/esm/components/FieldAi/components/PasswordValidation/PasswordValidation.d.ts +0 -7
  66. package/dist/esm/components/FieldAi/components/PasswordValidation/PasswordValidation.js +0 -17
  67. package/dist/esm/components/FieldAi/components/PasswordValidation/index.d.ts +0 -1
  68. package/dist/esm/components/FieldAi/components/PasswordValidation/index.js +0 -1
  69. package/dist/esm/components/FieldAi/components/PasswordValidation/styles.module.css +0 -36
  70. package/dist/esm/components/FieldAi/components/TextArea/TextArea.d.ts +0 -39
  71. package/dist/esm/components/FieldAi/components/TextArea/TextArea.js +0 -27
  72. package/dist/esm/components/FieldAi/components/TextArea/index.d.ts +0 -1
  73. package/dist/esm/components/FieldAi/components/TextArea/index.js +0 -1
  74. package/dist/esm/components/FieldAi/components/TextArea/styles.module.css +0 -32
  75. package/dist/esm/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.d.ts +0 -10
  76. package/dist/esm/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.js +0 -17
  77. package/dist/esm/components/FieldAi/components/WithPasswordValidation/index.d.ts +0 -1
  78. package/dist/esm/components/FieldAi/components/WithPasswordValidation/index.js +0 -1
  79. package/dist/esm/components/FieldAi/components/WithPasswordValidation/styles.module.css +0 -6
  80. package/dist/esm/components/FieldAi/index.d.ts +0 -1
  81. package/dist/esm/components/FieldAi/index.js +0 -1
  82. package/dist/esm/components/FieldAi/styles.module.css +0 -61
  83. package/dist/esm/components/FieldAi/utils.d.ts +0 -10
  84. package/dist/esm/components/FieldAi/utils.js +0 -15
  85. package/src/components/FieldAi/FieldAi.tsx +0 -201
  86. package/src/components/FieldAi/components/AlertButton/AlertButton.tsx +0 -16
  87. package/src/components/FieldAi/components/AlertButton/index.ts +0 -1
  88. package/src/components/FieldAi/components/AlertButton/styles.module.scss +0 -20
  89. package/src/components/FieldAi/components/CheckItem/CheckItem.tsx +0 -45
  90. package/src/components/FieldAi/components/CheckItem/index.ts +0 -1
  91. package/src/components/FieldAi/components/CheckItem/styles.module.scss +0 -44
  92. package/src/components/FieldAi/components/MobileFieldAi/MobileFieldAi.tsx +0 -57
  93. package/src/components/FieldAi/components/MobileFieldAi/index.ts +0 -1
  94. package/src/components/FieldAi/components/MobileFieldAi/styles.module.scss +0 -90
  95. package/src/components/FieldAi/components/PasswordValidation/PasswordValidation.tsx +0 -85
  96. package/src/components/FieldAi/components/PasswordValidation/index.ts +0 -1
  97. package/src/components/FieldAi/components/PasswordValidation/styles.module.scss +0 -34
  98. package/src/components/FieldAi/components/TextArea/TextArea.tsx +0 -113
  99. package/src/components/FieldAi/components/TextArea/index.ts +0 -1
  100. package/src/components/FieldAi/components/TextArea/styles.module.scss +0 -35
  101. package/src/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.tsx +0 -63
  102. package/src/components/FieldAi/components/WithPasswordValidation/index.ts +0 -1
  103. package/src/components/FieldAi/components/WithPasswordValidation/styles.module.scss +0 -8
  104. package/src/components/FieldAi/index.ts +0 -1
  105. package/src/components/FieldAi/styles.module.scss +0 -85
  106. package/src/components/FieldAi/utils.ts +0 -27
@@ -1,36 +0,0 @@
1
- .tooltipText{
2
- display:flex;
3
- flex-direction:column;
4
- }
5
-
6
- .validationList{
7
- display:flex;
8
- flex-direction:column;
9
- gap:12px;
10
- }
11
-
12
- .validationItemsContainer{
13
- font-family:var(--sans-body-m-font-family, SB Sans Interface);
14
- font-weight:var(--sans-body-m-font-weight, Regular);
15
- line-height:var(--sans-body-m-line-height, 20px);
16
- font-size:var(--sans-body-m-font-size, 14px);
17
- letter-spacing:var(--sans-body-m-letter-spacing, 0.1px);
18
- paragraph-spacing:var(--sans-body-m-paragraph-spacing, 7.7px);
19
- color:var(--sys-neutral-text-main, #41424e);
20
- display:flex;
21
- flex-direction:column;
22
- gap:12px;
23
- }
24
- .validationItemsContainer[data-layout-type=mobile], .validationItemsContainer[data-layout-type=tablet]{
25
- gap:8px;
26
- font-family:var(--sans-body-s-font-family, SB Sans Interface);
27
- font-weight:var(--sans-body-s-font-weight, Regular);
28
- line-height:var(--sans-body-s-line-height, 16px);
29
- font-size:var(--sans-body-s-font-size, 12px);
30
- letter-spacing:var(--sans-body-s-letter-spacing, 0.1px);
31
- paragraph-spacing:var(--sans-body-s-paragraph-spacing, 6.6px);
32
- padding:8px 16px;
33
- }
34
- .validationItemsContainer[data-layout-type=mobile] .validationList, .validationItemsContainer[data-layout-type=tablet] .validationList{
35
- gap:2px;
36
- }
@@ -1,39 +0,0 @@
1
- import { ChangeEvent, FocusEventHandler, KeyboardEventHandler, RefAttributes } from 'react';
2
- import { InputPrivateProps } from '@snack-uikit/input-private';
3
- import { WithSupportProps } from '@snack-uikit/utils';
4
- export type TextAreaProps = RefAttributes<HTMLTextAreaElement> & WithSupportProps<{
5
- /** HTML-аттрибут name */
6
- name?: string;
7
- /** HTML-аттрибут value */
8
- value?: string;
9
- /** Колбек смены значения */
10
- onChange?(value: string, e: ChangeEvent<HTMLTextAreaElement>): void;
11
- /** HTML-аттрибут id */
12
- id?: string;
13
- className?: string;
14
- /** Плейсхолдер */
15
- placeholder?: string;
16
- /** Является ли поле доступным только на чтение */
17
- readonly?: boolean;
18
- /** Является ли поле деактивированным */
19
- disabled?: boolean;
20
- /** Включен ли автокомплит */
21
- autoComplete?: boolean;
22
- /** Максимальное кол-во символов */
23
- maxLength?: number;
24
- /** Колбек получения фокуса */
25
- onFocus?: FocusEventHandler<HTMLTextAreaElement>;
26
- /** Колбек потери фокуса */
27
- onBlur?: FocusEventHandler<HTMLTextAreaElement>;
28
- /** Колбек нажатия клавиши клавиатуры */
29
- onKeyDown?: KeyboardEventHandler<HTMLTextAreaElement>;
30
- /** HTML-аттрибут tab-index */
31
- tabIndex?: number;
32
- /** Минимальное кол-во строк, до которого размер поля может быть увеличен @default 3*/
33
- minRows?: number;
34
- /** Включение проверки орфографии @default true*/
35
- spellCheck?: boolean;
36
- /** Режим работы экранной клавиатуры */
37
- inputMode?: InputPrivateProps['inputMode'];
38
- }>;
39
- export declare const TextArea: import("react").ForwardRefExoticComponent<Omit<TextAreaProps, "ref"> & RefAttributes<HTMLTextAreaElement>>;
@@ -1,27 +0,0 @@
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 cn from 'classnames';
14
- import { forwardRef, useState, } from 'react';
15
- import TextareaAutosize from 'react-textarea-autosize';
16
- import { extractSupportProps, useLayoutEffect } from '@snack-uikit/utils';
17
- import styles from './styles.module.css';
18
- export const TextArea = forwardRef((_a, ref) => {
19
- var { name, value = '', onChange, placeholder, id, className, disabled = false, readonly = false, autoComplete = false, maxLength, onFocus, onBlur, onKeyDown, tabIndex, minRows = 3, spellCheck, inputMode } = _a, rest = __rest(_a, ["name", "value", "onChange", "placeholder", "id", "className", "disabled", "readonly", "autoComplete", "maxLength", "onFocus", "onBlur", "onKeyDown", "tabIndex", "minRows", "spellCheck", "inputMode"]);
20
- // fix of height on the initial render
21
- // see https://github.com/Andarist/react-textarea-autosize/issues/337#issuecomment-1024980737
22
- const [, setIsRerendered] = useState(false);
23
- useLayoutEffect(() => setIsRerendered(true), []);
24
- const onChangeHandler = e => onChange === null || onChange === void 0 ? void 0 : onChange(e.target.value, e);
25
- const stopPropagation = e => e.stopPropagation();
26
- return (_jsx(TextareaAutosize, Object.assign({ id: id, name: name, value: value, ref: ref, className: cn(className, styles.textarea), autoComplete: autoComplete ? 'on' : 'off', placeholder: placeholder, disabled: disabled, readOnly: readonly, maxLength: maxLength, onChange: onChangeHandler, onClick: stopPropagation, onFocus: onFocus, onBlur: onBlur, onKeyDown: onKeyDown, tabIndex: tabIndex, minRows: minRows, spellCheck: spellCheck, inputMode: inputMode }, extractSupportProps(rest))));
27
- });
@@ -1 +0,0 @@
1
- export * from './TextArea';
@@ -1 +0,0 @@
1
- export * from './TextArea';
@@ -1,32 +0,0 @@
1
- .textarea{
2
- resize:none;
3
- box-sizing:border-box;
4
- width:100%;
5
- max-width:100%;
6
- margin:0;
7
- padding:0;
8
- color:var(--sys-neutral-text-main, #41424e);
9
- background-color:transparent;
10
- border:none;
11
- border-radius:0;
12
- outline:0;
13
- }
14
- .textarea::-moz-placeholder{
15
- color:var(--sys-neutral-text-disabled, #aaaebd);
16
- }
17
- .textarea::placeholder{
18
- color:var(--sys-neutral-text-disabled, #aaaebd);
19
- }
20
- .textarea::-webkit-scrollbar{
21
- width:0;
22
- max-width:0;
23
- }
24
- .textarea:-moz-read-only{
25
- color:var(--sys-neutral-text-support, #6d707f);
26
- }
27
- .textarea:read-only{
28
- color:var(--sys-neutral-text-support, #6d707f);
29
- }
30
- .textarea[disabled]{
31
- color:var(--sys-neutral-text-disabled, #aaaebd);
32
- }
@@ -1,10 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
3
- import { ValidationPassword, ValidationPasswordKey } from '../../utils';
4
- export type WithPasswordTooltipProps = WithLayoutType<{
5
- showValidation?: boolean;
6
- children: ReactNode;
7
- passwordValidation: ValidationPassword;
8
- animatedKey?: ValidationPasswordKey | null;
9
- }>;
10
- export declare function WithPasswordValidation({ showValidation, passwordValidation, layoutType, children, animatedKey, }: WithPasswordTooltipProps): string | number | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | null | undefined;
@@ -1,17 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { AdaptiveTooltip } from '@cloud-ru/uikit-product-mobile-tooltip';
3
- import { isTouchDevice } from '../../../../helpers';
4
- import { PasswordValidation } from '../PasswordValidation';
5
- import styles from './styles.module.css';
6
- export function WithPasswordValidation({ showValidation, passwordValidation, layoutType, children, animatedKey, }) {
7
- if (isTouchDevice(layoutType)) {
8
- if (showValidation) {
9
- return (_jsxs("div", { className: styles.validationContainer, children: [_jsx(PasswordValidation, { passwordValidation: passwordValidation, layoutType: layoutType, animatedKey: animatedKey }), children] }));
10
- }
11
- return children;
12
- }
13
- if (showValidation) {
14
- return (_jsx(AdaptiveTooltip, { placement: 'left-end', layoutType: layoutType, tip: _jsx(PasswordValidation, { passwordValidation: passwordValidation, layoutType: layoutType, animatedKey: animatedKey }), offset: 8, children: children }));
15
- }
16
- return children;
17
- }
@@ -1 +0,0 @@
1
- export * from './WithPasswordValidation';
@@ -1 +0,0 @@
1
- export * from './WithPasswordValidation';
@@ -1,6 +0,0 @@
1
- .validationContainer{
2
- display:flex;
3
- flex-direction:column;
4
- gap:8px;
5
- background-color:var(--sys-neutral-background1-level, #fdfdfd);
6
- }
@@ -1 +0,0 @@
1
- export * from './FieldAi';
@@ -1 +0,0 @@
1
- export * from './FieldAi';
@@ -1,61 +0,0 @@
1
- .wrapper{
2
- display:flex;
3
- flex-direction:column;
4
- gap:var(--dimension-050m, 4px);
5
- position:relative;
6
- }
7
-
8
- .passwordWrapper{
9
- gap:0;
10
- }
11
-
12
- .alert{
13
- display:flex;
14
- gap:8px;
15
- padding:4px 8px;
16
- border-radius:8px 8px 0 0;
17
- border:1px solid var(--sys-blue-decor-activated, #aac4ea);
18
- background-color:var(--sys-blue-decor-default, #d6e2f4);
19
- box-sizing:border-box;
20
- height:38px;
21
- position:absolute;
22
- left:0;
23
- top:-26px;
24
- width:100%;
25
- color:var(--sys-neutral-text-main, #41424e);
26
- }
27
-
28
- .alertText{
29
- flex:1;
30
- min-width:0;
31
- color:var(--sys-neutral-text-main, #41424e);
32
- }
33
-
34
- .secured textarea{
35
- -webkit-text-security:disc;
36
- text-security:disc;
37
- }
38
-
39
- .mobileSubmitButton{
40
- position:relative !important;
41
- flex-shrink:0 !important;
42
- }
43
- .mobileSubmitButton:after{
44
- content:"";
45
- display:flex;
46
- width:48px;
47
- height:48px;
48
- position:absolute;
49
- top:50%;
50
- left:50%;
51
- transform:translate(-50%, -50%);
52
- }
53
-
54
- .submitButton:not([data-disabled]){
55
- background:radial-gradient(229.88% 112% at 37.5% 77.08%, #26D07C 19.86%, #5FD7C2 50.73%, #7CB5F2 89.88%);
56
- }
57
-
58
- .textarea > :first-child[data-validation=default]:not([data-readonly]):not([data-disable-focus]):focus-within:not([data-disabled]){
59
- border-color:transparent;
60
- background:linear-gradient(var(--sys-neutral-background2-level), var(--sys-neutral-background2-level) 0) padding-box, radial-gradient(57.79% 100% at 50% 0%, #7cb5f2 38%, #5fd7c2 79%, #26d07c 90%) border-box;
61
- }
@@ -1,10 +0,0 @@
1
- export type ValidationPassword = {
2
- onlyLatin: boolean;
3
- minLength: boolean;
4
- hasLetterCases: boolean;
5
- hasNumber: boolean;
6
- hasSymbol: boolean;
7
- noSpaces: boolean;
8
- };
9
- export type ValidationPasswordKey = keyof ValidationPassword;
10
- export declare const getValidationPassword: (password?: string) => ValidationPassword;
@@ -1,15 +0,0 @@
1
- const MIN_PASSWORD_LENGTH = 8;
2
- const NUMBER_REGEX = /[0-9]/;
3
- const CAPITAL_REGEX = /\p{Lu}/u;
4
- const LOWER_REGEX = /\p{Ll}/u;
5
- const SYMBOLS_REGEX = /[\p{P}\p{S}]/u;
6
- const NO_SPACES = /^\S*$/u;
7
- const LATIN_REGEX = /^[a-zA-Z0-9\p{P}\p{S}]+$/u;
8
- export const getValidationPassword = (password = '') => ({
9
- onlyLatin: Boolean(password.match(LATIN_REGEX)),
10
- minLength: password.length >= MIN_PASSWORD_LENGTH,
11
- hasLetterCases: Boolean(password.match(CAPITAL_REGEX)) && Boolean(password.match(LOWER_REGEX)),
12
- hasNumber: Boolean(password.match(NUMBER_REGEX)),
13
- hasSymbol: Boolean(password.match(SYMBOLS_REGEX)),
14
- noSpaces: Boolean(password.match(NO_SPACES)),
15
- });
@@ -1,201 +0,0 @@
1
- import cn from 'classnames';
2
- import { forwardRef, KeyboardEventHandler, useEffect, useMemo, useRef, useState } from 'react';
3
-
4
- import { EyeClosedSVG, EyeSVG, PasswordLockSVG } from '@cloud-ru/uikit-product-icons';
5
- import { useLocale } from '@cloud-ru/uikit-product-locale';
6
- import {
7
- AdaptiveFieldTextArea,
8
- FieldTextAreaProps,
9
- getAdaptiveFieldProps,
10
- } from '@cloud-ru/uikit-product-mobile-fields';
11
- import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
12
- import { ButtonFunction, ButtonOutline } from '@snack-uikit/button';
13
- import { themeVars } from '@snack-uikit/figma-tokens';
14
- import { Tooltip } from '@snack-uikit/tooltip';
15
- import { Typography } from '@snack-uikit/typography';
16
-
17
- import { FieldSubmitButton } from '../../helperComponents/FieldSubmitButton';
18
- import { TextAreaActionsFooter } from '../../helperComponents/TextAreaActionsFooter';
19
- import { isTouchDevice as isTouchDeviceHelper } from '../../helpers';
20
- import { AIDisclaimer } from '../AIDisclaimer/AIDisclaimer';
21
- import { AlertButton } from './components/AlertButton';
22
- import { MobileFieldAi } from './components/MobileFieldAi';
23
- import { WithPasswordValidation } from './components/WithPasswordValidation';
24
- import styles from './styles.module.scss';
25
- import { getValidationPassword, ValidationPasswordKey } from './utils';
26
-
27
- export type FieldAiProps = WithLayoutType<
28
- Omit<FieldTextAreaProps, 'placeholder' | 'labelTooltip' | 'label' | 'required' | 'size' | 'spellCheck' | 'footer'> & {
29
- /** Режим ввода sensitive данных (пароля, API ключей, токенов, etc) */
30
- secure?: boolean | 'password';
31
- /** Колбек действия при отправке */
32
- onSubmit(value: string): void;
33
- /** Действие при клике по кнопке сброса контекста */
34
- onResetContextClick?(): void;
35
- /** Действие для отмены секьюрности поля */
36
- onCancelSecure?(): void;
37
- }
38
- >;
39
-
40
- export const FieldAi = forwardRef<HTMLTextAreaElement, FieldAiProps>(
41
- (
42
- {
43
- secure = false,
44
- onSubmit: handleSubmitProp,
45
- value,
46
- onResetContextClick,
47
- onCancelSecure,
48
- disabled,
49
- className,
50
- ...props
51
- },
52
- ref,
53
- ) => {
54
- const { layoutType, validationState } = props;
55
- const { t } = useLocale('FieldsPredefined');
56
- const isTouchDevice = isTouchDeviceHelper(layoutType);
57
-
58
- const [isValueHidden, setIsValueHidden] = useState<boolean>(true);
59
- const [animatedValidationKey, setAnimatedValidationKey] = useState<ValidationPasswordKey | null>(null);
60
- const timerRef = useRef<NodeJS.Timeout | null>(null);
61
-
62
- const isValueValid = typeof value === 'string' && value.trim().length > 0;
63
- const isPasswordMode = secure === 'password';
64
-
65
- const passwordValidation = useMemo(() => getValidationPassword(value), [value]);
66
- const isPasswordValid = isPasswordMode ? Object.values(passwordValidation).every(Boolean) : true;
67
- const showPasswordError = !isPasswordValid && secure && value;
68
- const showPasswordAlert = Boolean(onCancelSecure) && secure === 'password';
69
-
70
- useEffect(
71
- () => () => {
72
- if (timerRef.current) {
73
- clearTimeout(timerRef.current);
74
- }
75
- },
76
- [],
77
- );
78
-
79
- const handleSubmit = () => {
80
- if (isValueValid && isPasswordValid) {
81
- handleSubmitProp(value);
82
- }
83
- };
84
-
85
- const triggerValidationHighlight = (key: ValidationPasswordKey) => {
86
- setAnimatedValidationKey(key);
87
-
88
- timerRef.current = setTimeout(() => {
89
- setAnimatedValidationKey(null);
90
- }, 1000);
91
- };
92
-
93
- const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = event => {
94
- if (isTouchDevice) {
95
- return;
96
- }
97
-
98
- if (isPasswordMode && event.key.length === 1) {
99
- const isLetter = /\p{L}/u.test(event.key);
100
- const isLatinLetter = /^[a-zA-Z]$/.test(event.key);
101
-
102
- if (isLetter && !isLatinLetter) {
103
- event.preventDefault();
104
- triggerValidationHighlight('onlyLatin');
105
- return;
106
- }
107
- }
108
-
109
- if (event.key === 'Enter' && !event.shiftKey) {
110
- event.preventDefault();
111
-
112
- if (!disabled) {
113
- handleSubmit();
114
- }
115
-
116
- return;
117
- }
118
- };
119
-
120
- if (isTouchDevice && !secure) {
121
- return (
122
- <MobileFieldAi
123
- {...props}
124
- {...getAdaptiveFieldProps(props)}
125
- onSubmit={handleSubmit}
126
- submitEnabled={isValueValid && !disabled}
127
- ref={ref}
128
- value={value}
129
- />
130
- );
131
- }
132
-
133
- return (
134
- <div className={cn(styles.wrapper, isPasswordMode && styles.passwordWrapper, className)}>
135
- {showPasswordAlert && (
136
- <div className={styles.alert}>
137
- <PasswordLockSVG size={16} color={themeVars.sys.neutral.textSupport} />
138
- <Typography.SansBodyS className={styles.alertText}>{t('FieldAi.secret.alert.text')}</Typography.SansBodyS>
139
- <AlertButton label={t('FieldAi.secret.alert.button')} onClick={onCancelSecure} />
140
- </div>
141
- )}
142
- <WithPasswordValidation
143
- showValidation={isPasswordMode}
144
- passwordValidation={passwordValidation}
145
- layoutType={layoutType}
146
- animatedKey={animatedValidationKey}
147
- >
148
- <AdaptiveFieldTextArea
149
- {...props}
150
- ref={ref}
151
- value={value}
152
- size='m'
153
- minRows={secure ? 1 : 2}
154
- maxRows={secure ? 1 : 4}
155
- placeholder={secure ? t('FieldAi.secret.placeholder') : t('FieldAi.regular.placeholder')}
156
- className={cn(styles.textarea, secure && isValueHidden ? styles.secured : undefined)}
157
- onKeyDown={handleKeyDown}
158
- spellCheck={!secure}
159
- validationState={showPasswordError ? 'error' : validationState}
160
- footer={
161
- <TextAreaActionsFooter
162
- left={
163
- secure && (
164
- <ButtonFunction
165
- size='xs'
166
- icon={isValueHidden ? <EyeSVG /> : <EyeClosedSVG />}
167
- onClick={() => setIsValueHidden(prev => !prev)}
168
- />
169
- )
170
- }
171
- right={
172
- <>
173
- {secure && onResetContextClick && (
174
- <Tooltip tip={t('FieldAi.resetContext.tooltip')} hoverDelayOpen={600}>
175
- <ButtonOutline
176
- size='xs'
177
- label={t('FieldAi.resetContext.label')}
178
- onClick={onResetContextClick}
179
- appearance='destructive'
180
- />
181
- </Tooltip>
182
- )}
183
- <FieldSubmitButton
184
- showTooltip={!isTouchDevice}
185
- className={cn(styles.submitButton, isTouchDevice ? styles.mobileSubmitButton : undefined)}
186
- active={isValueValid && !disabled && isPasswordValid}
187
- handleClick={handleSubmit}
188
- size={isTouchDevice ? 's' : 'xs'}
189
- />
190
- </>
191
- }
192
- />
193
- }
194
- />
195
- </WithPasswordValidation>
196
-
197
- {!isPasswordMode && <AIDisclaimer layoutType={layoutType} />}
198
- </div>
199
- );
200
- },
201
- );
@@ -1,16 +0,0 @@
1
- import { Typography } from '@snack-uikit/typography';
2
-
3
- import styles from './styles.module.scss';
4
-
5
- export type AlertButtonProps = {
6
- label: string;
7
- onClick?(): void;
8
- };
9
-
10
- export function AlertButton({ label, onClick }: AlertButtonProps) {
11
- return (
12
- <button onClick={onClick} className={styles.button}>
13
- <Typography.SansLabelM className={styles.label}>{label}</Typography.SansLabelM>
14
- </button>
15
- );
16
- }
@@ -1 +0,0 @@
1
- export * from './AlertButton';
@@ -1,20 +0,0 @@
1
- @use '@cloud-ru/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as stv;
2
-
3
- .button {
4
- outline: none;
5
- border: none;
6
- background-color: transparent;
7
- cursor: pointer;
8
- height: 16px;
9
- display: flex;
10
- align-items: center;
11
- justify-content: center;
12
- }
13
-
14
- .label {
15
- color: stv.$sys-blue-text-support;
16
-
17
- &:hover {
18
- color: stv.$sys-neutral-text-main;
19
- }
20
- }
@@ -1,45 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
-
3
- import { CheckSVG } from '@cloud-ru/uikit-product-icons';
4
- import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
5
- import { Typography } from '@snack-uikit/typography';
6
-
7
- import styles from './styles.module.scss';
8
-
9
- type CheckItemProps = WithLayoutType<{
10
- label: string;
11
- checked: boolean;
12
- shouldHide?: boolean;
13
- animated?: boolean;
14
- }>;
15
-
16
- const CHECKED_ITEM_DISAPPEAR_TIMEOUT = 500;
17
-
18
- export function CheckItem({ label, checked, layoutType, shouldHide = false, animated = false }: CheckItemProps) {
19
- const [visible, setVisible] = useState(checked);
20
-
21
- useEffect(() => {
22
- if (checked) {
23
- const timeoutId = setTimeout(() => {
24
- setVisible(false);
25
- }, CHECKED_ITEM_DISAPPEAR_TIMEOUT);
26
-
27
- return () => clearTimeout(timeoutId);
28
- }
29
-
30
- setVisible(true);
31
- }, [checked]);
32
-
33
- if (shouldHide && !visible) {
34
- return null;
35
- }
36
-
37
- return (
38
- <div className={styles.checkItem} data-layout-type={layoutType} data-animated={animated}>
39
- <CheckSVG size={16} className={styles.icon} data-checked={checked} />
40
- <Typography.SansBodyM className={styles.label} data-checked={checked}>
41
- {label}
42
- </Typography.SansBodyM>
43
- </div>
44
- );
45
- }
@@ -1 +0,0 @@
1
- export * from './CheckItem';
@@ -1,44 +0,0 @@
1
- @use '@cloud-ru/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as ste;
2
-
3
- @keyframes shake {
4
- 0%, 100% {
5
- transform: translateX(0);
6
- }
7
- 10%, 30%, 50%, 70%, 90% {
8
- transform: translateX(-4px);
9
- }
10
- 20%, 40%, 60%, 80% {
11
- transform: translateX(4px);
12
- }
13
- }
14
-
15
- .checkItem {
16
- display: inline-flex;
17
- gap: 10px;
18
-
19
- &[data-layout-type='mobile'],
20
- &[data-layout-type='tablet'] {
21
- gap: 8px;
22
- }
23
-
24
- &[data-animated='true'] {
25
- animation: shake 0.5s ease-in-out;
26
- }
27
- }
28
-
29
- .icon {
30
- flex-shrink: 0;
31
- color: ste.$sys-neutral-accent-default;
32
-
33
- &[data-checked='true'] {
34
- color: ste.$sys-primary-text-light;
35
- }
36
- }
37
-
38
- .label {
39
- color: ste.$sys-neutral-text-light;
40
-
41
- &[data-checked='true'] {
42
- color: ste.$sys-primary-text-light;
43
- }
44
- }