@rovula/ui 0.0.73 → 0.0.75
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 +36 -0
- package/dist/cjs/bundle.js +3 -3
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/cjs/types/components/TextArea/TextArea.d.ts +38 -0
- package/dist/cjs/types/components/TextArea/TextArea.stories.d.ts +9 -0
- package/dist/cjs/types/components/TextArea/TextArea.styles.d.ts +27 -0
- package/dist/cjs/types/components/Tree/Tree.stories.d.ts +1 -0
- package/dist/cjs/types/index.d.ts +2 -0
- package/dist/components/TextArea/TextArea.js +55 -0
- package/dist/components/TextArea/TextArea.stories.js +86 -0
- package/dist/components/TextArea/TextArea.styles.js +207 -0
- package/dist/components/Tree/Tree.stories.js +73 -0
- package/dist/components/Tree/TreeItem.js +1 -1
- package/dist/esm/bundle.css +36 -0
- package/dist/esm/bundle.js +3 -3
- package/dist/esm/bundle.js.map +1 -1
- package/dist/esm/types/components/TextArea/TextArea.d.ts +38 -0
- package/dist/esm/types/components/TextArea/TextArea.stories.d.ts +9 -0
- package/dist/esm/types/components/TextArea/TextArea.styles.d.ts +27 -0
- package/dist/esm/types/components/Tree/Tree.stories.d.ts +1 -0
- package/dist/esm/types/index.d.ts +2 -0
- package/dist/index.d.ts +38 -1
- package/dist/index.js +1 -0
- package/dist/src/theme/global.css +46 -0
- package/package.json +1 -1
- package/src/components/TextArea/TextArea.stories.tsx +134 -0
- package/src/components/TextArea/TextArea.styles.ts +228 -0
- package/src/components/TextArea/TextArea.tsx +150 -0
- package/src/components/Tree/Tree.stories.tsx +100 -0
- package/src/components/Tree/TreeItem.tsx +1 -1
- package/src/index.ts +2 -0
- package/src/theme/global.css +26 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import React, { forwardRef, useImperativeHandle, useMemo, useRef } from "react";
|
|
2
|
+
import { cn } from "@/utils/cn";
|
|
3
|
+
import {
|
|
4
|
+
textareaVariant,
|
|
5
|
+
labelVariant as textareaLabelVariant,
|
|
6
|
+
helperTextVariant as textareaHelperTextVariant,
|
|
7
|
+
clearIconWrapperVariant,
|
|
8
|
+
clearIconVariant,
|
|
9
|
+
} from "./TextArea.styles";
|
|
10
|
+
import { XCircleIcon } from "@heroicons/react/16/solid";
|
|
11
|
+
|
|
12
|
+
export type TextAreaProps = {
|
|
13
|
+
id?: string;
|
|
14
|
+
label?: string;
|
|
15
|
+
size?: "sm" | "md" | "lg";
|
|
16
|
+
rounded?: "none" | "normal" | "full";
|
|
17
|
+
variant?: "flat" | "outline" | "underline";
|
|
18
|
+
helperText?: string;
|
|
19
|
+
errorMessage?: string;
|
|
20
|
+
fullwidth?: boolean;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
error?: boolean;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
isFloatingLabel?: boolean;
|
|
25
|
+
keepCloseIconOnValue?: boolean;
|
|
26
|
+
hasClearIcon?: boolean;
|
|
27
|
+
labelClassName?: string;
|
|
28
|
+
className?: string;
|
|
29
|
+
} & Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "size">;
|
|
30
|
+
|
|
31
|
+
export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
|
32
|
+
(
|
|
33
|
+
{
|
|
34
|
+
id,
|
|
35
|
+
label,
|
|
36
|
+
size = "md",
|
|
37
|
+
rounded = "normal",
|
|
38
|
+
variant = "outline",
|
|
39
|
+
helperText,
|
|
40
|
+
errorMessage,
|
|
41
|
+
fullwidth = true,
|
|
42
|
+
disabled = false,
|
|
43
|
+
error = false,
|
|
44
|
+
required = true,
|
|
45
|
+
isFloatingLabel = true,
|
|
46
|
+
keepCloseIconOnValue = false,
|
|
47
|
+
hasClearIcon = true,
|
|
48
|
+
labelClassName,
|
|
49
|
+
className,
|
|
50
|
+
...props
|
|
51
|
+
},
|
|
52
|
+
ref
|
|
53
|
+
) => {
|
|
54
|
+
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
55
|
+
const _id = id || `textarea-${label ?? ""}`;
|
|
56
|
+
|
|
57
|
+
useImperativeHandle(ref, () => textareaRef?.current as HTMLTextAreaElement);
|
|
58
|
+
|
|
59
|
+
// Reuse TextInput visual language via utility classes to stay consistent
|
|
60
|
+
const containerClassName = useMemo(
|
|
61
|
+
() => `inline-flex flex-col ${fullwidth ? "w-full" : ""}`,
|
|
62
|
+
[fullwidth]
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const textareaClassName = textareaVariant({
|
|
66
|
+
size,
|
|
67
|
+
rounded,
|
|
68
|
+
variant,
|
|
69
|
+
fullwidth,
|
|
70
|
+
disabled,
|
|
71
|
+
error,
|
|
72
|
+
hasClearIcon,
|
|
73
|
+
isFloatingLabel,
|
|
74
|
+
} as any);
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className={containerClassName}>
|
|
78
|
+
<div className="relative">
|
|
79
|
+
<textarea
|
|
80
|
+
{...props}
|
|
81
|
+
id={_id}
|
|
82
|
+
ref={textareaRef}
|
|
83
|
+
disabled={disabled}
|
|
84
|
+
placeholder={isFloatingLabel ? " " : props.placeholder}
|
|
85
|
+
className={cn(textareaClassName, className)}
|
|
86
|
+
/>
|
|
87
|
+
{hasClearIcon && (
|
|
88
|
+
<div
|
|
89
|
+
className={clearIconWrapperVariant({ size })}
|
|
90
|
+
style={{
|
|
91
|
+
display:
|
|
92
|
+
keepCloseIconOnValue && props.value ? "flex" : undefined,
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
<XCircleIcon
|
|
96
|
+
type="button"
|
|
97
|
+
className={clearIconVariant({ size })}
|
|
98
|
+
onMouseDown={(e) => {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
if (textareaRef.current) {
|
|
101
|
+
const prev = textareaRef.current.value;
|
|
102
|
+
textareaRef.current.value = "";
|
|
103
|
+
if (props.onChange && prev !== "") {
|
|
104
|
+
props.onChange({ target: { value: "" } } as any);
|
|
105
|
+
}
|
|
106
|
+
textareaRef.current.focus();
|
|
107
|
+
}
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
)}
|
|
112
|
+
{label && (
|
|
113
|
+
<label
|
|
114
|
+
htmlFor={_id}
|
|
115
|
+
className={cn(
|
|
116
|
+
textareaLabelVariant({
|
|
117
|
+
size,
|
|
118
|
+
disabled,
|
|
119
|
+
error,
|
|
120
|
+
isFloatingLabel,
|
|
121
|
+
}),
|
|
122
|
+
labelClassName
|
|
123
|
+
)}
|
|
124
|
+
>
|
|
125
|
+
{label}{" "}
|
|
126
|
+
{required && (
|
|
127
|
+
<span
|
|
128
|
+
className={cn("text-error", {
|
|
129
|
+
"text-input-disable-text": disabled,
|
|
130
|
+
})}
|
|
131
|
+
>
|
|
132
|
+
*
|
|
133
|
+
</span>
|
|
134
|
+
)}
|
|
135
|
+
</label>
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
{(errorMessage || helperText) && (
|
|
139
|
+
<span
|
|
140
|
+
className={textareaHelperTextVariant({ size, disabled, error })}
|
|
141
|
+
>
|
|
142
|
+
{errorMessage || helperText}
|
|
143
|
+
</span>
|
|
144
|
+
)}
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
export default TextArea;
|
|
@@ -446,3 +446,103 @@ export const CheckAll: StoryObj<typeof Tree> = {
|
|
|
446
446
|
);
|
|
447
447
|
},
|
|
448
448
|
};
|
|
449
|
+
|
|
450
|
+
export const LongText: StoryObj<typeof Tree> = {
|
|
451
|
+
args: {
|
|
452
|
+
data: [
|
|
453
|
+
{
|
|
454
|
+
id: "2699d80b-6772-4878-9639-75e370786e79",
|
|
455
|
+
title:
|
|
456
|
+
"Level1 RUNLINE_LV_2_00000000000000000000000000000000000000000000000000000000",
|
|
457
|
+
children: [
|
|
458
|
+
{
|
|
459
|
+
id: "9b4511f4-ad9a-42e0-8376-60d5edbeffb3",
|
|
460
|
+
title:
|
|
461
|
+
"Level1 RUNLINE_LV_3_0000000000000000000000000000000000000000000000000000",
|
|
462
|
+
children: [
|
|
463
|
+
{
|
|
464
|
+
id: "c8d5dfb5-6c61-482b-88fe-186eb7685479",
|
|
465
|
+
title: "2025-07-27_05-25-53",
|
|
466
|
+
children: [],
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
id: "81ff1dd0-b283-4f60-864e-5d814e99d903",
|
|
470
|
+
title: "2025-07-27_06-05-53",
|
|
471
|
+
children: [],
|
|
472
|
+
},
|
|
473
|
+
],
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
id: "ad79c17b-2861-431a-af0e-3f1c73164508",
|
|
479
|
+
title: "RUNLINE_LV_2",
|
|
480
|
+
children: [
|
|
481
|
+
{
|
|
482
|
+
id: "46ee87c4-4ea7-48f8-9ed9-14833e4dacc2",
|
|
483
|
+
title: "2025-07-27_06-25-53",
|
|
484
|
+
children: [],
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
id: "1379b081-9f7f-4d82-8470-8321d9b7de0c",
|
|
488
|
+
title: "RUNLINE_LV_3",
|
|
489
|
+
children: [
|
|
490
|
+
{
|
|
491
|
+
id: "cf9145d4-ad06-4433-8384-4c10d266a6aa",
|
|
492
|
+
title: "2025-07-26_19-01-31",
|
|
493
|
+
children: [],
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
id: "f247313c-01cb-4363-a390-a72b889c72d3",
|
|
497
|
+
title: "2025-07-26_19-11-31",
|
|
498
|
+
children: [],
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
id: "0b7c650a-0d78-4e6e-8399-5dbaeb510751",
|
|
502
|
+
title: "Lv4",
|
|
503
|
+
children: [
|
|
504
|
+
{
|
|
505
|
+
id: "88d89572-462d-46c9-b4d0-4df736117799",
|
|
506
|
+
title: "Lv 5",
|
|
507
|
+
children: [],
|
|
508
|
+
},
|
|
509
|
+
],
|
|
510
|
+
},
|
|
511
|
+
],
|
|
512
|
+
},
|
|
513
|
+
],
|
|
514
|
+
},
|
|
515
|
+
],
|
|
516
|
+
},
|
|
517
|
+
render: (args) => {
|
|
518
|
+
const [isCheckedAll, setIsCheckedAll] = useState(false);
|
|
519
|
+
const [checkedId, onCheckedId] = useState<string[]>([]);
|
|
520
|
+
|
|
521
|
+
return (
|
|
522
|
+
<div className="flex flex-col gap-4 w-full">
|
|
523
|
+
<div className="flex gap-2">
|
|
524
|
+
<Button
|
|
525
|
+
variant="outline"
|
|
526
|
+
onClick={() => setIsCheckedAll(!isCheckedAll)}
|
|
527
|
+
>
|
|
528
|
+
{isCheckedAll ? "Unchecked" : "Checked"} All
|
|
529
|
+
</Button>
|
|
530
|
+
<Button variant="outline" onClick={() => onCheckedId([])}>
|
|
531
|
+
Clear
|
|
532
|
+
</Button>
|
|
533
|
+
</div>
|
|
534
|
+
<div className="w-full max-w-[300px]">
|
|
535
|
+
<Tree
|
|
536
|
+
{...args}
|
|
537
|
+
hierarchicalCheck
|
|
538
|
+
checkedAll={isCheckedAll}
|
|
539
|
+
checkedId={checkedId}
|
|
540
|
+
onCheckedChange={(state) => {
|
|
541
|
+
onCheckedId(Object.keys(state).filter((key) => state?.[key]));
|
|
542
|
+
}}
|
|
543
|
+
/>
|
|
544
|
+
</div>
|
|
545
|
+
</div>
|
|
546
|
+
);
|
|
547
|
+
},
|
|
548
|
+
};
|
|
@@ -241,7 +241,7 @@ const TreeItem: FC<TreeItemProps> = ({
|
|
|
241
241
|
{showIcon ? customIcon || defaultIcon : null}
|
|
242
242
|
<div
|
|
243
243
|
className={cn(
|
|
244
|
-
"flex flex-1 cursor-pointer text-subtitle5 text-ellipsis",
|
|
244
|
+
"flex flex-1 cursor-pointer text-subtitle5 text-ellipsis overflow-hidden break-all text-left",
|
|
245
245
|
classes?.title
|
|
246
246
|
)}
|
|
247
247
|
>
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import "./icons/iconConfig";
|
|
|
5
5
|
|
|
6
6
|
export { default as Button } from "./components/Button/Button";
|
|
7
7
|
export { default as TextInput } from "./components/TextInput/TextInput";
|
|
8
|
+
export { default as TextArea } from "./components/TextArea/TextArea";
|
|
8
9
|
export { default as Text } from "./components/Text/Text";
|
|
9
10
|
export { default as Tabs } from "./components/Tabs/Tabs";
|
|
10
11
|
export { default as Dropdown } from "./components/Dropdown/Dropdown";
|
|
@@ -46,6 +47,7 @@ export * from "./components/RadioGroup/RadioGroup";
|
|
|
46
47
|
// Export component types
|
|
47
48
|
export type { ButtonProps } from "./components/Button/Button";
|
|
48
49
|
export type { InputProps } from "./components/TextInput/TextInput";
|
|
50
|
+
export type { TextAreaProps } from "./components/TextArea/TextArea";
|
|
49
51
|
export type { DropdownProps, Options } from "./components/Dropdown/Dropdown";
|
|
50
52
|
export type { NavbarProps } from "./components/Navbar/Navbar";
|
|
51
53
|
export type { AvatarProps } from "./components/Avatar/Avatar";
|
package/src/theme/global.css
CHANGED
|
@@ -28,3 +28,29 @@
|
|
|
28
28
|
-moz-appearance: textfield;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
@layer utilities {
|
|
33
|
+
|
|
34
|
+
.ui-scrollbar::-webkit-scrollbar {
|
|
35
|
+
height: 6px;
|
|
36
|
+
width: 6px;
|
|
37
|
+
background: rgba(0, 0, 0, 0.08);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ui-scrollbar::-webkit-scrollbar-thumb {
|
|
41
|
+
border-radius: 6px;
|
|
42
|
+
background: rgba(121, 141, 150, 0.48);
|
|
43
|
+
width: 6px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.ui-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
47
|
+
background: rgba(251, 252, 253, 0.48);
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.ui-scrollbar::-webkit-scrollbar-corner {
|
|
52
|
+
display: none;
|
|
53
|
+
/* background: transparent; */
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
}
|