@rovula/ui 0.0.53 → 0.0.55

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.
@@ -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;
@@ -82,7 +83,7 @@ export interface TreeProps extends Pick<TreeItemProps, "renderIcon" | "renderRig
82
83
  checkedId?: string[];
83
84
  loadingId?: string[];
84
85
  onExpandChange?: (id: string, expanded: boolean) => void;
85
- onCheckedChange?: (checkedId: string[], uncheckedId: string[], checkedState: Record<string, boolean>) => void;
86
+ onCheckedChange?: (checkedState: Record<string, boolean>) => void;
86
87
  onClickItem?: (id: string) => void;
87
88
  onCheckedItem?: (id: string, checked: boolean) => void;
88
89
  defaultExpandAll?: boolean;
@@ -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
@@ -643,6 +643,7 @@ interface TreeItemProps extends TreeData {
643
643
  maxLevel?: number;
644
644
  checkIsExpanded: (id: string) => boolean;
645
645
  checkIsChecked: (id: string) => boolean;
646
+ checkAutoDisabled: (id: string) => boolean;
646
647
  checkIsLoading?: (id: string) => void;
647
648
  onExpandChange?: (id: string, expanded: boolean) => void;
648
649
  onCheckedChange?: (id: string, checked: boolean) => void;
@@ -696,7 +697,7 @@ interface TreeProps extends Pick<TreeItemProps, "renderIcon" | "renderRightSecti
696
697
  checkedId?: string[];
697
698
  loadingId?: string[];
698
699
  onExpandChange?: (id: string, expanded: boolean) => void;
699
- onCheckedChange?: (checkedId: string[], uncheckedId: string[], checkedState: Record<string, boolean>) => void;
700
+ onCheckedChange?: (checkedState: Record<string, boolean>) => void;
700
701
  onClickItem?: (id: string) => void;
701
702
  onCheckedItem?: (id: string, checked: boolean) => void;
702
703
  defaultExpandAll?: boolean;
@@ -704,6 +705,8 @@ interface TreeProps extends Pick<TreeItemProps, "renderIcon" | "renderRightSecti
704
705
  hierarchicalCheck?: boolean;
705
706
  checkable?: boolean;
706
707
  maxLevel?: number;
708
+ mode: "checkbox" | "radio";
709
+ autoDisabled?: boolean;
707
710
  }
708
711
 
709
712
  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.53",
3
+ "version": "0.0.55",
4
4
  "main": "dist/cjs/bundle.js",
5
5
  "module": "dist/esm/bundle.js",
6
6
  "types": "dist/index.d.ts",
@@ -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,
@@ -107,16 +107,11 @@ export const Controller: StoryObj<typeof Tree> = {
107
107
  defaultExpandAll
108
108
  defaultCheckedId={checkedId}
109
109
  checkedId={checkedId}
110
- onCheckedChange={(ids: string[]) => {
111
- setSelectedSectionList(
112
- Object.keys(selectedSectionList).reduce(
113
- (prev, id) => ({
114
- ...prev,
115
- [id]: ids.includes(id),
116
- }),
117
- {}
118
- )
119
- );
110
+ onCheckedChange={(ids) => {
111
+ setSelectedSectionList((prev) => ({
112
+ ...prev,
113
+ ...ids,
114
+ }));
120
115
  }}
121
116
  />
122
117
  </div>
@@ -387,3 +382,31 @@ export const HideCheckboxMode: StoryObj<typeof Tree> = {
387
382
  );
388
383
  },
389
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
 
@@ -144,15 +163,18 @@ const Tree: FC<TreeProps> = ({
144
163
  setCheckedState(newState);
145
164
 
146
165
  if (onCheckedChange) {
147
- const checkedIds = Object.keys(newState).filter((key) => newState[key]);
148
- const uncheckedIds = Object.keys(newState).filter(
149
- (key) => !newState[key]
150
- );
151
-
152
- onCheckedChange?.(checkedIds, uncheckedIds, newState);
166
+ onCheckedChange?.(newState);
153
167
  }
154
168
  },
155
- [checkedState, data, onCheckedChange, hierarchicalCheck, onCheckedItem]
169
+ [
170
+ checkedState,
171
+ data,
172
+ onCheckedChange,
173
+ hierarchicalCheck,
174
+ onCheckedItem,
175
+ mode,
176
+ autoDisabled,
177
+ ]
156
178
  );
157
179
 
158
180
  const checkIsExpanded = useCallback(
@@ -179,6 +201,17 @@ const Tree: FC<TreeProps> = ({
179
201
  [loadingId]
180
202
  );
181
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
+
182
215
  return (
183
216
  <div className={cn("w-full", classes?.container)}>
184
217
  {data.map((item, idx) => (
@@ -191,13 +224,14 @@ const Tree: FC<TreeProps> = ({
191
224
  checkIsChecked={checkIsChecked}
192
225
  onExpandChange={handleExpandChange}
193
226
  onCheckedChange={handleCheckedChange}
227
+ checkAutoDisabled={checkAutoDisabled}
194
228
  checkIsLoading={checkIsLoading}
195
229
  renderIcon={renderIcon}
196
230
  renderElement={renderElement}
197
231
  renderTitle={renderTitle}
198
232
  renderRightSection={renderRightSection}
199
233
  enableSeparatorLine={enableSeparatorLine}
200
- disabled={disabled}
234
+ disabled={checkAutoDisabled(item.id)}
201
235
  showIcon={showIcon}
202
236
  lineSize={lineSize}
203
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;
@@ -100,11 +101,7 @@ export interface TreeProps
100
101
  checkedId?: string[];
101
102
  loadingId?: string[];
102
103
  onExpandChange?: (id: string, expanded: boolean) => void;
103
- onCheckedChange?: (
104
- checkedId: string[],
105
- uncheckedId: string[],
106
- checkedState: Record<string, boolean>
107
- ) => void;
104
+ onCheckedChange?: (checkedState: Record<string, boolean>) => void;
108
105
  onClickItem?: (id: string) => void;
109
106
  onCheckedItem?: (id: string, checked: boolean) => void;
110
107
  defaultExpandAll?: boolean;
@@ -112,4 +109,7 @@ export interface TreeProps
112
109
  hierarchicalCheck?: boolean;
113
110
  checkable?: boolean;
114
111
  maxLevel?: number;
112
+ mode: "checkbox" | "radio";
113
+ // Only radio mode
114
+ autoDisabled?: boolean;
115
115
  }