@rovula/ui 0.1.8 → 0.1.10
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/dist/cjs/bundle.css +0 -10
- package/dist/cjs/bundle.js +3 -3
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +4 -0
- package/dist/cjs/types/components/Form/ValidationHintList.d.ts +4 -1
- package/dist/cjs/types/components/InputFilter/InputFilter.stories.d.ts +4 -0
- package/dist/cjs/types/components/MaskedTextInput/MaskedTextInput.d.ts +4 -0
- package/dist/cjs/types/components/MaskedTextInput/MaskedTextInput.stories.d.ts +8 -0
- package/dist/cjs/types/components/PasswordInput/PasswordInput.stories.d.ts +4 -0
- package/dist/cjs/types/components/Search/Search.stories.d.ts +4 -0
- package/dist/cjs/types/components/TextArea/TextArea.d.ts +8 -0
- package/dist/cjs/types/components/TextArea/TextArea.stories.d.ts +4 -0
- package/dist/cjs/types/components/TextInput/TextInput.d.ts +8 -0
- package/dist/cjs/types/components/TextInput/TextInput.stories.d.ts +20 -0
- package/dist/components/Form/ValidationHintList.js +9 -9
- package/dist/components/OtpInput/OtpInput.js +1 -1
- package/dist/components/TextArea/TextArea.js +32 -3
- package/dist/components/TextArea/TextArea.stories.js +29 -0
- package/dist/components/TextInput/TextInput.js +38 -2
- package/dist/components/TextInput/TextInput.stories.js +28 -0
- package/dist/esm/bundle.css +0 -10
- package/dist/esm/bundle.js +2 -2
- package/dist/esm/bundle.js.map +1 -1
- package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +4 -0
- package/dist/esm/types/components/Form/ValidationHintList.d.ts +4 -1
- package/dist/esm/types/components/InputFilter/InputFilter.stories.d.ts +4 -0
- package/dist/esm/types/components/MaskedTextInput/MaskedTextInput.d.ts +4 -0
- package/dist/esm/types/components/MaskedTextInput/MaskedTextInput.stories.d.ts +8 -0
- package/dist/esm/types/components/PasswordInput/PasswordInput.stories.d.ts +4 -0
- package/dist/esm/types/components/Search/Search.stories.d.ts +4 -0
- package/dist/esm/types/components/TextArea/TextArea.d.ts +8 -0
- package/dist/esm/types/components/TextArea/TextArea.stories.d.ts +4 -0
- package/dist/esm/types/components/TextInput/TextInput.d.ts +8 -0
- package/dist/esm/types/components/TextInput/TextInput.stories.d.ts +20 -0
- package/dist/index.d.ts +24 -1
- package/dist/src/theme/global.css +0 -13
- package/package.json +1 -1
- package/src/components/Form/ValidationHintList.tsx +24 -11
- package/src/components/OtpInput/OtpInput.tsx +22 -9
- package/src/components/TextArea/TextArea.stories.tsx +108 -0
- package/src/components/TextArea/TextArea.tsx +52 -1
- package/src/components/TextInput/TextInput.stories.tsx +120 -5
- package/src/components/TextInput/TextInput.tsx +65 -0
|
@@ -82,6 +82,7 @@ declare const meta: {
|
|
|
82
82
|
width?: number | string | undefined | undefined;
|
|
83
83
|
role?: React.AriaRole | undefined;
|
|
84
84
|
tabIndex?: number | undefined | undefined;
|
|
85
|
+
format?: ((value: string) => string) | undefined;
|
|
85
86
|
"aria-activedescendant"?: string | undefined | undefined;
|
|
86
87
|
"aria-atomic"?: (boolean | "true" | "false") | undefined;
|
|
87
88
|
"aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined | undefined;
|
|
@@ -302,6 +303,7 @@ declare const meta: {
|
|
|
302
303
|
list?: string | undefined | undefined;
|
|
303
304
|
status?: "default" | "warning" | "error" | undefined;
|
|
304
305
|
step?: number | string | undefined | undefined;
|
|
306
|
+
normalize?: ((value: string) => string) | undefined;
|
|
305
307
|
warning?: boolean | undefined;
|
|
306
308
|
title?: string | undefined | undefined;
|
|
307
309
|
startIcon?: React.ReactNode;
|
|
@@ -382,6 +384,8 @@ declare const meta: {
|
|
|
382
384
|
onClickEndIcon?: (() => void) | undefined;
|
|
383
385
|
renderStartIcon?: (() => React.ReactNode) | undefined;
|
|
384
386
|
renderEndIcon?: (() => React.ReactNode) | undefined;
|
|
387
|
+
trimOnCommit?: boolean | undefined;
|
|
388
|
+
normalizeOnCommit?: ((value: string) => string) | undefined;
|
|
385
389
|
ref?: React.LegacyRef<HTMLInputElement> | undefined;
|
|
386
390
|
key?: React.Key | null | undefined;
|
|
387
391
|
}>) => import("react/jsx-runtime").JSX.Element)[];
|
|
@@ -6,12 +6,15 @@ export type ValidationHintRule<TValues> = {
|
|
|
6
6
|
validate: (values: TValues) => boolean;
|
|
7
7
|
when?: (values: TValues) => boolean;
|
|
8
8
|
};
|
|
9
|
+
export type ValidationHintStateClassMap = Partial<Record<ValidationHintState, string>>;
|
|
9
10
|
export type ValidationHintListProps<TValues> = {
|
|
10
11
|
values: TValues;
|
|
11
12
|
rules: ValidationHintRule<TValues>[];
|
|
12
13
|
mode?: ValidationHintMode;
|
|
13
14
|
className?: string;
|
|
14
15
|
itemClassName?: string;
|
|
16
|
+
labelStateClassName?: ValidationHintStateClassMap;
|
|
17
|
+
iconStateClassName?: ValidationHintStateClassMap;
|
|
15
18
|
};
|
|
16
|
-
export declare const ValidationHintList: <TValues>({ values, rules, mode, className, itemClassName, }: ValidationHintListProps<TValues>) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export declare const ValidationHintList: <TValues>({ values, rules, mode, className, itemClassName, labelStateClassName, iconStateClassName, }: ValidationHintListProps<TValues>) => import("react/jsx-runtime").JSX.Element;
|
|
17
20
|
export default ValidationHintList;
|
|
@@ -67,6 +67,7 @@ declare const meta: {
|
|
|
67
67
|
width?: number | string | undefined | undefined;
|
|
68
68
|
role?: React.AriaRole | undefined;
|
|
69
69
|
tabIndex?: number | undefined | undefined;
|
|
70
|
+
format?: ((value: string) => string) | undefined;
|
|
70
71
|
"aria-activedescendant"?: string | undefined | undefined;
|
|
71
72
|
"aria-atomic"?: (boolean | "true" | "false") | undefined;
|
|
72
73
|
"aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined | undefined;
|
|
@@ -287,6 +288,7 @@ declare const meta: {
|
|
|
287
288
|
list?: string | undefined | undefined;
|
|
288
289
|
status?: "default" | "warning" | "error" | undefined;
|
|
289
290
|
step?: number | string | undefined | undefined;
|
|
291
|
+
normalize?: ((value: string) => string) | undefined;
|
|
290
292
|
warning?: boolean | undefined;
|
|
291
293
|
title?: string | undefined | undefined;
|
|
292
294
|
startIcon?: React.ReactNode;
|
|
@@ -367,6 +369,8 @@ declare const meta: {
|
|
|
367
369
|
onClickEndIcon?: (() => void) | undefined;
|
|
368
370
|
renderStartIcon?: (() => React.ReactNode) | undefined;
|
|
369
371
|
renderEndIcon?: (() => React.ReactNode) | undefined;
|
|
372
|
+
trimOnCommit?: boolean | undefined;
|
|
373
|
+
normalizeOnCommit?: ((value: string) => string) | undefined;
|
|
370
374
|
ref?: React.LegacyRef<HTMLInputElement> | undefined;
|
|
371
375
|
key?: React.Key | null | undefined;
|
|
372
376
|
}>) => import("react/jsx-runtime").JSX.Element)[];
|
|
@@ -67,6 +67,10 @@ export declare const MaskedTextInput: React.ForwardRefExoticComponent<{
|
|
|
67
67
|
onClickEndIcon?: () => void;
|
|
68
68
|
renderStartIcon?: () => React.ReactNode;
|
|
69
69
|
renderEndIcon?: () => React.ReactNode;
|
|
70
|
+
normalize?: (value: string) => string;
|
|
71
|
+
format?: (value: string) => string;
|
|
72
|
+
trimOnCommit?: boolean;
|
|
73
|
+
normalizeOnCommit?: (value: string) => string;
|
|
70
74
|
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
71
75
|
mask?: string;
|
|
72
76
|
maskChar?: string;
|
|
@@ -38,6 +38,10 @@ declare const meta: {
|
|
|
38
38
|
onClickEndIcon?: () => void;
|
|
39
39
|
renderStartIcon?: () => React.ReactNode;
|
|
40
40
|
renderEndIcon?: () => React.ReactNode;
|
|
41
|
+
normalize?: (value: string) => string;
|
|
42
|
+
format?: (value: string) => string;
|
|
43
|
+
trimOnCommit?: boolean;
|
|
44
|
+
normalizeOnCommit?: (value: string) => string;
|
|
41
45
|
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
42
46
|
mask?: string;
|
|
43
47
|
maskChar?: string;
|
|
@@ -88,6 +92,10 @@ declare const meta: {
|
|
|
88
92
|
onClickEndIcon?: (() => void) | undefined;
|
|
89
93
|
renderStartIcon?: (() => React.ReactNode) | undefined;
|
|
90
94
|
renderEndIcon?: (() => React.ReactNode) | undefined;
|
|
95
|
+
normalize?: ((value: string) => string) | undefined;
|
|
96
|
+
format?: ((value: string) => string) | undefined;
|
|
97
|
+
trimOnCommit?: boolean | undefined;
|
|
98
|
+
normalizeOnCommit?: ((value: string) => string) | undefined;
|
|
91
99
|
suppressHydrationWarning?: boolean | undefined | undefined;
|
|
92
100
|
color?: string | undefined | undefined;
|
|
93
101
|
height?: number | string | undefined | undefined;
|
|
@@ -25,6 +25,7 @@ declare const meta: {
|
|
|
25
25
|
width?: number | string | undefined | undefined;
|
|
26
26
|
role?: React.AriaRole | undefined;
|
|
27
27
|
tabIndex?: number | undefined | undefined;
|
|
28
|
+
format?: ((value: string) => string) | undefined;
|
|
28
29
|
"aria-activedescendant"?: string | undefined | undefined;
|
|
29
30
|
"aria-atomic"?: (boolean | "true" | "false") | undefined;
|
|
30
31
|
"aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined | undefined;
|
|
@@ -246,6 +247,7 @@ declare const meta: {
|
|
|
246
247
|
list?: string | undefined | undefined;
|
|
247
248
|
status?: "default" | "warning" | "error" | undefined;
|
|
248
249
|
step?: number | string | undefined | undefined;
|
|
250
|
+
normalize?: ((value: string) => string) | undefined;
|
|
249
251
|
warning?: boolean | undefined;
|
|
250
252
|
error?: boolean | undefined;
|
|
251
253
|
size?: "sm" | "md" | "lg" | undefined;
|
|
@@ -336,6 +338,8 @@ declare const meta: {
|
|
|
336
338
|
onClickEndIcon?: (() => void) | undefined;
|
|
337
339
|
renderStartIcon?: (() => React.ReactNode) | undefined;
|
|
338
340
|
renderEndIcon?: (() => React.ReactNode) | undefined;
|
|
341
|
+
trimOnCommit?: boolean | undefined;
|
|
342
|
+
normalizeOnCommit?: ((value: string) => string) | undefined;
|
|
339
343
|
showToggle?: boolean | undefined;
|
|
340
344
|
hideIcon?: React.ReactNode;
|
|
341
345
|
showIcon?: React.ReactNode;
|
|
@@ -61,6 +61,7 @@ declare const meta: {
|
|
|
61
61
|
width?: number | string | undefined | undefined;
|
|
62
62
|
role?: React.AriaRole | undefined;
|
|
63
63
|
tabIndex?: number | undefined | undefined;
|
|
64
|
+
format?: ((value: string) => string) | undefined;
|
|
64
65
|
"aria-activedescendant"?: string | undefined | undefined;
|
|
65
66
|
"aria-atomic"?: (boolean | "true" | "false") | undefined;
|
|
66
67
|
"aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined | undefined;
|
|
@@ -281,6 +282,7 @@ declare const meta: {
|
|
|
281
282
|
list?: string | undefined | undefined;
|
|
282
283
|
status?: "default" | "warning" | "error" | undefined;
|
|
283
284
|
step?: number | string | undefined | undefined;
|
|
285
|
+
normalize?: ((value: string) => string) | undefined;
|
|
284
286
|
warning?: boolean | undefined;
|
|
285
287
|
title?: string | undefined | undefined;
|
|
286
288
|
startIcon?: React.ReactNode;
|
|
@@ -361,6 +363,8 @@ declare const meta: {
|
|
|
361
363
|
onClickEndIcon?: (() => void) | undefined;
|
|
362
364
|
renderStartIcon?: (() => React.ReactNode) | undefined;
|
|
363
365
|
renderEndIcon?: (() => React.ReactNode) | undefined;
|
|
366
|
+
trimOnCommit?: boolean | undefined;
|
|
367
|
+
normalizeOnCommit?: ((value: string) => string) | undefined;
|
|
364
368
|
ref?: React.LegacyRef<HTMLInputElement> | undefined;
|
|
365
369
|
key?: React.Key | null | undefined;
|
|
366
370
|
}>) => import("react/jsx-runtime").JSX.Element)[];
|
|
@@ -16,6 +16,10 @@ export type TextAreaProps = {
|
|
|
16
16
|
hasClearIcon?: boolean;
|
|
17
17
|
labelClassName?: string;
|
|
18
18
|
className?: string;
|
|
19
|
+
normalize?: (value: string) => string;
|
|
20
|
+
format?: (value: string) => string;
|
|
21
|
+
trimOnCommit?: boolean;
|
|
22
|
+
normalizeOnCommit?: (value: string) => string;
|
|
19
23
|
} & Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "size">;
|
|
20
24
|
export declare const TextArea: React.ForwardRefExoticComponent<{
|
|
21
25
|
id?: string;
|
|
@@ -34,5 +38,9 @@ export declare const TextArea: React.ForwardRefExoticComponent<{
|
|
|
34
38
|
hasClearIcon?: boolean;
|
|
35
39
|
labelClassName?: string;
|
|
36
40
|
className?: string;
|
|
41
|
+
normalize?: (value: string) => string;
|
|
42
|
+
format?: (value: string) => string;
|
|
43
|
+
trimOnCommit?: boolean;
|
|
44
|
+
normalizeOnCommit?: (value: string) => string;
|
|
37
45
|
} & Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "size"> & React.RefAttributes<HTMLTextAreaElement>>;
|
|
38
46
|
export default TextArea;
|
|
@@ -7,3 +7,7 @@ export declare const Default: Story;
|
|
|
7
7
|
export declare const ErrorState: Story;
|
|
8
8
|
export declare const HelperText: Story;
|
|
9
9
|
export declare const Disabled: Story;
|
|
10
|
+
export declare const Normalize: Story;
|
|
11
|
+
export declare const Format: Story;
|
|
12
|
+
export declare const TrimOnCommit: Story;
|
|
13
|
+
export declare const NormalizeOnCommit: Story;
|
|
@@ -36,6 +36,10 @@ export type InputProps = {
|
|
|
36
36
|
onClickEndIcon?: () => void;
|
|
37
37
|
renderStartIcon?: () => ReactNode;
|
|
38
38
|
renderEndIcon?: () => ReactNode;
|
|
39
|
+
normalize?: (value: string) => string;
|
|
40
|
+
format?: (value: string) => string;
|
|
41
|
+
trimOnCommit?: boolean;
|
|
42
|
+
normalizeOnCommit?: (value: string) => string;
|
|
39
43
|
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">;
|
|
40
44
|
export declare const TextInput: React.ForwardRefExoticComponent<{
|
|
41
45
|
id?: string;
|
|
@@ -74,5 +78,9 @@ export declare const TextInput: React.ForwardRefExoticComponent<{
|
|
|
74
78
|
onClickEndIcon?: () => void;
|
|
75
79
|
renderStartIcon?: () => ReactNode;
|
|
76
80
|
renderEndIcon?: () => ReactNode;
|
|
81
|
+
normalize?: (value: string) => string;
|
|
82
|
+
format?: (value: string) => string;
|
|
83
|
+
trimOnCommit?: boolean;
|
|
84
|
+
normalizeOnCommit?: (value: string) => string;
|
|
77
85
|
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & React.RefAttributes<HTMLInputElement>>;
|
|
78
86
|
export default TextInput;
|
|
@@ -38,6 +38,10 @@ declare const meta: {
|
|
|
38
38
|
onClickEndIcon?: () => void;
|
|
39
39
|
renderStartIcon?: () => React.ReactNode;
|
|
40
40
|
renderEndIcon?: () => React.ReactNode;
|
|
41
|
+
normalize?: (value: string) => string;
|
|
42
|
+
format?: (value: string) => string;
|
|
43
|
+
trimOnCommit?: boolean;
|
|
44
|
+
normalizeOnCommit?: (value: string) => string;
|
|
41
45
|
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & React.RefAttributes<HTMLInputElement>>;
|
|
42
46
|
tags: string[];
|
|
43
47
|
parameters: {
|
|
@@ -80,6 +84,10 @@ declare const meta: {
|
|
|
80
84
|
onClickEndIcon?: (() => void) | undefined;
|
|
81
85
|
renderStartIcon?: (() => React.ReactNode) | undefined;
|
|
82
86
|
renderEndIcon?: (() => React.ReactNode) | undefined;
|
|
87
|
+
normalize?: ((value: string) => string) | undefined;
|
|
88
|
+
format?: ((value: string) => string) | undefined;
|
|
89
|
+
trimOnCommit?: boolean | undefined;
|
|
90
|
+
normalizeOnCommit?: ((value: string) => string) | undefined;
|
|
83
91
|
suppressHydrationWarning?: boolean | undefined | undefined;
|
|
84
92
|
color?: string | undefined | undefined;
|
|
85
93
|
height?: number | string | undefined | undefined;
|
|
@@ -415,3 +423,15 @@ export declare const KeepFooterSpace: {
|
|
|
415
423
|
export declare const FeedbackApiCompatibility: {
|
|
416
424
|
render: () => import("react/jsx-runtime").JSX.Element;
|
|
417
425
|
};
|
|
426
|
+
export declare const Normalize: {
|
|
427
|
+
render: () => import("react/jsx-runtime").JSX.Element;
|
|
428
|
+
};
|
|
429
|
+
export declare const Format: {
|
|
430
|
+
render: () => import("react/jsx-runtime").JSX.Element;
|
|
431
|
+
};
|
|
432
|
+
export declare const TrimOnCommit: {
|
|
433
|
+
render: () => import("react/jsx-runtime").JSX.Element;
|
|
434
|
+
};
|
|
435
|
+
export declare const NormalizeOnCommit: {
|
|
436
|
+
render: () => import("react/jsx-runtime").JSX.Element;
|
|
437
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -85,6 +85,10 @@ type InputProps = {
|
|
|
85
85
|
onClickEndIcon?: () => void;
|
|
86
86
|
renderStartIcon?: () => ReactNode;
|
|
87
87
|
renderEndIcon?: () => ReactNode;
|
|
88
|
+
normalize?: (value: string) => string;
|
|
89
|
+
format?: (value: string) => string;
|
|
90
|
+
trimOnCommit?: boolean;
|
|
91
|
+
normalizeOnCommit?: (value: string) => string;
|
|
88
92
|
} & Omit<React__default.InputHTMLAttributes<HTMLInputElement>, "size">;
|
|
89
93
|
declare const TextInput: React__default.ForwardRefExoticComponent<{
|
|
90
94
|
id?: string;
|
|
@@ -123,6 +127,10 @@ declare const TextInput: React__default.ForwardRefExoticComponent<{
|
|
|
123
127
|
onClickEndIcon?: () => void;
|
|
124
128
|
renderStartIcon?: () => ReactNode;
|
|
125
129
|
renderEndIcon?: () => ReactNode;
|
|
130
|
+
normalize?: (value: string) => string;
|
|
131
|
+
format?: (value: string) => string;
|
|
132
|
+
trimOnCommit?: boolean;
|
|
133
|
+
normalizeOnCommit?: (value: string) => string;
|
|
126
134
|
} & Omit<React__default.InputHTMLAttributes<HTMLInputElement>, "size"> & React__default.RefAttributes<HTMLInputElement>>;
|
|
127
135
|
|
|
128
136
|
type MaskRule = {
|
|
@@ -177,6 +185,10 @@ declare const MaskedTextInput: React__default.ForwardRefExoticComponent<{
|
|
|
177
185
|
onClickEndIcon?: () => void;
|
|
178
186
|
renderStartIcon?: () => React__default.ReactNode;
|
|
179
187
|
renderEndIcon?: () => React__default.ReactNode;
|
|
188
|
+
normalize?: (value: string) => string;
|
|
189
|
+
format?: (value: string) => string;
|
|
190
|
+
trimOnCommit?: boolean;
|
|
191
|
+
normalizeOnCommit?: (value: string) => string;
|
|
180
192
|
} & Omit<React__default.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
181
193
|
mask?: string;
|
|
182
194
|
maskChar?: string;
|
|
@@ -258,6 +270,10 @@ type TextAreaProps = {
|
|
|
258
270
|
hasClearIcon?: boolean;
|
|
259
271
|
labelClassName?: string;
|
|
260
272
|
className?: string;
|
|
273
|
+
normalize?: (value: string) => string;
|
|
274
|
+
format?: (value: string) => string;
|
|
275
|
+
trimOnCommit?: boolean;
|
|
276
|
+
normalizeOnCommit?: (value: string) => string;
|
|
261
277
|
} & Omit<React__default.TextareaHTMLAttributes<HTMLTextAreaElement>, "size">;
|
|
262
278
|
declare const TextArea: React__default.ForwardRefExoticComponent<{
|
|
263
279
|
id?: string;
|
|
@@ -276,6 +292,10 @@ declare const TextArea: React__default.ForwardRefExoticComponent<{
|
|
|
276
292
|
hasClearIcon?: boolean;
|
|
277
293
|
labelClassName?: string;
|
|
278
294
|
className?: string;
|
|
295
|
+
normalize?: (value: string) => string;
|
|
296
|
+
format?: (value: string) => string;
|
|
297
|
+
trimOnCommit?: boolean;
|
|
298
|
+
normalizeOnCommit?: (value: string) => string;
|
|
279
299
|
} & Omit<React__default.TextareaHTMLAttributes<HTMLTextAreaElement>, "size"> & React__default.RefAttributes<HTMLTextAreaElement>>;
|
|
280
300
|
|
|
281
301
|
type TextProps = {
|
|
@@ -1230,14 +1250,17 @@ type ValidationHintRule<TValues> = {
|
|
|
1230
1250
|
validate: (values: TValues) => boolean;
|
|
1231
1251
|
when?: (values: TValues) => boolean;
|
|
1232
1252
|
};
|
|
1253
|
+
type ValidationHintStateClassMap = Partial<Record<ValidationHintState, string>>;
|
|
1233
1254
|
type ValidationHintListProps<TValues> = {
|
|
1234
1255
|
values: TValues;
|
|
1235
1256
|
rules: ValidationHintRule<TValues>[];
|
|
1236
1257
|
mode?: ValidationHintMode;
|
|
1237
1258
|
className?: string;
|
|
1238
1259
|
itemClassName?: string;
|
|
1260
|
+
labelStateClassName?: ValidationHintStateClassMap;
|
|
1261
|
+
iconStateClassName?: ValidationHintStateClassMap;
|
|
1239
1262
|
};
|
|
1240
|
-
declare const ValidationHintList: <TValues>({ values, rules, mode, className, itemClassName, }: ValidationHintListProps<TValues>) => react_jsx_runtime.JSX.Element;
|
|
1263
|
+
declare const ValidationHintList: <TValues>({ values, rules, mode, className, itemClassName, labelStateClassName, iconStateClassName, }: ValidationHintListProps<TValues>) => react_jsx_runtime.JSX.Element;
|
|
1241
1264
|
|
|
1242
1265
|
type OptionValue = string | number;
|
|
1243
1266
|
type OptionLike<TValue extends OptionValue = string> = {
|
|
@@ -7889,11 +7889,6 @@ input[type=number] {
|
|
|
7889
7889
|
color: color-mix(in srgb, var(--text-g-contrast-medium) calc(100% * var(--tw-text-opacity, 1)), transparent);
|
|
7890
7890
|
}
|
|
7891
7891
|
|
|
7892
|
-
.text-text-white {
|
|
7893
|
-
--tw-text-opacity: 1;
|
|
7894
|
-
color: color-mix(in srgb, var(--text-white) calc(100% * var(--tw-text-opacity, 1)), transparent);
|
|
7895
|
-
}
|
|
7896
|
-
|
|
7897
7892
|
.text-warning {
|
|
7898
7893
|
--tw-text-opacity: 1;
|
|
7899
7894
|
color: color-mix(in srgb, var(--state-warning-default) calc(100% * var(--tw-text-opacity, 1)), transparent);
|
|
@@ -7920,14 +7915,6 @@ input[type=number] {
|
|
|
7920
7915
|
opacity: 0;
|
|
7921
7916
|
}
|
|
7922
7917
|
|
|
7923
|
-
.opacity-100 {
|
|
7924
|
-
opacity: 1;
|
|
7925
|
-
}
|
|
7926
|
-
|
|
7927
|
-
.opacity-40 {
|
|
7928
|
-
opacity: 0.4;
|
|
7929
|
-
}
|
|
7930
|
-
|
|
7931
7918
|
.opacity-50 {
|
|
7932
7919
|
opacity: 0.5;
|
|
7933
7920
|
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { CircleCheck } from "lucide-react";
|
|
3
3
|
import { cn } from "@/utils/cn";
|
|
4
4
|
|
|
5
5
|
export type ValidationHintState = "pending" | "valid" | "invalid";
|
|
@@ -12,12 +12,18 @@ export type ValidationHintRule<TValues> = {
|
|
|
12
12
|
when?: (values: TValues) => boolean;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
export type ValidationHintStateClassMap = Partial<
|
|
16
|
+
Record<ValidationHintState, string>
|
|
17
|
+
>;
|
|
18
|
+
|
|
15
19
|
export type ValidationHintListProps<TValues> = {
|
|
16
20
|
values: TValues;
|
|
17
21
|
rules: ValidationHintRule<TValues>[];
|
|
18
22
|
mode?: ValidationHintMode;
|
|
19
23
|
className?: string;
|
|
20
24
|
itemClassName?: string;
|
|
25
|
+
labelStateClassName?: ValidationHintStateClassMap;
|
|
26
|
+
iconStateClassName?: ValidationHintStateClassMap;
|
|
21
27
|
};
|
|
22
28
|
|
|
23
29
|
const resolveHintState = <TValues,>(
|
|
@@ -30,16 +36,16 @@ const resolveHintState = <TValues,>(
|
|
|
30
36
|
return rule.validate(values) ? "valid" : "invalid";
|
|
31
37
|
};
|
|
32
38
|
|
|
33
|
-
const
|
|
34
|
-
valid: "text-
|
|
39
|
+
const hintLabelStateClass: Record<ValidationHintState, string> = {
|
|
40
|
+
valid: "text-text-g-contrast-high",
|
|
35
41
|
invalid: "text-input-error",
|
|
36
|
-
pending: "text-text-g-contrast-
|
|
42
|
+
pending: "text-text-g-contrast-high",
|
|
37
43
|
};
|
|
38
44
|
|
|
39
45
|
const hintIconStateClass: Record<ValidationHintState, string> = {
|
|
40
|
-
valid: "
|
|
41
|
-
invalid: "
|
|
42
|
-
pending: "
|
|
46
|
+
valid: "text-primary",
|
|
47
|
+
invalid: "text-input-error",
|
|
48
|
+
pending: "text-text-g-contrast-low",
|
|
43
49
|
};
|
|
44
50
|
|
|
45
51
|
export const ValidationHintList = <TValues,>({
|
|
@@ -48,6 +54,8 @@ export const ValidationHintList = <TValues,>({
|
|
|
48
54
|
mode = ["pending", "valid", "invalid"],
|
|
49
55
|
className,
|
|
50
56
|
itemClassName,
|
|
57
|
+
labelStateClassName,
|
|
58
|
+
iconStateClassName,
|
|
51
59
|
}: ValidationHintListProps<TValues>) => {
|
|
52
60
|
const enabledStates = new Set<ValidationHintState>(mode);
|
|
53
61
|
|
|
@@ -63,13 +71,18 @@ export const ValidationHintList = <TValues,>({
|
|
|
63
71
|
<li
|
|
64
72
|
key={rule.id}
|
|
65
73
|
className={cn(
|
|
66
|
-
"flex items-center gap-2 typography-small2",
|
|
67
|
-
|
|
74
|
+
"flex items-center gap-2 typography-small2 ",
|
|
75
|
+
hintLabelStateClass[normalizedState],
|
|
76
|
+
labelStateClassName?.[normalizedState],
|
|
68
77
|
itemClassName,
|
|
69
78
|
)}
|
|
70
79
|
>
|
|
71
|
-
<
|
|
72
|
-
className={cn(
|
|
80
|
+
<CircleCheck
|
|
81
|
+
className={cn(
|
|
82
|
+
"size-4",
|
|
83
|
+
hintIconStateClass[normalizedState],
|
|
84
|
+
iconStateClassName?.[normalizedState],
|
|
85
|
+
)}
|
|
73
86
|
/>
|
|
74
87
|
<span>{rule.label}</span>
|
|
75
88
|
</li>
|
|
@@ -26,7 +26,7 @@ export type OtpInputProps = {
|
|
|
26
26
|
const sanitizeChars = (
|
|
27
27
|
raw: string,
|
|
28
28
|
charPattern: RegExp,
|
|
29
|
-
maxLength: number
|
|
29
|
+
maxLength: number,
|
|
30
30
|
): string[] => {
|
|
31
31
|
const chars = Array.from(raw).filter((char) => charPattern.test(char));
|
|
32
32
|
return chars.slice(0, maxLength);
|
|
@@ -48,7 +48,7 @@ export const OtpInput = forwardRef<HTMLInputElement, OtpInputProps>(
|
|
|
48
48
|
className,
|
|
49
49
|
inputClassName,
|
|
50
50
|
},
|
|
51
|
-
ref
|
|
51
|
+
ref,
|
|
52
52
|
) => {
|
|
53
53
|
const inputRefs = useRef<Array<HTMLInputElement | null>>([]);
|
|
54
54
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
@@ -58,7 +58,11 @@ export const OtpInput = forwardRef<HTMLInputElement, OtpInputProps>(
|
|
|
58
58
|
return Array.from({ length }, (_, index) => normalizedValue[index] || "");
|
|
59
59
|
}, [length, value]);
|
|
60
60
|
|
|
61
|
-
useImperativeHandle(
|
|
61
|
+
useImperativeHandle(
|
|
62
|
+
ref,
|
|
63
|
+
() => inputRefs.current[0] as HTMLInputElement,
|
|
64
|
+
[],
|
|
65
|
+
);
|
|
62
66
|
|
|
63
67
|
const setCode = (nextSlots: string[]) => {
|
|
64
68
|
const nextValue = nextSlots.join("");
|
|
@@ -107,7 +111,10 @@ export const OtpInput = forwardRef<HTMLInputElement, OtpInputProps>(
|
|
|
107
111
|
}
|
|
108
112
|
};
|
|
109
113
|
|
|
110
|
-
const handlePaste = (
|
|
114
|
+
const handlePaste = (
|
|
115
|
+
index: number,
|
|
116
|
+
event: ClipboardEvent<HTMLInputElement>,
|
|
117
|
+
) => {
|
|
111
118
|
event.preventDefault();
|
|
112
119
|
if (disabled) return;
|
|
113
120
|
|
|
@@ -125,7 +132,10 @@ export const OtpInput = forwardRef<HTMLInputElement, OtpInputProps>(
|
|
|
125
132
|
focusInput(nextFocusIndex);
|
|
126
133
|
};
|
|
127
134
|
|
|
128
|
-
const handleKeyDown = (
|
|
135
|
+
const handleKeyDown = (
|
|
136
|
+
index: number,
|
|
137
|
+
event: KeyboardEvent<HTMLInputElement>,
|
|
138
|
+
) => {
|
|
129
139
|
if (disabled) return;
|
|
130
140
|
|
|
131
141
|
if (event.key === "ArrowLeft") {
|
|
@@ -160,7 +170,10 @@ export const OtpInput = forwardRef<HTMLInputElement, OtpInputProps>(
|
|
|
160
170
|
};
|
|
161
171
|
|
|
162
172
|
return (
|
|
163
|
-
<div
|
|
173
|
+
<div
|
|
174
|
+
className={cn("flex items-center gap-3", className)}
|
|
175
|
+
ref={containerRef}
|
|
176
|
+
>
|
|
164
177
|
{slots.map((slot, index) => (
|
|
165
178
|
<input
|
|
166
179
|
key={index}
|
|
@@ -176,11 +189,11 @@ export const OtpInput = forwardRef<HTMLInputElement, OtpInputProps>(
|
|
|
176
189
|
autoFocus={autoFocus && index === 0}
|
|
177
190
|
aria-invalid={invalid || undefined}
|
|
178
191
|
className={cn(
|
|
179
|
-
"h-14 w-[46px] rounded-[8px] border bg-transparent text-center text-2xl font-semibold
|
|
192
|
+
"h-14 w-[46px] rounded-[8px] text-input-filled-text border bg-transparent text-center text-2xl font-semibold outline-none transition-all duration-200",
|
|
180
193
|
"border-input-default-stroke focus:border-input-active-stroke",
|
|
181
194
|
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
182
195
|
invalid && "border-input-error focus:border-input-error",
|
|
183
|
-
inputClassName
|
|
196
|
+
inputClassName,
|
|
184
197
|
)}
|
|
185
198
|
onFocus={(event) => {
|
|
186
199
|
event.target.select();
|
|
@@ -202,7 +215,7 @@ export const OtpInput = forwardRef<HTMLInputElement, OtpInputProps>(
|
|
|
202
215
|
))}
|
|
203
216
|
</div>
|
|
204
217
|
);
|
|
205
|
-
}
|
|
218
|
+
},
|
|
206
219
|
);
|
|
207
220
|
|
|
208
221
|
OtpInput.displayName = "OtpInput";
|
|
@@ -132,3 +132,111 @@ export const Disabled: Story = {
|
|
|
132
132
|
);
|
|
133
133
|
},
|
|
134
134
|
};
|
|
135
|
+
|
|
136
|
+
const NormalizeDemo = () => {
|
|
137
|
+
const [value, setValue] = React.useState("");
|
|
138
|
+
return (
|
|
139
|
+
<div className="flex flex-col gap-6 w-full max-w-md">
|
|
140
|
+
<p className="text-sm text-text-g-contrast-low">
|
|
141
|
+
<code>normalize</code> strips disallowed characters on every keystroke.
|
|
142
|
+
This example removes backslash and special path characters in real-time.
|
|
143
|
+
</p>
|
|
144
|
+
<TextArea
|
|
145
|
+
id="normalize-demo"
|
|
146
|
+
label="Notes"
|
|
147
|
+
size="lg"
|
|
148
|
+
rows={4}
|
|
149
|
+
helperText={`Stored value: "${value}"`}
|
|
150
|
+
value={value}
|
|
151
|
+
normalize={(v) => v.replace(/[\\/:*?"'<>|]/g, "")}
|
|
152
|
+
onChange={(e) => setValue(e.target.value)}
|
|
153
|
+
/>
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export const Normalize: Story = {
|
|
159
|
+
render: () => <NormalizeDemo />,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const FormatDemo = () => {
|
|
163
|
+
const [value, setValue] = React.useState("hello world");
|
|
164
|
+
return (
|
|
165
|
+
<div className="flex flex-col gap-6 w-full max-w-md">
|
|
166
|
+
<p className="text-sm text-text-g-contrast-low">
|
|
167
|
+
<code>format</code> transforms the displayed value without changing the
|
|
168
|
+
stored value. This example displays text in uppercase.
|
|
169
|
+
</p>
|
|
170
|
+
<TextArea
|
|
171
|
+
id="format-demo"
|
|
172
|
+
label="Template"
|
|
173
|
+
size="lg"
|
|
174
|
+
rows={4}
|
|
175
|
+
helperText={`Stored value: "${value}"`}
|
|
176
|
+
value={value}
|
|
177
|
+
format={(v) => v.toUpperCase()}
|
|
178
|
+
onChange={(e) => setValue(e.target.value)}
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export const Format: Story = {
|
|
185
|
+
render: () => <FormatDemo />,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const TrimOnCommitDemo = () => {
|
|
189
|
+
const [value, setValue] = React.useState("");
|
|
190
|
+
return (
|
|
191
|
+
<div className="flex flex-col gap-6 w-full max-w-md">
|
|
192
|
+
<p className="text-sm text-text-g-contrast-low">
|
|
193
|
+
<code>trimOnCommit</code> trims leading and trailing whitespace when
|
|
194
|
+
the user blurs the textarea. Try typing <code>" hello "</code> then
|
|
195
|
+
click outside.
|
|
196
|
+
</p>
|
|
197
|
+
<TextArea
|
|
198
|
+
id="trim-commit-demo"
|
|
199
|
+
label="Description"
|
|
200
|
+
size="lg"
|
|
201
|
+
rows={4}
|
|
202
|
+
helperText={`Stored value: "${value}"`}
|
|
203
|
+
value={value}
|
|
204
|
+
trimOnCommit
|
|
205
|
+
onChange={(e) => setValue(e.target.value)}
|
|
206
|
+
/>
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export const TrimOnCommit: Story = {
|
|
212
|
+
render: () => <TrimOnCommitDemo />,
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const NormalizeOnCommitDemo = () => {
|
|
216
|
+
const [value, setValue] = React.useState("");
|
|
217
|
+
return (
|
|
218
|
+
<div className="flex flex-col gap-6 w-full max-w-md">
|
|
219
|
+
<p className="text-sm text-text-g-contrast-low">
|
|
220
|
+
<code>normalizeOnCommit</code> applies a custom transform when the user
|
|
221
|
+
blurs. Use with <code>trimOnCommit</code> to compose — trim runs first,
|
|
222
|
+
then <code>normalizeOnCommit</code>. This example trims and collapses
|
|
223
|
+
multiple blank lines into one on blur.
|
|
224
|
+
</p>
|
|
225
|
+
<TextArea
|
|
226
|
+
id="normalize-on-commit-demo"
|
|
227
|
+
label="Notes"
|
|
228
|
+
size="lg"
|
|
229
|
+
rows={4}
|
|
230
|
+
helperText={`Stored value: "${value}"`}
|
|
231
|
+
value={value}
|
|
232
|
+
trimOnCommit
|
|
233
|
+
normalizeOnCommit={(v) => v.replace(/\n{3,}/g, "\n\n")}
|
|
234
|
+
onChange={(e) => setValue(e.target.value)}
|
|
235
|
+
/>
|
|
236
|
+
</div>
|
|
237
|
+
);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
export const NormalizeOnCommit: Story = {
|
|
241
|
+
render: () => <NormalizeOnCommitDemo />,
|
|
242
|
+
};
|