@rovula/ui 0.0.57 → 0.0.59

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.
@@ -5,7 +5,8 @@ export type TreeData<T = {}> = {
5
5
  icon?: ReactNode;
6
6
  disabled?: boolean;
7
7
  isLeaf?: boolean;
8
- onClickItem?: (id: string) => void;
8
+ itemData?: any;
9
+ onClickItem?: (id: string, itemData?: any) => void;
9
10
  children?: TreeData<T>[];
10
11
  renderIcon?: (params: {
11
12
  id: string;
@@ -31,9 +32,9 @@ export interface TreeItemProps extends TreeData {
31
32
  checkIsChecked: (id: string) => boolean;
32
33
  checkAutoDisabled: (id: string) => boolean;
33
34
  checkIsLoading?: (id: string) => void;
34
- onExpandChange?: (id: string, expanded: boolean) => void;
35
+ onExpandChange?: (id: string, expanded: boolean, itemData: any) => void;
35
36
  onCheckedChange?: (id: string, checked: boolean) => void;
36
- notifyClickItem?: (id: string) => void;
37
+ notifyClickItem?: (id: string, itemData: any) => void;
37
38
  renderRightSection?: (params: {
38
39
  id: string;
39
40
  expanded: boolean;
@@ -82,9 +83,9 @@ export interface TreeProps extends Pick<TreeItemProps, "renderIcon" | "renderRig
82
83
  defaultCheckedId?: string[];
83
84
  checkedId?: string[];
84
85
  loadingId?: string[];
85
- onExpandChange?: (id: string, expanded: boolean) => void;
86
- onCheckedChange?: (checkedState: Record<string, boolean>) => void;
87
- onClickItem?: (id: string) => void;
86
+ onExpandChange?: (id: string, expanded: boolean, itemData: any) => void;
87
+ onCheckedChange?: (checkedState: Record<string, boolean>, id?: string) => void;
88
+ onClickItem?: (id: string, itemData: any) => void;
88
89
  onCheckedItem?: (id: string, checked: boolean) => void;
89
90
  defaultExpandAll?: boolean;
90
91
  defaultCheckAll?: boolean;
package/dist/index.d.ts CHANGED
@@ -621,7 +621,8 @@ type TreeData<T = {}> = {
621
621
  icon?: ReactNode;
622
622
  disabled?: boolean;
623
623
  isLeaf?: boolean;
624
- onClickItem?: (id: string) => void;
624
+ itemData?: any;
625
+ onClickItem?: (id: string, itemData?: any) => void;
625
626
  children?: TreeData<T>[];
626
627
  renderIcon?: (params: {
627
628
  id: string;
@@ -647,9 +648,9 @@ interface TreeItemProps extends TreeData {
647
648
  checkIsChecked: (id: string) => boolean;
648
649
  checkAutoDisabled: (id: string) => boolean;
649
650
  checkIsLoading?: (id: string) => void;
650
- onExpandChange?: (id: string, expanded: boolean) => void;
651
+ onExpandChange?: (id: string, expanded: boolean, itemData: any) => void;
651
652
  onCheckedChange?: (id: string, checked: boolean) => void;
652
- notifyClickItem?: (id: string) => void;
653
+ notifyClickItem?: (id: string, itemData: any) => void;
653
654
  renderRightSection?: (params: {
654
655
  id: string;
655
656
  expanded: boolean;
@@ -698,9 +699,9 @@ interface TreeProps extends Pick<TreeItemProps, "renderIcon" | "renderRightSecti
698
699
  defaultCheckedId?: string[];
699
700
  checkedId?: string[];
700
701
  loadingId?: string[];
701
- onExpandChange?: (id: string, expanded: boolean) => void;
702
- onCheckedChange?: (checkedState: Record<string, boolean>) => void;
703
- onClickItem?: (id: string) => void;
702
+ onExpandChange?: (id: string, expanded: boolean, itemData: any) => void;
703
+ onCheckedChange?: (checkedState: Record<string, boolean>, id?: string) => void;
704
+ onClickItem?: (id: string, itemData: any) => void;
704
705
  onCheckedItem?: (id: string, checked: boolean) => void;
705
706
  defaultExpandAll?: boolean;
706
707
  defaultCheckAll?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rovula/ui",
3
- "version": "0.0.57",
3
+ "version": "0.0.59",
4
4
  "main": "dist/cjs/bundle.js",
5
5
  "module": "dist/esm/bundle.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,11 +1,12 @@
1
- import React, { useState } from "react";
1
+ import React, { useEffect, useState } from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
  import Tabs from "./Tabs";
4
4
  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
+ import { Button, Tree } from "@/index";
9
+ import { exampleData } from "../Tree/example-data";
9
10
 
10
11
  const meta = {
11
12
  title: "Components/Tabs",
@@ -211,11 +212,67 @@ export const Disabled = {
211
212
  },
212
213
  } satisfies StoryObj;
213
214
 
215
+ const TabContent = ({ tab }: any) => {
216
+ useEffect(() => {
217
+ console.log("tab ", tab, " Mount");
218
+
219
+ return () => {
220
+ console.log("tab ", tab, " DidMount");
221
+ };
222
+ }, [tab]);
223
+
224
+ return (
225
+ <div>
226
+ <p>Tab {tab} content</p>
227
+ <input />
228
+ <Tree data={exampleData} />
229
+ </div>
230
+ );
231
+ };
232
+
214
233
  export const Controller = {
215
234
  args: {
216
235
  initialTab: 1,
217
236
  value: 0,
218
- tabs,
237
+ tabs: [
238
+ // {
239
+ // label: "Tab1",
240
+ // content: <TabContent tab={1} />,
241
+ // },
242
+ // {
243
+ // label: "Tab2",
244
+ // content: <TabContent tab={2} />,
245
+ // },
246
+ // {
247
+ // label: "Tab3",
248
+ // content: <TabContent tab={3} />,
249
+ // },
250
+
251
+ {
252
+ label: "Tab1",
253
+ content: (
254
+ <div key={`tab-content-key-1`}>
255
+ fdfsdfdsfsdf <input />
256
+ </div>
257
+ ),
258
+ },
259
+ {
260
+ label: "Tab2",
261
+ content: (
262
+ <div key={`tab-content-key-2`}>
263
+ fdfsdfdsfsdf <input />
264
+ </div>
265
+ ),
266
+ },
267
+ {
268
+ label: "Tab3",
269
+ content: (
270
+ <div key={`tab-content-key-3`}>
271
+ fdfsdfdsfsdf <input />
272
+ </div>
273
+ ),
274
+ },
275
+ ],
219
276
  enableAddTabButton: true,
220
277
  },
221
278
  render: (args) => {
@@ -78,46 +78,53 @@ const Tabs: React.FC<TabsProps> = ({
78
78
  }
79
79
  }, [value]);
80
80
 
81
- const updateSliderStyle = () => {
82
- const activeTabElement = tabRefs.current[activeTab];
83
- if (activeTabElement) {
84
- setSliderStyle({
85
- width: `${activeTabElement.offsetWidth}px`,
86
- transform: `translateX(${activeTabElement.offsetLeft}px)`,
87
- });
88
- }
89
- };
81
+ // const updateSliderStyle = () => {
82
+ // const activeTabElement = tabRefs.current[activeTab];
83
+ // if (activeTabElement) {
84
+ // setSliderStyle({
85
+ // width: `${activeTabElement.offsetWidth}px`,
86
+ // transform: `translateX(${activeTabElement.offsetLeft}px)`,
87
+ // });
88
+ // }
89
+ // };
90
90
 
91
- useEffect(() => {
92
- if (isInitialMount.current) {
93
- isInitialMount.current = false;
91
+ // useEffect(() => {
92
+ // let timer: NodeJS.Timeout;
94
93
 
95
- // Set initial position without animation
96
- const activeTabElement = tabRefs.current[activeTab];
97
- if (activeTabElement) {
98
- setSliderStyle({
99
- width: "0px",
100
- transform: `translateX(${
101
- activeTabElement.offsetLeft + activeTabElement.offsetWidth / 2
102
- }px)`,
103
- });
94
+ // if (isInitialMount.current) {
95
+ // isInitialMount.current = false;
104
96
 
105
- // Trigger reflow
106
- setTimeout(() => {
107
- updateSliderStyle();
108
- }, 50);
109
- }
110
- } else {
111
- updateSliderStyle();
112
- }
97
+ // // Set initial position without animation
98
+ // const activeTabElement = tabRefs.current[activeTab];
99
+ // if (activeTabElement) {
100
+ // setSliderStyle({
101
+ // width: "0px",
102
+ // transform: `translateX(${
103
+ // activeTabElement.offsetLeft + activeTabElement.offsetWidth / 2
104
+ // }px)`,
105
+ // });
113
106
 
114
- const handleResize = () => {
115
- updateSliderStyle();
116
- };
107
+ // // Trigger reflow
108
+ // timer = setTimeout(() => {
109
+ // updateSliderStyle();
110
+ // }, 50);
111
+ // }
112
+ // } else {
113
+ // updateSliderStyle();
114
+ // }
117
115
 
118
- window.addEventListener("resize", handleResize);
119
- return () => window.removeEventListener("resize", handleResize);
120
- }, [activeTab, tabs, tabMode, keepIconSpace]);
116
+ // const handleResize = () => {
117
+ // updateSliderStyle();
118
+ // };
119
+
120
+ // window.addEventListener("resize", handleResize);
121
+ // return () => {
122
+ // window.removeEventListener("resize", handleResize);
123
+ // if (timer) {
124
+ // clearTimeout(timer);
125
+ // }
126
+ // };
127
+ // }, [activeTab, tabs, tabMode, keepIconSpace]);
121
128
 
122
129
  return (
123
130
  <div className={cn("w-full", className)}>
@@ -233,9 +240,7 @@ const Tabs: React.FC<TabsProps> = ({
233
240
  id={`tab-content-${activeTab}`}
234
241
  aria-labelledby={`tab-${activeTab}`}
235
242
  >
236
- <div key={tabs[activeTab].label + tabs[activeTab].id ?? Math.random()}>
237
- {tabs[activeTab]?.content}
238
- </div>
243
+ {tabs[activeTab]?.content}
239
244
  </div>
240
245
  </div>
241
246
  );
@@ -335,6 +335,7 @@ export const ExpandLoadData: StoryObj<typeof Tree> = {
335
335
  {...args}
336
336
  data={data}
337
337
  loadingId={loadingId}
338
+ hierarchicalCheck
338
339
  onExpandChange={handleOnExpandChange}
339
340
  />
340
341
  </div>
@@ -93,9 +93,40 @@ const Tree: FC<TreeProps> = ({
93
93
  }
94
94
  }, [checkedId]);
95
95
 
96
+ useEffect(() => {
97
+ if (!hierarchicalCheck) {
98
+ return;
99
+ }
100
+
101
+ const state: Record<string, boolean> = {};
102
+ const updateChildren = (parentId: string, isChecked: boolean) => {
103
+ traverseTree(data, (node) => {
104
+ if (node.id === parentId && node.children) {
105
+ node.children.forEach((child) => {
106
+ state[child.id] = isChecked;
107
+ updateChildren(child.id, isChecked);
108
+ });
109
+ }
110
+ });
111
+ };
112
+
113
+ setCheckedState((prev) => {
114
+ Object.keys(prev)
115
+ .filter((key) => prev[key])
116
+ .map((id) => {
117
+ updateChildren(id, true);
118
+ });
119
+
120
+ return {
121
+ ...prev,
122
+ ...state,
123
+ };
124
+ });
125
+ }, [data, hierarchicalCheck]);
126
+
96
127
  const handleExpandChange = useCallback(
97
- (id: string, expanded: boolean) => {
98
- onExpandChange?.(id, expanded);
128
+ (id: string, expanded: boolean, itemData: any) => {
129
+ onExpandChange?.(id, expanded, itemData);
99
130
  setExpandedState((prev) => ({ ...prev, [id]: expanded }));
100
131
  },
101
132
  [onExpandChange]
@@ -108,7 +139,7 @@ const Tree: FC<TreeProps> = ({
108
139
 
109
140
  onCheckedItem?.(id, checked);
110
141
  setCheckedState(newState);
111
- onCheckedChange?.(newState);
142
+ onCheckedChange?.(newState, id);
112
143
 
113
144
  return;
114
145
  }
@@ -163,7 +194,7 @@ const Tree: FC<TreeProps> = ({
163
194
  setCheckedState(newState);
164
195
 
165
196
  if (onCheckedChange) {
166
- onCheckedChange?.(newState);
197
+ onCheckedChange?.(newState, id);
167
198
  }
168
199
  },
169
200
  [
@@ -36,6 +36,7 @@ const TreeItem: FC<TreeItemProps> = ({
36
36
  currentLevel = 1,
37
37
  maxLevel = 10,
38
38
  notifyClickItem,
39
+ itemData,
39
40
  }) => {
40
41
  const isLoading = useMemo(() => checkIsLoading?.(id), [checkIsLoading, id]);
41
42
  const isChecked = useMemo(() => checkIsChecked(id), [checkIsChecked, id]);
@@ -93,8 +94,8 @@ const TreeItem: FC<TreeItemProps> = ({
93
94
  );
94
95
 
95
96
  const handleExpandToggle = useCallback(() => {
96
- onExpandChange?.(id, !isExpanded);
97
- }, [id, isExpanded, onExpandChange]);
97
+ onExpandChange?.(id, !isExpanded, itemData);
98
+ }, [id, isExpanded, onExpandChange, itemData]);
98
99
 
99
100
  useEffect(() => {
100
101
  if (isExpanded && !isLoading && !hasChildren) {
@@ -103,9 +104,9 @@ const TreeItem: FC<TreeItemProps> = ({
103
104
  }, [isLoading, handleExpandToggle]);
104
105
 
105
106
  const handleOnClickItem = useCallback(() => {
106
- onClickItem?.(id);
107
- notifyClickItem?.(id);
108
- }, [onClickItem, notifyClickItem, id]);
107
+ onClickItem?.(id, itemData);
108
+ notifyClickItem?.(id, itemData);
109
+ }, [id, isExpanded, onClickItem, notifyClickItem, itemData]);
109
110
 
110
111
  const defaultIcon = (
111
112
  <Icon
@@ -254,7 +255,7 @@ const TreeItem: FC<TreeItemProps> = ({
254
255
  {isExpanded && hasChildren && currentLevel < (maxLevel || Infinity) && (
255
256
  <div
256
257
  className={cn(
257
- "flex flex-row overflow-hidden max-h-screen",
258
+ "flex flex-row overflow-hidden",
258
259
  classes?.expandedChildrenWrapper
259
260
  )}
260
261
  >
@@ -269,7 +270,7 @@ const TreeItem: FC<TreeItemProps> = ({
269
270
  )}
270
271
  <div
271
272
  className={cn(
272
- "flex flex-col overflow-hidden max-h-screen",
273
+ "flex flex-col overflow-hidden",
273
274
  classes?.expandedChildrenWrapperInner
274
275
  )}
275
276
  style={styles.childPadding}
@@ -6,7 +6,8 @@ export type TreeData<T = {}> = {
6
6
  icon?: ReactNode;
7
7
  disabled?: boolean;
8
8
  isLeaf?: boolean;
9
- onClickItem?: (id: string) => void;
9
+ itemData?: any;
10
+ onClickItem?: (id: string, itemData?: any) => void;
10
11
  children?: TreeData<T>[]; // Recursively include additional data
11
12
  renderIcon?: (params: {
12
13
  id: string;
@@ -33,9 +34,9 @@ export interface TreeItemProps extends TreeData {
33
34
  checkIsChecked: (id: string) => boolean;
34
35
  checkAutoDisabled: (id: string) => boolean;
35
36
  checkIsLoading?: (id: string) => void;
36
- onExpandChange?: (id: string, expanded: boolean) => void;
37
+ onExpandChange?: (id: string, expanded: boolean, itemData: any) => void;
37
38
  onCheckedChange?: (id: string, checked: boolean) => void;
38
- notifyClickItem?: (id: string) => void;
39
+ notifyClickItem?: (id: string, itemData: any) => void;
39
40
  renderRightSection?: (params: {
40
41
  id: string;
41
42
  expanded: boolean;
@@ -100,9 +101,12 @@ export interface TreeProps
100
101
  defaultCheckedId?: string[];
101
102
  checkedId?: string[];
102
103
  loadingId?: string[];
103
- onExpandChange?: (id: string, expanded: boolean) => void;
104
- onCheckedChange?: (checkedState: Record<string, boolean>) => void;
105
- onClickItem?: (id: string) => void;
104
+ onExpandChange?: (id: string, expanded: boolean, itemData: any) => void;
105
+ onCheckedChange?: (
106
+ checkedState: Record<string, boolean>,
107
+ id?: string
108
+ ) => void;
109
+ onClickItem?: (id: string, itemData: any) => void;
106
110
  onCheckedItem?: (id: string, checked: boolean) => void;
107
111
  defaultExpandAll?: boolean;
108
112
  defaultCheckAll?: boolean;