@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
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { CircleCheck } from "lucide-react";
|
|
3
3
|
import { cn } from "@/utils/cn";
|
|
4
4
|
const resolveHintState = (values, rule) => {
|
|
5
5
|
const shouldEvaluate = rule.when ? rule.when(values) : true;
|
|
@@ -7,24 +7,24 @@ const resolveHintState = (values, rule) => {
|
|
|
7
7
|
return "pending";
|
|
8
8
|
return rule.validate(values) ? "valid" : "invalid";
|
|
9
9
|
};
|
|
10
|
-
const
|
|
11
|
-
valid: "text-
|
|
10
|
+
const hintLabelStateClass = {
|
|
11
|
+
valid: "text-text-g-contrast-high",
|
|
12
12
|
invalid: "text-input-error",
|
|
13
|
-
pending: "text-text-g-contrast-
|
|
13
|
+
pending: "text-text-g-contrast-high",
|
|
14
14
|
};
|
|
15
15
|
const hintIconStateClass = {
|
|
16
|
-
valid: "
|
|
17
|
-
invalid: "
|
|
18
|
-
pending: "
|
|
16
|
+
valid: "text-primary",
|
|
17
|
+
invalid: "text-input-error",
|
|
18
|
+
pending: "text-text-g-contrast-low",
|
|
19
19
|
};
|
|
20
|
-
export const ValidationHintList = ({ values, rules, mode = ["pending", "valid", "invalid"], className, itemClassName, }) => {
|
|
20
|
+
export const ValidationHintList = ({ values, rules, mode = ["pending", "valid", "invalid"], className, itemClassName, labelStateClassName, iconStateClassName, }) => {
|
|
21
21
|
const enabledStates = new Set(mode);
|
|
22
22
|
return (_jsx("ul", { className: cn("mt-2 flex flex-col gap-3", className), children: rules.map((rule) => {
|
|
23
23
|
const state = resolveHintState(values, rule);
|
|
24
24
|
const normalizedState = enabledStates.has(state)
|
|
25
25
|
? state
|
|
26
26
|
: "pending";
|
|
27
|
-
return (_jsxs("li", { className: cn("flex items-center gap-2 typography-small2",
|
|
27
|
+
return (_jsxs("li", { className: cn("flex items-center gap-2 typography-small2 ", hintLabelStateClass[normalizedState], labelStateClassName === null || labelStateClassName === void 0 ? void 0 : labelStateClassName[normalizedState], itemClassName), children: [_jsx(CircleCheck, { className: cn("size-4", hintIconStateClass[normalizedState], iconStateClassName === null || iconStateClassName === void 0 ? void 0 : iconStateClassName[normalizedState]) }), _jsx("span", { children: rule.label })] }, rule.id));
|
|
28
28
|
}) }));
|
|
29
29
|
};
|
|
30
30
|
export default ValidationHintList;
|
|
@@ -102,7 +102,7 @@ export const OtpInput = forwardRef(({ value, onChange, onBlur, onComplete, lengt
|
|
|
102
102
|
};
|
|
103
103
|
return (_jsx("div", { className: cn("flex items-center gap-3", className), ref: containerRef, children: slots.map((slot, index) => (_jsx("input", { ref: (element) => {
|
|
104
104
|
inputRefs.current[index] = element;
|
|
105
|
-
}, type: "text", inputMode: inputMode, autoComplete: index === 0 ? "one-time-code" : "off", value: slot, maxLength: 1, disabled: disabled, autoFocus: autoFocus && index === 0, "aria-invalid": invalid || undefined, className: cn("h-14 w-[46px] rounded-[8px] border bg-transparent text-center text-2xl font-semibold
|
|
105
|
+
}, type: "text", inputMode: inputMode, autoComplete: index === 0 ? "one-time-code" : "off", value: slot, maxLength: 1, disabled: disabled, autoFocus: autoFocus && index === 0, "aria-invalid": invalid || undefined, className: cn("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", "border-input-default-stroke focus:border-input-active-stroke", "disabled:cursor-not-allowed disabled:opacity-50", invalid && "border-input-error focus:border-input-error", inputClassName), onFocus: (event) => {
|
|
106
106
|
event.target.select();
|
|
107
107
|
}, onBlur: (event) => {
|
|
108
108
|
var _a;
|
|
@@ -10,15 +10,44 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
import { forwardRef, useImperativeHandle, useMemo, useRef } from "react";
|
|
13
|
+
import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef } from "react";
|
|
14
14
|
import { cn } from "@/utils/cn";
|
|
15
15
|
import { textareaVariant, labelVariant as textareaLabelVariant, helperTextVariant as textareaHelperTextVariant, clearIconWrapperVariant, clearIconVariant, } from "./TextArea.styles";
|
|
16
16
|
import { XCircleIcon } from "@heroicons/react/16/solid";
|
|
17
17
|
export const TextArea = forwardRef((_a, ref) => {
|
|
18
|
-
var { id, label, size = "md", rounded = "normal", variant = "outline", helperText, errorMessage, fullwidth = true, disabled = false, error = false, required = true, isFloatingLabel = true, keepCloseIconOnValue = false, hasClearIcon = true, labelClassName, className } = _a, props = __rest(_a, ["id", "label", "size", "rounded", "variant", "helperText", "errorMessage", "fullwidth", "disabled", "error", "required", "isFloatingLabel", "keepCloseIconOnValue", "hasClearIcon", "labelClassName", "className"]);
|
|
18
|
+
var { id, label, size = "md", rounded = "normal", variant = "outline", helperText, errorMessage, fullwidth = true, disabled = false, error = false, required = true, isFloatingLabel = true, keepCloseIconOnValue = false, hasClearIcon = true, labelClassName, className, normalize, format, trimOnCommit, normalizeOnCommit } = _a, props = __rest(_a, ["id", "label", "size", "rounded", "variant", "helperText", "errorMessage", "fullwidth", "disabled", "error", "required", "isFloatingLabel", "keepCloseIconOnValue", "hasClearIcon", "labelClassName", "className", "normalize", "format", "trimOnCommit", "normalizeOnCommit"]);
|
|
19
19
|
const textareaRef = useRef(null);
|
|
20
20
|
const _id = id || `textarea-${label !== null && label !== void 0 ? label : ""}`;
|
|
21
21
|
useImperativeHandle(ref, () => textareaRef === null || textareaRef === void 0 ? void 0 : textareaRef.current);
|
|
22
|
+
const handleChange = useCallback((e) => {
|
|
23
|
+
var _a;
|
|
24
|
+
if (normalize) {
|
|
25
|
+
e.target.value = normalize(e.target.value);
|
|
26
|
+
}
|
|
27
|
+
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
28
|
+
}, [normalize, props.onChange]);
|
|
29
|
+
const commitValue = useCallback((e) => {
|
|
30
|
+
var _a;
|
|
31
|
+
const textarea = e.currentTarget;
|
|
32
|
+
let committed = textarea.value;
|
|
33
|
+
if (trimOnCommit)
|
|
34
|
+
committed = committed.trim();
|
|
35
|
+
if (normalizeOnCommit)
|
|
36
|
+
committed = normalizeOnCommit(committed);
|
|
37
|
+
if (committed !== textarea.value) {
|
|
38
|
+
textarea.value = committed;
|
|
39
|
+
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, Object.assign(Object.assign({}, e), { target: textarea }));
|
|
40
|
+
}
|
|
41
|
+
}, [trimOnCommit, normalizeOnCommit, props.onChange]);
|
|
42
|
+
const handleBlur = useCallback((e) => {
|
|
43
|
+
var _a;
|
|
44
|
+
if (trimOnCommit || normalizeOnCommit)
|
|
45
|
+
commitValue(e);
|
|
46
|
+
(_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
47
|
+
}, [trimOnCommit, normalizeOnCommit, commitValue, props.onBlur]);
|
|
48
|
+
const displayValue = format && typeof props.value === "string"
|
|
49
|
+
? format(props.value)
|
|
50
|
+
: props.value;
|
|
22
51
|
// Reuse TextInput visual language via utility classes to stay consistent
|
|
23
52
|
const containerClassName = useMemo(() => `inline-flex flex-col ${fullwidth ? "w-full" : ""}`, [fullwidth]);
|
|
24
53
|
const textareaClassName = textareaVariant({
|
|
@@ -31,7 +60,7 @@ export const TextArea = forwardRef((_a, ref) => {
|
|
|
31
60
|
hasClearIcon,
|
|
32
61
|
isFloatingLabel,
|
|
33
62
|
});
|
|
34
|
-
return (_jsxs("div", { className: containerClassName, children: [_jsxs("div", { className: "relative", children: [_jsx("textarea", Object.assign({}, props, { id: _id, ref: textareaRef, disabled: disabled, placeholder: isFloatingLabel ? " " : props.placeholder, className: cn(textareaClassName, className) })), hasClearIcon && (_jsx("div", { className: clearIconWrapperVariant({ size }), style: {
|
|
63
|
+
return (_jsxs("div", { className: containerClassName, children: [_jsxs("div", { className: "relative", children: [_jsx("textarea", Object.assign({}, props, { id: _id, ref: textareaRef, disabled: disabled, placeholder: isFloatingLabel ? " " : props.placeholder, className: cn(textareaClassName, className), value: displayValue, onChange: normalize ? handleChange : props.onChange, onBlur: trimOnCommit || normalizeOnCommit ? handleBlur : props.onBlur })), hasClearIcon && (_jsx("div", { className: clearIconWrapperVariant({ size }), style: {
|
|
35
64
|
display: keepCloseIconOnValue && props.value ? "flex" : undefined,
|
|
36
65
|
}, children: _jsx(XCircleIcon, { type: "button", className: clearIconVariant({ size }), onMouseDown: (e) => {
|
|
37
66
|
e.preventDefault();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
2
3
|
import { TextArea } from "@/index";
|
|
3
4
|
const meta = {
|
|
4
5
|
title: "Components/TextArea",
|
|
@@ -84,3 +85,31 @@ export const Disabled = {
|
|
|
84
85
|
return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(TextArea, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(TextArea, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(TextArea, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
|
|
85
86
|
},
|
|
86
87
|
};
|
|
88
|
+
const NormalizeDemo = () => {
|
|
89
|
+
const [value, setValue] = React.useState("");
|
|
90
|
+
return (_jsxs("div", { className: "flex flex-col gap-6 w-full max-w-md", children: [_jsxs("p", { className: "text-sm text-text-g-contrast-low", children: [_jsx("code", { children: "normalize" }), " strips disallowed characters on every keystroke. This example removes backslash and special path characters in real-time."] }), _jsx(TextArea, { id: "normalize-demo", label: "Notes", size: "lg", rows: 4, helperText: `Stored value: "${value}"`, value: value, normalize: (v) => v.replace(/[\\/:*?"'<>|]/g, ""), onChange: (e) => setValue(e.target.value) })] }));
|
|
91
|
+
};
|
|
92
|
+
export const Normalize = {
|
|
93
|
+
render: () => _jsx(NormalizeDemo, {}),
|
|
94
|
+
};
|
|
95
|
+
const FormatDemo = () => {
|
|
96
|
+
const [value, setValue] = React.useState("hello world");
|
|
97
|
+
return (_jsxs("div", { className: "flex flex-col gap-6 w-full max-w-md", children: [_jsxs("p", { className: "text-sm text-text-g-contrast-low", children: [_jsx("code", { children: "format" }), " transforms the displayed value without changing the stored value. This example displays text in uppercase."] }), _jsx(TextArea, { id: "format-demo", label: "Template", size: "lg", rows: 4, helperText: `Stored value: "${value}"`, value: value, format: (v) => v.toUpperCase(), onChange: (e) => setValue(e.target.value) })] }));
|
|
98
|
+
};
|
|
99
|
+
export const Format = {
|
|
100
|
+
render: () => _jsx(FormatDemo, {}),
|
|
101
|
+
};
|
|
102
|
+
const TrimOnCommitDemo = () => {
|
|
103
|
+
const [value, setValue] = React.useState("");
|
|
104
|
+
return (_jsxs("div", { className: "flex flex-col gap-6 w-full max-w-md", children: [_jsxs("p", { className: "text-sm text-text-g-contrast-low", children: [_jsx("code", { children: "trimOnCommit" }), " trims leading and trailing whitespace when the user blurs the textarea. Try typing ", _jsx("code", { children: "\" hello \"" }), " then click outside."] }), _jsx(TextArea, { id: "trim-commit-demo", label: "Description", size: "lg", rows: 4, helperText: `Stored value: "${value}"`, value: value, trimOnCommit: true, onChange: (e) => setValue(e.target.value) })] }));
|
|
105
|
+
};
|
|
106
|
+
export const TrimOnCommit = {
|
|
107
|
+
render: () => _jsx(TrimOnCommitDemo, {}),
|
|
108
|
+
};
|
|
109
|
+
const NormalizeOnCommitDemo = () => {
|
|
110
|
+
const [value, setValue] = React.useState("");
|
|
111
|
+
return (_jsxs("div", { className: "flex flex-col gap-6 w-full max-w-md", children: [_jsxs("p", { className: "text-sm text-text-g-contrast-low", children: [_jsx("code", { children: "normalizeOnCommit" }), " applies a custom transform when the user blurs. Use with ", _jsx("code", { children: "trimOnCommit" }), " to compose \u2014 trim runs first, then ", _jsx("code", { children: "normalizeOnCommit" }), ". This example trims and collapses multiple blank lines into one on blur."] }), _jsx(TextArea, { id: "normalize-on-commit-demo", label: "Notes", size: "lg", rows: 4, helperText: `Stored value: "${value}"`, value: value, trimOnCommit: true, normalizeOnCommit: (v) => v.replace(/\n{3,}/g, "\n\n"), onChange: (e) => setValue(e.target.value) })] }));
|
|
112
|
+
};
|
|
113
|
+
export const NormalizeOnCommit = {
|
|
114
|
+
render: () => _jsx(NormalizeOnCommitDemo, {}),
|
|
115
|
+
};
|
|
@@ -15,7 +15,7 @@ import { helperTextVariant, iconActionVariant, inlineEndIconWrapperVariant, inli
|
|
|
15
15
|
import { CircleAlert, CircleX, Search, } from "lucide-react";
|
|
16
16
|
import { cn } from "@/utils/cn";
|
|
17
17
|
export const TextInput = forwardRef((_a, ref) => {
|
|
18
|
-
var { id, label, size = "md", rounded = "normal", variant = "outline", type = "text", iconMode = "solid", helperText, errorMessage, warningMessage, status, fullwidth = true, disabled = false, error = false, warning = false, required = true, isFloatingLabel = true, keepCloseIconOnValue = false, keepFooterSpace = true, hasClearIcon = true, hasSearchIcon = false, startIcon, endIcon, labelClassName, onClickStartIcon, onClickEndIcon, renderStartIcon, renderEndIcon, classes } = _a, props = __rest(_a, ["id", "label", "size", "rounded", "variant", "type", "iconMode", "helperText", "errorMessage", "warningMessage", "status", "fullwidth", "disabled", "error", "warning", "required", "isFloatingLabel", "keepCloseIconOnValue", "keepFooterSpace", "hasClearIcon", "hasSearchIcon", "startIcon", "endIcon", "labelClassName", "onClickStartIcon", "onClickEndIcon", "renderStartIcon", "renderEndIcon", "classes"]);
|
|
18
|
+
var { id, label, size = "md", rounded = "normal", variant = "outline", type = "text", iconMode = "solid", helperText, errorMessage, warningMessage, status, fullwidth = true, disabled = false, error = false, warning = false, required = true, isFloatingLabel = true, keepCloseIconOnValue = false, keepFooterSpace = true, hasClearIcon = true, hasSearchIcon = false, startIcon, endIcon, labelClassName, onClickStartIcon, onClickEndIcon, renderStartIcon, renderEndIcon, classes, normalize, format, trimOnCommit, normalizeOnCommit } = _a, props = __rest(_a, ["id", "label", "size", "rounded", "variant", "type", "iconMode", "helperText", "errorMessage", "warningMessage", "status", "fullwidth", "disabled", "error", "warning", "required", "isFloatingLabel", "keepCloseIconOnValue", "keepFooterSpace", "hasClearIcon", "hasSearchIcon", "startIcon", "endIcon", "labelClassName", "onClickStartIcon", "onClickEndIcon", "renderStartIcon", "renderEndIcon", "classes", "normalize", "format", "trimOnCommit", "normalizeOnCommit"]);
|
|
19
19
|
const inputRef = useRef(null);
|
|
20
20
|
const _id = id || `${type}-${label}-input`;
|
|
21
21
|
const hasLeftSectionIcon = !!startIcon || !!renderStartIcon;
|
|
@@ -82,6 +82,42 @@ export const TextInput = forwardRef((_a, ref) => {
|
|
|
82
82
|
position: "end",
|
|
83
83
|
});
|
|
84
84
|
useImperativeHandle(ref, () => inputRef === null || inputRef === void 0 ? void 0 : inputRef.current);
|
|
85
|
+
const handleChange = useCallback((e) => {
|
|
86
|
+
var _a;
|
|
87
|
+
if (normalize) {
|
|
88
|
+
e.target.value = normalize(e.target.value);
|
|
89
|
+
}
|
|
90
|
+
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
91
|
+
}, [normalize, props.onChange]);
|
|
92
|
+
const commitValue = useCallback((e) => {
|
|
93
|
+
var _a;
|
|
94
|
+
const input = e.currentTarget;
|
|
95
|
+
let committed = input.value;
|
|
96
|
+
if (trimOnCommit)
|
|
97
|
+
committed = committed.trim();
|
|
98
|
+
if (normalizeOnCommit)
|
|
99
|
+
committed = normalizeOnCommit(committed);
|
|
100
|
+
if (committed !== input.value) {
|
|
101
|
+
input.value = committed;
|
|
102
|
+
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, Object.assign(Object.assign({}, e), { target: input }));
|
|
103
|
+
}
|
|
104
|
+
}, [trimOnCommit, normalizeOnCommit, props.onChange]);
|
|
105
|
+
const handleBlur = useCallback((e) => {
|
|
106
|
+
var _a;
|
|
107
|
+
if (trimOnCommit || normalizeOnCommit)
|
|
108
|
+
commitValue(e);
|
|
109
|
+
(_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
110
|
+
}, [trimOnCommit, normalizeOnCommit, commitValue, props.onBlur]);
|
|
111
|
+
const handleKeyDown = useCallback((e) => {
|
|
112
|
+
var _a;
|
|
113
|
+
if ((trimOnCommit || normalizeOnCommit) && e.key === "Enter") {
|
|
114
|
+
commitValue(e);
|
|
115
|
+
}
|
|
116
|
+
(_a = props.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
117
|
+
}, [trimOnCommit, normalizeOnCommit, commitValue, props.onKeyDown]);
|
|
118
|
+
const displayValue = format && typeof props.value === "string"
|
|
119
|
+
? format(props.value)
|
|
120
|
+
: props.value;
|
|
85
121
|
const handleClearInput = useCallback(() => {
|
|
86
122
|
if (inputRef.current) {
|
|
87
123
|
inputRef.current.value = "";
|
|
@@ -147,7 +183,7 @@ export const TextInput = forwardRef((_a, ref) => {
|
|
|
147
183
|
renderEndIcon,
|
|
148
184
|
handleOnClickRightSectionIcon,
|
|
149
185
|
]);
|
|
150
|
-
return (_jsxs("div", { className: `inline-flex flex-col ${fullwidth ? "w-full" : ""}`, children: [_jsxs("div", { className: "relative", children: [_jsx("input", Object.assign({}, props, { placeholder: " ", ref: inputRef, type: type, id: _id, disabled: disabled, className: cn(inputClassname, props.className) })), hasSearchIcon && !hasLeftSectionIcon && (_jsx("div", { className: cn(inlineStartIconWrapperClassname, classes === null || classes === void 0 ? void 0 : classes.iconSearchWrapper), children: _jsx(Search, { className: cn(searchIconClassname, classes === null || classes === void 0 ? void 0 : classes.icon) }) })), startIconElement, hasClearIcon && !hasRightSectionIcon && (_jsx("div", { className: cn(inlineEndIconWrapperClassname, classes === null || classes === void 0 ? void 0 : classes.iconWrapper), style: {
|
|
186
|
+
return (_jsxs("div", { className: `inline-flex flex-col ${fullwidth ? "w-full" : ""}`, children: [_jsxs("div", { className: "relative", children: [_jsx("input", Object.assign({}, props, { placeholder: " ", ref: inputRef, type: type, id: _id, disabled: disabled, value: displayValue, className: cn(inputClassname, props.className), onChange: normalize ? handleChange : props.onChange, onBlur: trimOnCommit || normalizeOnCommit ? handleBlur : props.onBlur, onKeyDown: trimOnCommit || normalizeOnCommit ? handleKeyDown : props.onKeyDown })), hasSearchIcon && !hasLeftSectionIcon && (_jsx("div", { className: cn(inlineStartIconWrapperClassname, classes === null || classes === void 0 ? void 0 : classes.iconSearchWrapper), children: _jsx(Search, { className: cn(searchIconClassname, classes === null || classes === void 0 ? void 0 : classes.icon) }) })), startIconElement, hasClearIcon && !hasRightSectionIcon && (_jsx("div", { className: cn(inlineEndIconWrapperClassname, classes === null || classes === void 0 ? void 0 : classes.iconWrapper), style: {
|
|
151
187
|
display: keepCloseIconOnValue && props.value ? "flex" : undefined,
|
|
152
188
|
}, children: _jsx(CircleX, { className: cn(iconActionClassname,
|
|
153
189
|
// 'fill-none stroke-current',
|
|
@@ -101,3 +101,31 @@ const FeedbackApiDemo = () => {
|
|
|
101
101
|
export const FeedbackApiCompatibility = {
|
|
102
102
|
render: () => _jsx(FeedbackApiDemo, {}),
|
|
103
103
|
};
|
|
104
|
+
const NormalizeDemo = () => {
|
|
105
|
+
const [value, setValue] = useState("");
|
|
106
|
+
return (_jsxs("div", { className: "flex flex-col gap-6 w-full max-w-md", children: [_jsxs("p", { className: "text-sm text-text-g-contrast-low", children: [_jsx("code", { children: "normalize" }), " strips disallowed characters on every keystroke. This example removes backslash and special path characters in real-time."] }), _jsx(TextInput, { id: "normalize-demo", label: "Device Name", size: "lg", keepFooterSpace: true, helperText: `Stored value: "${value}"`, value: value, normalize: (v) => v.trimStart().replace(/[\\/:*?"'<>|]/g, ""), onChange: (e) => setValue(e.target.value) })] }));
|
|
107
|
+
};
|
|
108
|
+
export const Normalize = {
|
|
109
|
+
render: () => _jsx(NormalizeDemo, {}),
|
|
110
|
+
};
|
|
111
|
+
const FormatDemo = () => {
|
|
112
|
+
const [value, setValue] = useState("1000000");
|
|
113
|
+
return (_jsxs("div", { className: "flex flex-col gap-6 w-full max-w-md", children: [_jsxs("p", { className: "text-sm text-text-g-contrast-low", children: [_jsx("code", { children: "format" }), " transforms the displayed value without changing the stored value. This example displays numbers with comma separators."] }), _jsx(TextInput, { id: "format-demo", label: "Amount", size: "lg", keepFooterSpace: true, helperText: `Stored value: "${value}"`, value: value, format: (v) => Number(v.replace(/,/g, "") || 0).toLocaleString(), normalize: (v) => v.replace(/[^0-9]/g, ""), onChange: (e) => setValue(e.target.value) })] }));
|
|
114
|
+
};
|
|
115
|
+
export const Format = {
|
|
116
|
+
render: () => _jsx(FormatDemo, {}),
|
|
117
|
+
};
|
|
118
|
+
const TrimOnCommitDemo = () => {
|
|
119
|
+
const [value, setValue] = useState("");
|
|
120
|
+
return (_jsxs("div", { className: "flex flex-col gap-6 w-full max-w-md", children: [_jsxs("p", { className: "text-sm text-text-g-contrast-low", children: [_jsx("code", { children: "trimOnCommit" }), " trims leading and trailing whitespace when the user blurs the input or presses Enter. Try typing", " ", _jsx("code", { children: "\"hello \"" }), " then click outside or press Enter."] }), _jsx(TextInput, { id: "trim-commit-demo", label: "Name", size: "lg", keepFooterSpace: true, helperText: `Stored value: "${value}"`, value: value, trimOnCommit: true, onChange: (e) => setValue(e.target.value) })] }));
|
|
121
|
+
};
|
|
122
|
+
export const TrimOnCommit = {
|
|
123
|
+
render: () => _jsx(TrimOnCommitDemo, {}),
|
|
124
|
+
};
|
|
125
|
+
const NormalizeOnCommitDemo = () => {
|
|
126
|
+
const [value, setValue] = useState("");
|
|
127
|
+
return (_jsxs("div", { className: "flex flex-col gap-6 w-full max-w-md", children: [_jsxs("p", { className: "text-sm text-text-g-contrast-low", children: [_jsx("code", { children: "normalizeOnCommit" }), " applies a custom transform when the user blurs or presses Enter. Use with ", _jsx("code", { children: "trimOnCommit" }), " to compose \u2014 trim runs first, then ", _jsx("code", { children: "normalizeOnCommit" }), ". This example trims and uppercases on commit."] }), _jsx(TextInput, { id: "normalize-on-commit-demo", label: "Code", size: "lg", keepFooterSpace: true, helperText: `Stored value: "${value}"`, value: value, trimOnCommit: true, normalizeOnCommit: (v) => v.toUpperCase(), onChange: (e) => setValue(e.target.value) })] }));
|
|
128
|
+
};
|
|
129
|
+
export const NormalizeOnCommit = {
|
|
130
|
+
render: () => _jsx(NormalizeOnCommitDemo, {}),
|
|
131
|
+
};
|
package/dist/esm/bundle.css
CHANGED
|
@@ -3929,10 +3929,6 @@ input[type=number] {
|
|
|
3929
3929
|
--tw-text-opacity: 1;
|
|
3930
3930
|
color: color-mix(in srgb, var(--text-g-contrast-medium) calc(100% * var(--tw-text-opacity, 1)), transparent);
|
|
3931
3931
|
}
|
|
3932
|
-
.text-text-white{
|
|
3933
|
-
--tw-text-opacity: 1;
|
|
3934
|
-
color: color-mix(in srgb, var(--text-white) calc(100% * var(--tw-text-opacity, 1)), transparent);
|
|
3935
|
-
}
|
|
3936
3932
|
.text-warning{
|
|
3937
3933
|
--tw-text-opacity: 1;
|
|
3938
3934
|
color: color-mix(in srgb, var(--state-warning-default) calc(100% * var(--tw-text-opacity, 1)), transparent);
|
|
@@ -3953,12 +3949,6 @@ input[type=number] {
|
|
|
3953
3949
|
.opacity-0{
|
|
3954
3950
|
opacity: 0;
|
|
3955
3951
|
}
|
|
3956
|
-
.opacity-100{
|
|
3957
|
-
opacity: 1;
|
|
3958
|
-
}
|
|
3959
|
-
.opacity-40{
|
|
3960
|
-
opacity: 0.4;
|
|
3961
|
-
}
|
|
3962
3952
|
.opacity-50{
|
|
3963
3953
|
opacity: 0.5;
|
|
3964
3954
|
}
|