@rovula/ui 0.0.54 → 0.0.56

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.
@@ -10,6 +10,7 @@ type Tab = {
10
10
  };
11
11
  type TabsProps = {
12
12
  tabs: Tab[];
13
+ value?: number;
13
14
  initialTab?: number;
14
15
  tabBarSize?: number;
15
16
  tabMode?: "start" | "justify";
@@ -10,6 +10,7 @@ declare const meta: {
10
10
  disabled?: boolean | undefined;
11
11
  isLoading?: boolean | undefined;
12
12
  }[];
13
+ value?: number | undefined;
13
14
  initialTab?: number | undefined;
14
15
  tabBarSize?: number | undefined;
15
16
  tabMode?: "start" | "justify" | undefined;
@@ -44,6 +45,7 @@ declare const meta: {
44
45
  disabled?: boolean | undefined;
45
46
  isLoading?: boolean | undefined;
46
47
  }[];
48
+ value?: number | undefined;
47
49
  initialTab?: number | undefined;
48
50
  tabBarSize?: number | undefined;
49
51
  tabMode?: "start" | "justify" | undefined;
@@ -144,3 +146,15 @@ export declare const Disabled: {
144
146
  };
145
147
  render: (args: {}) => import("react/jsx-runtime").JSX.Element;
146
148
  };
149
+ export declare const Controller: {
150
+ args: {
151
+ initialTab: number;
152
+ value: number;
153
+ tabs: {
154
+ label: string;
155
+ content: import("react/jsx-runtime").JSX.Element;
156
+ }[];
157
+ enableAddTabButton: boolean;
158
+ };
159
+ render: (args: {}) => import("react/jsx-runtime").JSX.Element;
160
+ };
@@ -14,3 +14,4 @@ export declare const ExpandLoadData: StoryObj<typeof Tree>;
14
14
  export declare const MaximumLevel: StoryObj<typeof Tree>;
15
15
  export declare const Leaf: StoryObj<typeof Tree>;
16
16
  export declare const HideCheckboxMode: StoryObj<typeof Tree>;
17
+ export declare const RadioMode: StoryObj<typeof Tree>;
@@ -29,6 +29,7 @@ export interface TreeItemProps extends TreeData {
29
29
  maxLevel?: number;
30
30
  checkIsExpanded: (id: string) => boolean;
31
31
  checkIsChecked: (id: string) => boolean;
32
+ checkAutoDisabled: (id: string) => boolean;
32
33
  checkIsLoading?: (id: string) => void;
33
34
  onExpandChange?: (id: string, expanded: boolean) => void;
34
35
  onCheckedChange?: (id: string, checked: boolean) => void;
@@ -90,4 +91,6 @@ export interface TreeProps extends Pick<TreeItemProps, "renderIcon" | "renderRig
90
91
  hierarchicalCheck?: boolean;
91
92
  checkable?: boolean;
92
93
  maxLevel?: number;
94
+ mode: "checkbox" | "radio";
95
+ autoDisabled?: boolean;
93
96
  }
package/dist/index.d.ts CHANGED
@@ -115,6 +115,7 @@ type Tab = {
115
115
  };
