@cloud-ru/uikit-product-fields-predefined 0.14.0 → 0.15.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.
- package/CHANGELOG.md +22 -0
- package/README.md +239 -3
- package/dist/cjs/components/FieldAi/FieldAi.js +26 -4
- package/dist/cjs/components/FieldAi/components/CheckItem/CheckItem.d.ts +2 -1
- package/dist/cjs/components/FieldAi/components/CheckItem/CheckItem.js +2 -2
- package/dist/cjs/components/FieldAi/components/CheckItem/styles.module.css +14 -0
- package/dist/cjs/components/FieldAi/components/PasswordValidation/PasswordValidation.d.ts +3 -2
- package/dist/cjs/components/FieldAi/components/PasswordValidation/PasswordValidation.js +2 -2
- package/dist/cjs/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.d.ts +3 -2
- package/dist/cjs/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.js +3 -3
- package/dist/cjs/components/FieldAi/utils.d.ts +1 -0
- package/dist/esm/components/FieldAi/FieldAi.js +27 -5
- package/dist/esm/components/FieldAi/components/CheckItem/CheckItem.d.ts +2 -1
- package/dist/esm/components/FieldAi/components/CheckItem/CheckItem.js +2 -2
- package/dist/esm/components/FieldAi/components/CheckItem/styles.module.css +14 -0
- package/dist/esm/components/FieldAi/components/PasswordValidation/PasswordValidation.d.ts +3 -2
- package/dist/esm/components/FieldAi/components/PasswordValidation/PasswordValidation.js +2 -2
- package/dist/esm/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.d.ts +3 -2
- package/dist/esm/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.js +3 -3
- package/dist/esm/components/FieldAi/utils.d.ts +1 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/components/FieldAi/FieldAi.tsx +36 -5
- package/src/components/FieldAi/components/CheckItem/CheckItem.tsx +3 -2
- package/src/components/FieldAi/components/CheckItem/styles.module.scss +16 -0
- package/src/components/FieldAi/components/PasswordValidation/PasswordValidation.tsx +9 -2
- package/src/components/FieldAi/components/WithPasswordValidation/WithPasswordValidation.tsx +15 -3
- package/src/components/FieldAi/utils.ts +2 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloud-ru/uikit-product-fields-predefined",
|
|
3
3
|
"title": "Fields Predefined",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.15.0",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"*.css",
|
|
7
7
|
"*.woff",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
},
|
|
33
33
|
"scripts": {},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@cloud-ru/uikit-product-icons": "16.0.
|
|
36
|
-
"@cloud-ru/uikit-product-mobile-dropdown": "0.9.
|
|
37
|
-
"@cloud-ru/uikit-product-mobile-fields": "0.12.
|
|
38
|
-
"@cloud-ru/uikit-product-mobile-modal": "0.9.
|
|
39
|
-
"@cloud-ru/uikit-product-mobile-tooltip": "0.5.
|
|
40
|
-
"@cloud-ru/uikit-product-utils": "8.0.
|
|
35
|
+
"@cloud-ru/uikit-product-icons": "16.0.1",
|
|
36
|
+
"@cloud-ru/uikit-product-mobile-dropdown": "0.9.29",
|
|
37
|
+
"@cloud-ru/uikit-product-mobile-fields": "0.12.1",
|
|
38
|
+
"@cloud-ru/uikit-product-mobile-modal": "0.9.26",
|
|
39
|
+
"@cloud-ru/uikit-product-mobile-tooltip": "0.5.2",
|
|
40
|
+
"@cloud-ru/uikit-product-utils": "8.0.2",
|
|
41
41
|
"@snack-uikit/attachment": "0.4.10",
|
|
42
42
|
"@snack-uikit/button": "0.19.16",
|
|
43
43
|
"@snack-uikit/drop-zone": "0.9.6",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"react-hook-form": ">=7.51.0",
|
|
62
62
|
"yup": ">=0.32.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "a8efe861f537e7d5b0bb7dbadff99c57fd612720"
|
|
65
65
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import cn from 'classnames';
|
|
2
|
-
import { forwardRef, KeyboardEventHandler, useMemo, useState } from 'react';
|
|
2
|
+
import { forwardRef, KeyboardEventHandler, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
4
|
import { EyeClosedSVG, EyeSVG } from '@cloud-ru/uikit-product-icons';
|
|
5
5
|
import { useLocale } from '@cloud-ru/uikit-product-locale';
|
|
@@ -19,7 +19,7 @@ import { AIDisclaimer } from '../AIDisclaimer/AIDisclaimer';
|
|
|
19
19
|
import { MobileFieldAi } from './components/MobileFieldAi';
|
|
20
20
|
import { WithPasswordValidation } from './components/WithPasswordValidation';
|
|
21
21
|
import styles from './styles.module.scss';
|
|
22
|
-
import { getValidationPassword } from './utils';
|
|
22
|
+
import { getValidationPassword, ValidationPasswordKey } from './utils';
|
|
23
23
|
|
|
24
24
|
export type FieldAiProps = WithLayoutType<
|
|
25
25
|
Omit<FieldTextAreaProps, 'placeholder' | 'labelTooltip' | 'label' | 'required' | 'size' | 'spellCheck' | 'footer'> & {
|
|
@@ -39,6 +39,8 @@ export const FieldAi = forwardRef<HTMLTextAreaElement, FieldAiProps>(
|
|
|
39
39
|
const isTouchDevice = isTouchDeviceHelper(layoutType);
|
|
40
40
|
|
|
41
41
|
const [isValueHidden, setIsValueHidden] = useState<boolean>(true);
|
|
42
|
+
const [animatedValidationKey, setAnimatedValidationKey] = useState<ValidationPasswordKey | null>(null);
|
|
43
|
+
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
|
42
44
|
|
|
43
45
|
const isValueValid = typeof value === 'string' && value.trim().length > 0;
|
|
44
46
|
const isPasswordMode = secure === 'password';
|
|
@@ -47,19 +49,47 @@ export const FieldAi = forwardRef<HTMLTextAreaElement, FieldAiProps>(
|
|
|
47
49
|
const isPasswordValid = isPasswordMode ? Object.values(passwordValidation).every(Boolean) : true;
|
|
48
50
|
const showPasswordError = !isPasswordValid && secure && value;
|
|
49
51
|
|
|
52
|
+
useEffect(
|
|
53
|
+
() => () => {
|
|
54
|
+
if (timerRef.current) {
|
|
55
|
+
clearTimeout(timerRef.current);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
[],
|
|
59
|
+
);
|
|
60
|
+
|
|
50
61
|
const handleSubmit = () => {
|
|
51
62
|
if (isValueValid && isPasswordValid) {
|
|
52
63
|
handleSubmitProp(value);
|
|
53
64
|
}
|
|
54
65
|
};
|
|
55
66
|
|
|
56
|
-
const
|
|
67
|
+
const triggerValidationHighlight = (key: ValidationPasswordKey) => {
|
|
68
|
+
setAnimatedValidationKey(key);
|
|
69
|
+
|
|
70
|
+
timerRef.current = setTimeout(() => {
|
|
71
|
+
setAnimatedValidationKey(null);
|
|
72
|
+
}, 1000);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = event => {
|
|
57
76
|
if (isTouchDevice) {
|
|
58
77
|
return;
|
|
59
78
|
}
|
|
60
79
|
|
|
61
|
-
if (
|
|
62
|
-
|
|
80
|
+
if (isPasswordMode && event.key.length === 1) {
|
|
81
|
+
const isLetter = /\p{L}/u.test(event.key);
|
|
82
|
+
const isLatinLetter = /^[a-zA-Z]$/.test(event.key);
|
|
83
|
+
|
|
84
|
+
if (isLetter && !isLatinLetter) {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
triggerValidationHighlight('onlyLatin');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
92
|
+
event.preventDefault();
|
|
63
93
|
|
|
64
94
|
if (!disabled) {
|
|
65
95
|
handleSubmit();
|
|
@@ -88,6 +118,7 @@ export const FieldAi = forwardRef<HTMLTextAreaElement, FieldAiProps>(
|
|
|
88
118
|
showValidation={isPasswordMode}
|
|
89
119
|
passwordValidation={passwordValidation}
|
|
90
120
|
layoutType={layoutType}
|
|
121
|
+
animatedKey={animatedValidationKey}
|
|
91
122
|
>
|
|
92
123
|
<AdaptiveFieldTextArea
|
|
93
124
|
{...props}
|
|
@@ -10,11 +10,12 @@ type CheckItemProps = WithLayoutType<{
|
|
|
10
10
|
label: string;
|
|
11
11
|
checked: boolean;
|
|
12
12
|
shouldHide?: boolean;
|
|
13
|
+
animated?: boolean;
|
|
13
14
|
}>;
|
|
14
15
|
|
|
15
16
|
const CHECKED_ITEM_DISAPPEAR_TIMEOUT = 500;
|
|
16
17
|
|
|
17
|
-
export function CheckItem({ label, checked, layoutType, shouldHide = false }: CheckItemProps) {
|
|
18
|
+
export function CheckItem({ label, checked, layoutType, shouldHide = false, animated = false }: CheckItemProps) {
|
|
18
19
|
const [visible, setVisible] = useState(checked);
|
|
19
20
|
|
|
20
21
|
useEffect(() => {
|
|
@@ -34,7 +35,7 @@ export function CheckItem({ label, checked, layoutType, shouldHide = false }: Ch
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
return (
|
|
37
|
-
<div className={styles.checkItem} data-layout-type={layoutType}>
|
|
38
|
+
<div className={styles.checkItem} data-layout-type={layoutType} data-animated={animated}>
|
|
38
39
|
<CheckSVG size={20} className={styles.icon} data-checked={checked} />
|
|
39
40
|
<Typography.SansBodyM className={styles.label} data-checked={checked}>
|
|
40
41
|
{label}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
@use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as ste;
|
|
2
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
|
+
|
|
3
15
|
.checkItem {
|
|
4
16
|
display: inline-flex;
|
|
5
17
|
gap: 10px;
|
|
@@ -8,6 +20,10 @@
|
|
|
8
20
|
&[data-layout-type='tablet'] {
|
|
9
21
|
gap: 8px;
|
|
10
22
|
}
|
|
23
|
+
|
|
24
|
+
&[data-animated='true'] {
|
|
25
|
+
animation: shake 0.5s ease-in-out;
|
|
26
|
+
}
|
|
11
27
|
}
|
|
12
28
|
|
|
13
29
|
.icon {
|
|
@@ -4,15 +4,16 @@ import { useLocale } from '@cloud-ru/uikit-product-locale';
|
|
|
4
4
|
import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
|
|
5
5
|
|
|
6
6
|
import { isTouchDevice as isTouchDeviceHelper } from '../../../../helpers';
|
|
7
|
-
import { ValidationPassword } from '../../utils';
|
|
7
|
+
import { ValidationPassword, ValidationPasswordKey } from '../../utils';
|
|
8
8
|
import { CheckItem } from '../CheckItem';
|
|
9
9
|
import styles from './styles.module.scss';
|
|
10
10
|
|
|
11
11
|
export type WithPasswordTooltipProps = WithLayoutType<{
|
|
12
12
|
passwordValidation: ValidationPassword;
|
|
13
|
+
animatedKey?: ValidationPasswordKey | null;
|
|
13
14
|
}>;
|
|
14
15
|
|
|
15
|
-
export function PasswordValidation({ passwordValidation, layoutType }: WithPasswordTooltipProps) {
|
|
16
|
+
export function PasswordValidation({ passwordValidation, layoutType, animatedKey }: WithPasswordTooltipProps) {
|
|
16
17
|
const { t } = useLocale('FieldsPredefined');
|
|
17
18
|
|
|
18
19
|
const allCriteriaMet = useMemo(() => Object.values(passwordValidation).every(item => item), [passwordValidation]);
|
|
@@ -41,36 +42,42 @@ export function PasswordValidation({ passwordValidation, layoutType }: WithPassw
|
|
|
41
42
|
label={t('FieldAi.secret.passwordTooltip.minLength')}
|
|
42
43
|
layoutType={layoutType}
|
|
43
44
|
shouldHide={isTouchDevice}
|
|
45
|
+
animated={animatedKey === 'minLength'}
|
|
44
46
|
/>
|
|
45
47
|
<CheckItem
|
|
46
48
|
checked={passwordValidation.onlyLatin}
|
|
47
49
|
label={t('FieldAi.secret.passwordTooltip.onlyLatin')}
|
|
48
50
|
layoutType={layoutType}
|
|
49
51
|
shouldHide={isTouchDevice}
|
|
52
|
+
animated={animatedKey === 'onlyLatin'}
|
|
50
53
|
/>
|
|
51
54
|
<CheckItem
|
|
52
55
|
checked={passwordValidation.hasLetterCases}
|
|
53
56
|
label={t('FieldAi.secret.passwordTooltip.hasLetterCases')}
|
|
54
57
|
layoutType={layoutType}
|
|
55
58
|
shouldHide={isTouchDevice}
|
|
59
|
+
animated={animatedKey === 'hasLetterCases'}
|
|
56
60
|
/>
|
|
57
61
|
<CheckItem
|
|
58
62
|
checked={passwordValidation.hasNumber}
|
|
59
63
|
label={t('FieldAi.secret.passwordTooltip.hasNumber')}
|
|
60
64
|
layoutType={layoutType}
|
|
61
65
|
shouldHide={isTouchDevice}
|
|
66
|
+
animated={animatedKey === 'hasNumber'}
|
|
62
67
|
/>
|
|
63
68
|
<CheckItem
|
|
64
69
|
checked={passwordValidation.hasSymbol}
|
|
65
70
|
label={t('FieldAi.secret.passwordTooltip.hasSymbol')}
|
|
66
71
|
layoutType={layoutType}
|
|
67
72
|
shouldHide={isTouchDevice}
|
|
73
|
+
animated={animatedKey === 'hasSymbol'}
|
|
68
74
|
/>
|
|
69
75
|
<CheckItem
|
|
70
76
|
checked={passwordValidation.noSpaces}
|
|
71
77
|
label={t('FieldAi.secret.passwordTooltip.noSpaces')}
|
|
72
78
|
layoutType={layoutType}
|
|
73
79
|
shouldHide={isTouchDevice}
|
|
80
|
+
animated={animatedKey === 'noSpaces'}
|
|
74
81
|
/>
|
|
75
82
|
</div>
|
|
76
83
|
</div>
|
|
@@ -4,7 +4,7 @@ import { AdaptiveTooltip } from '@cloud-ru/uikit-product-mobile-tooltip';
|
|
|
4
4
|
import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
|
|
5
5
|
|
|
6
6
|
import { isTouchDevice } from '../../../../helpers';
|
|
7
|
-
import { ValidationPassword } from '../../utils';
|
|
7
|
+
import { ValidationPassword, ValidationPasswordKey } from '../../utils';
|
|
8
8
|
import { PasswordValidation } from '../PasswordValidation';
|
|
9
9
|
import styles from './styles.module.scss';
|
|
10
10
|
|
|
@@ -12,6 +12,7 @@ export type WithPasswordTooltipProps = WithLayoutType<{
|
|
|
12
12
|
showValidation?: boolean;
|
|
13
13
|
children: ReactNode;
|
|
14
14
|
passwordValidation: ValidationPassword;
|
|
15
|
+
animatedKey?: ValidationPasswordKey | null;
|
|
15
16
|
}>;
|
|
16
17
|
|
|
17
18
|
export function WithPasswordValidation({
|
|
@@ -19,12 +20,17 @@ export function WithPasswordValidation({
|
|
|
19
20
|
passwordValidation,
|
|
20
21
|
layoutType,
|
|
21
22
|
children,
|
|
23
|
+
animatedKey,
|
|
22
24
|
}: WithPasswordTooltipProps) {
|
|
23
25
|
if (isTouchDevice(layoutType)) {
|
|
24
26
|
if (showValidation) {
|
|
25
27
|
return (
|
|
26
28
|
<div className={styles.validationContainer}>
|
|
27
|
-
<PasswordValidation
|
|
29
|
+
<PasswordValidation
|
|
30
|
+
passwordValidation={passwordValidation}
|
|
31
|
+
layoutType={layoutType}
|
|
32
|
+
animatedKey={animatedKey}
|
|
33
|
+
/>
|
|
28
34
|
|
|
29
35
|
{children}
|
|
30
36
|
</div>
|
|
@@ -39,7 +45,13 @@ export function WithPasswordValidation({
|
|
|
39
45
|
<AdaptiveTooltip
|
|
40
46
|
placement={'left-end'}
|
|
41
47
|
layoutType={layoutType}
|
|
42
|
-
tip={
|
|
48
|
+
tip={
|
|
49
|
+
<PasswordValidation
|
|
50
|
+
passwordValidation={passwordValidation}
|
|
51
|
+
layoutType={layoutType}
|
|
52
|
+
animatedKey={animatedKey}
|
|
53
|
+
/>
|
|
54
|
+
}
|
|
43
55
|
offset={8}
|
|
44
56
|
>
|
|
45
57
|
{children}
|