@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.
Files changed (32) hide show
  1. package/dist/cjs/bundle.css +36 -0
  2. package/dist/cjs/bundle.js +3 -3
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/TextArea/TextArea.d.ts +38 -0
  5. package/dist/cjs/types/components/TextArea/TextArea.stories.d.ts +9 -0
  6. package/dist/cjs/types/components/TextArea/TextArea.styles.d.ts +27 -0
  7. package/dist/cjs/types/components/Tree/Tree.stories.d.ts +1 -0
  8. package/dist/cjs/types/index.d.ts +2 -0
  9. package/dist/components/TextArea/TextArea.js +55 -0
  10. package/dist/components/TextArea/TextArea.stories.js +86 -0
  11. package/dist/components/TextArea/TextArea.styles.js +207 -0
  12. package/dist/components/Tree/Tree.stories.js +73 -0
  13. package/dist/components/Tree/TreeItem.js +1 -1
  14. package/dist/esm/bundle.css +36 -0
  15. package/dist/esm/bundle.js +3 -3
  16. package/dist/esm/bundle.js.map +1 -1
  17. package/dist/esm/types/components/TextArea/TextArea.d.ts +38 -0
  18. package/dist/esm/types/components/TextArea/TextArea.stories.d.ts +9 -0
  19. package/dist/esm/types/components/TextArea/TextArea.styles.d.ts +27 -0
  20. package/dist/esm/types/components/Tree/Tree.stories.d.ts +1 -0
  21. package/dist/esm/types/index.d.ts +2 -0
  22. package/dist/index.d.ts +38 -1
  23. package/dist/index.js +1 -0
  24. package/dist/src/theme/global.css +46 -0
  25. package/package.json +1 -1
  26. package/src/components/TextArea/TextArea.stories.tsx +134 -0
  27. package/src/components/TextArea/TextArea.styles.ts +228 -0
  28. package/src/components/TextArea/TextArea.tsx +150 -0
  29. package/src/components/Tree/Tree.stories.tsx +100 -0
  30. package/src/components/Tree/TreeItem.tsx +1 -1
  31. package/src/index.ts +2 -0
  32. 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";
@@ -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
+ }