116
116
  type TabsProps = {
117
117
  tabs: Tab[];
118
+ value?: number;
118
119
  initialTab?: number;
119
120
  tabBarSize?: number;
120
121
  tabMode?: "start" | "justify";
@@ -643,6 +644,7 @@ interface TreeItemProps extends TreeData {
643
644
  maxLevel?: number;
644
645
  checkIsExpanded: (id: string) => boolean;
645
646
  checkIsChecked: (id: string) => boolean;
647
+ checkAutoDisabled: (id: string) => boolean;
646
648
  checkIsLoading?: (id: string) => void;
647
649
  onExpandChange?: (id: string, expanded: boolean) => void;
648
650
  onCheckedChange?: (id: string, checked: boolean) => void;
@@ -704,6 +706,8 @@ interface TreeProps extends Pick<TreeItemProps, "renderIcon" | "renderRightSecti
704
706
  hierarchicalCheck?: boolean;
705
707
  checkable?: boolean;
706
708
  maxLevel?: number;
709
+ mode: "checkbox" | "radio";
710
+ autoDisabled?: boolean;
707
711
  }
708
712
 
709
713
  declare const Tree: FC<TreeProps>;
@@ -2501,9 +2501,14 @@ input[type=number] {
2501
2501
  height: 14px;
2502
2502
  }
2503
2503
 
2504
- .size-\[16pt\] {
2505
- width: 16pt;
2506
- height: 16pt;
2504
+ .size-\[16px\] {
2505
+ width: 16px;
2506
+ height: 16px;
2507
+ }
2508
+
2509
+ .size-\[18px\] {
2510
+ width: 18px;
2511
+ height: 18px;
2507
2512
  }
2508
2513
 
2509
2514
  .size-\[30px\] {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rovula/ui",
3
- "version": "0.0.54",
3
+ "version": "0.0.56",
4
4
  "main": "dist/cjs/bundle.js",
5
5
  "module": "dist/esm/bundle.js",
6
6
  "types": "dist/index.d.ts",
@@ -5,6 +5,7 @@ import { ChevronDownIcon, ArchiveBoxIcon } from "@heroicons/react/16/solid";
5
5
  import ActionButton from "../ActionButton/ActionButton";
6
6
  import Icon from "../Icon/Icon";
7
7
  import { useArgs } from "@storybook/preview-api";
8
+ import { Button } from "@/index";
8
9
 
9
10
  const meta = {
10
11
  title: "Components/Tabs",
@@ -209,3 +210,50 @@ export const Disabled = {
209
210
  );
210
211
  },
211
212
  } satisfies StoryObj;
213
+
214
+ export const Controller = {
215
+ args: {
216
+ initialTab: 1,
217
+ value: 0,
218
+ tabs,
219
+ enableAddTabButton: true,
220
+ },
221
+ render: (args) => {
222
+ const props: any = {
223
+ ...args,
224
+ };
225
+
226
+ const [, setArgs] = useArgs();
227
+ return (
228
+ <div className="flex flex-col gap-4 w-[500px]">
229
+ <div className="flex flex-row gap-2">
230
+ <Button onClick={() => setArgs({ ...props.tabs, value: 0 })}>
231
+ Set active tab 0
232
+ </Button>
233
+ <Button onClick={() => setArgs({ ...props.tabs, value: 1 })}>
234
+ Set active tab 1
235
+ </Button>
236
+ <Button onClick={() => setArgs({ ...props.tabs, value: 2 })}>
237
+ Set active tab 2
238
+ </Button>
239
+ </div>
240
+ <Tabs
241
+ tabs={tabs}
242
+ {...props}
243
+ tabMode="start"
244
+ onAddTab={() => {
245
+ setArgs({
246
+ tabs: [
247
+ ...props.tabs,
248
+ {
249
+ label: "Tab" + (props.tabs.length + 1),
250
+ content: <p>Tab {props.tabs.length + 1} content</p>,
251
+ },
252
+ ],
253
+ });
254
+ }}
255
+ />
256
+ </div>
257
+ );
258
+ },
259
+ } satisfies StoryObj;
@@ -16,6 +16,7 @@ type Tab = {
16
16
 
17
17
  type TabsProps = {
18
18
  tabs: Tab[];
19
+ value?: number;
19
20
  initialTab?: number;
20
21
  tabBarSize?: number;
21
22
  tabMode?: "start" | "justify";
@@ -40,6 +41,7 @@ type TabsProps = {
40
41
 
41
42
  const Tabs: React.FC<TabsProps> = ({
42
43
  tabs = [],
44
+ value,
43
45
  initialTab = 0,
44
46
  tabBarSize = 38,
45
47
  enableBorderLine = true,
@@ -69,6 +71,12 @@ const Tabs: React.FC<TabsProps> = ({
69
71
  const tabRefs = useRef<(HTMLButtonElement | null)[]>([]);
70
72
  const isInitialMount = useRef(true);
71
73
 
74
+ useEffect(() => {
75
+ if (value !== undefined) {
76
+ setActiveTab(value);
77
+ }
78
+ }, [value]);
79
+
72
80
  const updateSliderStyle = () => {
73
81
  const activeTabElement = tabRefs.current[activeTab];
74
82
  if (activeTabElement) {
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect, useMemo, useState } from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
  import Tree from "./Tree";
4
- import { ActionButton, Icon } from "@/index";
4
+ import { ActionButton, Button, Icon } from "@/index";
5
5
  import {
6
6
  exampleData,
7
7
  exampleData2,
@@ -382,3 +382,31 @@ export const HideCheckboxMode: StoryObj<typeof Tree> = {
382
382
  );
383
383
  },
384
384
  };
385
+
386
+ export const RadioMode: StoryObj<typeof Tree> = {
387
+ args: {
388
+ data: exampleData,
389
+ mode: "radio",
390
+ autoDisabled: true,
391
+ },
392
+ render: (args) => {
393
+ const [checkedId, onCheckedId] = useState<string[]>(["1"]);
394
+
395
+ return (
396
+ <div className="flex flex-col gap-4 w-full">
397
+ <div>
398
+ <Button variant="outline" onClick={() => onCheckedId([])}>
399
+ Clear
400
+ </Button>
401
+ </div>
402
+ <Tree
403
+ {...args}
404
+ checkedId={checkedId}
405
+ onCheckedChange={(state) => {
406
+ onCheckedId(Object.keys(state).filter((key) => state?.[key]));
407
+ }}
408
+ />
409
+ </div>
410
+ );
411
+ },
412
+ };
@@ -30,6 +30,8 @@ const Tree: FC<TreeProps> = ({
30
30
  enableSeparatorLine = true,
31
31
  checkable = true,
32
32
  maxLevel,
33
+ mode,
34
+ autoDisabled = false,
33
35
  }) => {
34
36
  const [checkedState, setCheckedState] = useState<Record<string, boolean>>({});
35
37
  const [expandedState, setExpandedState] = useState<Record<string, boolean>>(
@@ -83,6 +85,14 @@ const Tree: FC<TreeProps> = ({
83
85
  }
84
86
  }, [data, defaultCheckedId, defaultCheckAll]);
85
87
 
88
+ useEffect(() => {
89
+ if (checkedId !== undefined) {
90
+ setCheckedState(
91
+ checkedId.reduce((prev, cur) => ({ ...prev, [cur]: true }), {})
92
+ );
93
+ }
94
+ }, [checkedId]);
95
+
86
96
  const handleExpandChange = useCallback(
87
97
  (id: string, expanded: boolean) => {
88
98
  onExpandChange?.(id, expanded);
@@ -93,6 +103,15 @@ const Tree: FC<TreeProps> = ({
93
103
 
94
104
  const handleCheckedChange = useCallback(
95
105
  (id: string, checked: boolean) => {
106
+ if (mode === "radio") {
107
+ let newState = { [id]: checked };
108
+
109
+ onCheckedItem?.(id, checked);
110
+ setCheckedState(newState);
111
+ onCheckedChange?.(newState);
112
+
113
+ return;
114
+ }
96
115
  onCheckedItem?.(id, checked);
97
116
  let newState = { ...checkedState, [id]: checked };
98
117
 
@@ -147,7 +166,15 @@ const Tree: FC<TreeProps> = ({
147
166
  onCheckedChange?.(newState);
148
167
  }
149
168
  },
150
- [checkedState, data, onCheckedChange, hierarchicalCheck, onCheckedItem]
169
+ [
170
+ checkedState,
171
+ data,
172
+ onCheckedChange,
173
+ hierarchicalCheck,
174
+ onCheckedItem,
175
+ mode,
176
+ autoDisabled,
177
+ ]
151
178
  );
152
179
 
153
180
  const checkIsExpanded = useCallback(
@@ -174,6 +201,17 @@ const Tree: FC<TreeProps> = ({
174
201
  [loadingId]
175
202
  );
176
203
 
204
+ const checkAutoDisabled = useCallback(
205
+ (id: string) => {
206
+ if (autoDisabled && Object.values(checkedState).filter(Boolean).length) {
207
+ return (!checkedState?.[id] || disabled) ?? false;
208
+ }
209
+
210
+ return false;
211
+ },
212
+ [checkedState, disabled, autoDisabled]
213
+ );
214
+
177
215
  return (
178
216
  <div className={cn("w-full", classes?.container)}>
179
217
  {data.map((item, idx) => (
@@ -186,13 +224,14 @@ const Tree: FC<TreeProps> = ({
186
224
  checkIsChecked={checkIsChecked}
187
225
  onExpandChange={handleExpandChange}
188
226
  onCheckedChange={handleCheckedChange}
227
+ checkAutoDisabled={checkAutoDisabled}
189
228
  checkIsLoading={checkIsLoading}
190
229
  renderIcon={renderIcon}
191
230
  renderElement={renderElement}
192
231
  renderTitle={renderTitle}
193
232
  renderRightSection={renderRightSection}
194
233
  enableSeparatorLine={enableSeparatorLine}
195
- disabled={disabled}
234
+ disabled={checkAutoDisabled(item.id)}
196
235
  showIcon={showIcon}
197
236
  lineSize={lineSize}
198
237
  horizontalLineWidth={horizontalLineWidth}
@@ -20,6 +20,7 @@ const TreeItem: FC<TreeItemProps> = ({
20
20
  checkable,
21
21
  checkIsExpanded,
22
22
  checkIsChecked,
23
+ checkAutoDisabled,
23
24
  checkIsLoading,
24
25
  onExpandChange,
25
26
  onCheckedChange,
@@ -109,7 +110,7 @@ const TreeItem: FC<TreeItemProps> = ({
109
110
  const defaultIcon = (
110
111
  <Icon
111
112
  name={isExpanded ? "folder-open" : "folder"}
112
- className="fill-warning"
113
+ className="fill-warning size-[18px]"
113
114
  />
114
115
  );
115
116
 
@@ -213,7 +214,7 @@ const TreeItem: FC<TreeItemProps> = ({
213
214
  {shouldShowCheckbox ? (
214
215
  <Checkbox
215
216
  id={id}
216
- className={cn("size-[16pt]", classes?.checkbox)}
217
+ className={cn("size-[16px]", classes?.checkbox)}
217
218
  checked={isChecked}
218
219
  disabled={disabled}
219
220
  onCheckedChange={(newChecked) =>
@@ -224,7 +225,7 @@ const TreeItem: FC<TreeItemProps> = ({
224
225
  <div
225
226
  className={
226
227
  isFirstLevel && checkable
227
- ? cn("size-[16pt]", classes?.checkbox)
228
+ ? cn("size-[16px]", classes?.checkbox)
228
229
  : ""
229
230
  }
230
231
  />
@@ -280,13 +281,14 @@ const TreeItem: FC<TreeItemProps> = ({
280
281
  isLastItem={idx === children.length - 1}
281
282
  checkIsExpanded={checkIsExpanded}
282
283
  checkIsChecked={checkIsChecked}
284
+ checkAutoDisabled={checkAutoDisabled}
283
285
  checkIsLoading={checkIsLoading}
284
286
  onExpandChange={onExpandChange}
285
287
  onCheckedChange={onCheckedChange}
286
288
  renderIcon={renderIcon}
287
289
  renderElement={renderElement}
288
290
  renderTitle={renderTitle}
289
- disabled={disabled}
291
+ disabled={checkAutoDisabled(child.id)}
290
292
  showIcon={showIcon}
291
293
  lineSize={lineSize}
292
294
  horizontalLineWidth={horizontalLineWidth}
@@ -31,6 +31,7 @@ export interface TreeItemProps extends TreeData {
31
31
  maxLevel?: number;
32
32
  checkIsExpanded: (id: string) => boolean;
33
33
  checkIsChecked: (id: string) => boolean;
34
+ checkAutoDisabled: (id: string) => boolean;
34
35
  checkIsLoading?: (id: string) => void;
35
36
  onExpandChange?: (id: string, expanded: boolean) => void;
36
37
  onCheckedChange?: (id: string, checked: boolean) => void;
@@ -108,4 +109,7 @@ export interface TreeProps
108
109
  hierarchicalCheck?: boolean;
109
110
  checkable?: boolean;
110
111
  maxLevel?: number;
112
+ mode: "checkbox" | "radio";
113
+ // Only radio mode
114
+ autoDisabled?: boolean;
111
115
  }