@rovula/ui 0.0.47 → 0.0.49

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 (45) hide show
  1. package/dist/cjs/bundle.css +32 -4
  2. package/dist/cjs/bundle.js +3 -3
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/Switch/Switch.stories.d.ts +1 -6
  5. package/dist/cjs/types/components/Tree/Tree.d.ts +4 -0
  6. package/dist/cjs/types/components/Tree/Tree.stories.d.ts +12 -0
  7. package/dist/cjs/types/components/Tree/TreeItem.d.ts +4 -0
  8. package/dist/cjs/types/components/Tree/index.d.ts +4 -0
  9. package/dist/cjs/types/components/Tree/type.d.ts +76 -0
  10. package/dist/cjs/types/index.d.ts +1 -0
  11. package/dist/components/Switch/Switch.js +2 -2
  12. package/dist/components/Switch/Switch.stories.js +2 -7
  13. package/dist/components/Tree/Tree.js +104 -0
  14. package/dist/components/Tree/Tree.stories.js +162 -0
  15. package/dist/components/Tree/TreeItem.js +81 -0
  16. package/dist/components/Tree/index.js +4 -0
  17. package/dist/components/Tree/type.js +1 -0
  18. package/dist/esm/bundle.css +32 -4
  19. package/dist/esm/bundle.js +1 -1
  20. package/dist/esm/bundle.js.map +1 -1
  21. package/dist/esm/types/components/Switch/Switch.stories.d.ts +1 -6
  22. package/dist/esm/types/components/Tree/Tree.d.ts +4 -0
  23. package/dist/esm/types/components/Tree/Tree.stories.d.ts +12 -0
  24. package/dist/esm/types/components/Tree/TreeItem.d.ts +4 -0
  25. package/dist/esm/types/components/Tree/index.d.ts +4 -0
  26. package/dist/esm/types/components/Tree/type.d.ts +76 -0
  27. package/dist/esm/types/index.d.ts +1 -0
  28. package/dist/index.d.ts +82 -2
  29. package/dist/index.js +1 -0
  30. package/dist/src/theme/global.css +75 -14
  31. package/dist/theme/themes/SKL/color.css +10 -10
  32. package/dist/theme/themes/xspector/baseline.css +1 -0
  33. package/dist/theme/themes/xspector/components/switch.css +30 -0
  34. package/package.json +1 -1
  35. package/src/components/Switch/Switch.stories.tsx +2 -7
  36. package/src/components/Switch/Switch.tsx +2 -2
  37. package/src/components/Tree/Tree.stories.tsx +288 -0
  38. package/src/components/Tree/Tree.tsx +192 -0
  39. package/src/components/Tree/TreeItem.tsx +231 -0
  40. package/src/components/Tree/index.ts +5 -0
  41. package/src/components/Tree/type.ts +90 -0
  42. package/src/index.ts +1 -0
  43. package/src/theme/themes/SKL/color.css +10 -10
  44. package/src/theme/themes/xspector/baseline.css +1 -0
  45. package/src/theme/themes/xspector/components/switch.css +30 -0
@@ -293,13 +293,8 @@ declare const meta: {
293
293
  export default meta;
294
294
  export declare const Default: {
295
295
  args: {
296
- defaultValue: number[];
297
- max: number;
298
- step: number;
299
- name: string;
300
- minStepsBetweenThumbs: number;
296
+ checked: boolean;
301
297
  disabled: boolean;
302
- inverted: boolean;
303
298
  };
304
299
  render: (args: {}) => import("react/jsx-runtime").JSX.Element;
305
300
  };
@@ -0,0 +1,4 @@
1
+ import { FC } from "react";
2
+ import { TreeProps } from "./type";
3
+ declare const Tree: FC<TreeProps>;
4
+ export default Tree;
@@ -0,0 +1,12 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import Tree from "./Tree";
3
+ declare const meta: Meta<typeof Tree>;
4
+ export default meta;
5
+ export declare const Default: StoryObj<typeof Tree>;
6
+ export declare const onClick: StoryObj<typeof Tree>;
7
+ export declare const CustomIcon: StoryObj<typeof Tree>;
8
+ export declare const renderRightSection: StoryObj<typeof Tree>;
9
+ export declare const ControlShowExpandButton: StoryObj<typeof Tree>;
10
+ export declare const Diabled: StoryObj<typeof Tree>;
11
+ export declare const DiabledEachItem: StoryObj<typeof Tree>;
12
+ export declare const ExpandLoadData: StoryObj<typeof Tree>;
@@ -0,0 +1,4 @@
1
+ import { FC } from "react";
2
+ import { TreeItemProps } from "./type";
3
+ declare const TreeItem: FC<TreeItemProps>;
4
+ export default TreeItem;
@@ -0,0 +1,4 @@
1
+ import Tree from "./Tree";
2
+ import TreeItem from "./TreeItem";
3
+ export * from "./type";
4
+ export { Tree, TreeItem };
@@ -0,0 +1,76 @@
1
+ import { CSSProperties, ReactNode } from "react";
2
+ export type TreeData = {
3
+ id: string;
4
+ title: string;
5
+ icon?: ReactNode;
6
+ disabled?: boolean;
7
+ onClickItem?: (id: string) => void;
8
+ children?: TreeData[];
9
+ renderIcon?: (params: {
10
+ id: string;
11
+ expanded: boolean;
12
+ selected: boolean;
13
+ }) => ReactNode;
14
+ };
15
+ export interface TreeItemProps extends TreeData {
16
+ isFirstLevel?: boolean;
17
+ isLastItem: boolean;
18
+ disabled?: boolean;
19
+ showIcon?: boolean;
20
+ showExpandButton?: boolean;
21
+ enableSeparatorLine?: boolean;
22
+ checkIsExpanded: (id: string) => boolean;
23
+ checkIsChecked: (id: string) => boolean;
24
+ checkIsLoading?: (id: string) => void;
25
+ onExpandChange?: (id: string, expanded: boolean) => void;
26
+ onCheckedChange?: (id: string, checked: boolean) => void;
27
+ renderRightSection?: (params: {
28
+ id: string;
29
+ expanded: boolean;
30
+ selected: boolean;
31
+ }) => ReactNode;
32
+ renderElement?: (params: {
33
+ id: string;
34
+ expanded: boolean;
35
+ selected: boolean;
36
+ children: ReactNode;
37
+ styles: {
38
+ branch: CSSProperties;
39
+ horizontalLine: CSSProperties;
40
+ expandButton: CSSProperties;
41
+ childPadding: CSSProperties;
42
+ };
43
+ onClick?: TreeItemProps["onClickItem"];
44
+ }) => ReactNode;
45
+ renderTitle?: (params: {
46
+ id: string;
47
+ title: string;
48
+ expanded: boolean;
49
+ selected: boolean;
50
+ }) => ReactNode;
51
+ classes?: Partial<{
52
+ elementWrapper: string;
53
+ branch: string;
54
+ itemWrapper: string;
55
+ itemContainer: string;
56
+ horizontalLine: string;
57
+ expandButton: string;
58
+ separatorLine: string;
59
+ checkbox: string;
60
+ item: string;
61
+ title: string;
62
+ childrenWrapper: string;
63
+ }>;
64
+ }
65
+ export interface TreeProps extends Pick<TreeItemProps, "renderIcon" | "renderRightSection" | "renderElement" | "renderTitle" | "showIcon" | "disabled" | "enableSeparatorLine" | "classes"> {
66
+ data: TreeData[];
67
+ defaultExpandedId?: string[];
68
+ defaultCheckedId?: string[];
69
+ checkedId?: string[];
70
+ loadingId?: string[];
71
+ onExpandChange?: (id: string, expanded: boolean) => void;
72
+ onCheckedChange?: (checkedId: string[]) => void;
73
+ defaultExpandAll?: boolean;
74
+ defaultCheckAll?: boolean;
75
+ hierarchicalCheck?: boolean;
76
+ }
@@ -32,6 +32,7 @@ export * from "./components/Tooltip/TooltipSimple";
32
32
  export * from "./components/Toast/Toast";
33
33
  export * from "./components/Toast/Toaster";
34
34
  export * from "./components/Toast/useToast";
35
+ export * from "./components/Tree";
35
36
  export type { ButtonProps } from "./components/Button/Button";
36
37
  export type { InputProps } from "./components/TextInput/TextInput";
37
38
  export type { DropdownProps, Options } from "./components/Dropdown/Dropdown";
@@ -18,7 +18,7 @@ const switchBaseClasses = "group inline-flex h-3 w-[32px] shrink-0 cursor-pointe
18
18
  const switchStateClasses = {
19
19
  unchecked: "data-[state=unchecked]:bg-[var(--switch-default-color)] hover:data-[state=unchecked]:bg-[var(--switch-hover-color)]",
20
20
  checked: "data-[state=checked]:bg-[var(--switch-active-color)] hover:data-[state=checked]:bg-[var(--switch-active-hover-color)]",
21
- disabled: "data-[disabled]:cursor-not-allowed data-[disabled]:bg-[var(--switch-disabled-color)] data-[disabled]:pointer-events-none",
21
+ disabled: "data-[disabled]:cursor-not-allowed data-[disabled]:!bg-[var(--switch-disabled-color)] data-[disabled]:pointer-events-none",
22
22
  };
23
23
  const thumbBaseClasses = "block size-4 rounded-full shadow-lg transition-transform";
24
24
  const thumbStateClasses = {
@@ -26,7 +26,7 @@ const thumbStateClasses = {
26
26
  checked: "data-[state=checked]:bg-[var(--switch-thumb-active-color)] data-[state=checked]:translate-x-4",
27
27
  hover: "group-hover:ring group-hover:data-[state=checked]:ring-[var(--switch-thumb-active-hover-ring)] group-hover:data-[state=unchecked]:ring-[var(--switch-thumb-hover-ring)]",
28
28
  hoverColor: "group-hover:data-[state=checked]:bg-[var(--switch-thumb-active-hover-color)] group-hover:data-[state=unchecked]:bg-[var(--switch-thumb-hover-color)]",
29
- disabled: "group-disabled:bg-[--switch-thumb-disabled-color]",
29
+ disabled: "group-disabled:!bg-[--switch-thumb-disabled-color]",
30
30
  };
31
31
  const Switch = React.forwardRef((_a, ref) => {
32
32
  var { className } = _a, props = __rest(_a, ["className"]);
@@ -10,19 +10,14 @@ const meta = {
10
10
  layout: "fullscreen",
11
11
  },
12
12
  decorators: [
13
- (Story) => (_jsx("div", { className: "p-5 flex w-full", children: _jsx(Story, {}) })),
13
+ (Story) => (_jsx("div", { className: "p-5 flex w-full bg-base-bg2", children: _jsx(Story, {}) })),
14
14
  ],
15
15
  };
16
16
  export default meta;
17
17
  export const Default = {
18
18
  args: {
19
- defaultValue: [50],
20
- max: 100,
21
- step: 1,
22
- name: "test",
23
- minStepsBetweenThumbs: 1,
19
+ checked: false,
24
20
  disabled: false,
25
- inverted: false,
26
21
  },
27
22
  render: (args) => {
28
23
  console.log("args ", args);
@@ -0,0 +1,104 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import TreeItem from "./TreeItem";
4
+ const Tree = ({ classes, data, defaultExpandedId = [], defaultCheckedId = [], checkedId, loadingId, renderIcon, renderRightSection, renderElement, renderTitle, onExpandChange, onCheckedChange, defaultExpandAll = false, defaultCheckAll = false, hierarchicalCheck = false, showIcon = true, disabled, enableSeparatorLine = true, }) => {
5
+ const [checkedState, setCheckedState] = useState({});
6
+ const [expandedState, setExpandedState] = useState({});
7
+ const traverseTree = (nodes, callback) => {
8
+ nodes.forEach((node) => {
9
+ callback(node);
10
+ if (node.children) {
11
+ traverseTree(node.children, callback);
12
+ }
13
+ });
14
+ };
15
+ useEffect(() => {
16
+ if (defaultExpandAll) {
17
+ const allExpanded = {};
18
+ traverseTree(data, (node) => {
19
+ allExpanded[node.id] = true;
20
+ });
21
+ setExpandedState(allExpanded);
22
+ }
23
+ else if (defaultExpandedId === null || defaultExpandedId === void 0 ? void 0 : defaultExpandedId.length) {
24
+ const initialExpandedState = defaultExpandedId.reduce((acc, id) => {
25
+ acc[id] = true;
26
+ return acc;
27
+ }, {});
28
+ setExpandedState(initialExpandedState);
29
+ }
30
+ }, [data, defaultExpandedId, defaultExpandAll]);
31
+ useEffect(() => {
32
+ if (defaultCheckAll) {
33
+ const allChecked = {};
34
+ traverseTree(data, (node) => {
35
+ allChecked[node.id] = true;
36
+ });
37
+ setCheckedState(allChecked);
38
+ }
39
+ else if (!checkedId && (defaultCheckedId === null || defaultCheckedId === void 0 ? void 0 : defaultCheckedId.length)) {
40
+ const initialCheckedState = defaultCheckedId.reduce((acc, id) => {
41
+ acc[id] = true;
42
+ return acc;
43
+ }, {});
44
+ setCheckedState(initialCheckedState);
45
+ }
46
+ }, [data, defaultCheckedId, checkedId, defaultCheckAll]);
47
+ const handleExpandChange = useCallback((id, expanded) => {
48
+ onExpandChange === null || onExpandChange === void 0 ? void 0 : onExpandChange(id, expanded);
49
+ setExpandedState((prev) => (Object.assign(Object.assign({}, prev), { [id]: expanded })));
50
+ }, [onExpandChange]);
51
+ const handleCheckedChange = useCallback((id, checked) => {
52
+ let newState = Object.assign(Object.assign({}, checkedState), { [id]: checked });
53
+ if (hierarchicalCheck) {
54
+ const updateCheckedState = (nodeId, isChecked, state) => {
55
+ state[nodeId] = isChecked;
56
+ // Update children recursively
57
+ const updateChildren = (parentId, isChecked) => {
58
+ traverseTree(data, (node) => {
59
+ if (node.id === parentId && node.children) {
60
+ node.children.forEach((child) => {
61
+ state[child.id] = isChecked;
62
+ updateChildren(child.id, isChecked);
63
+ });
64
+ }
65
+ });
66
+ };
67
+ // Update parents recursively
68
+ const updateParents = (childId, state) => {
69
+ traverseTree(data, (node) => {
70
+ var _a;
71
+ if ((_a = node.children) === null || _a === void 0 ? void 0 : _a.some((child) => child.id === childId)) {
72
+ const allChildrenChecked = node.children.every((child) => state[child.id]);
73
+ state[node.id] = allChildrenChecked;
74
+ updateParents(node.id, state);
75
+ }
76
+ });
77
+ };
78
+ updateChildren(nodeId, isChecked);
79
+ updateParents(nodeId, state);
80
+ return state;
81
+ };
82
+ newState = updateCheckedState(id, checked, newState);
83
+ }
84
+ setCheckedState(newState);
85
+ if (onCheckedChange) {
86
+ const checkedIds = Object.keys(newState).filter((key) => newState[key]);
87
+ onCheckedChange(checkedIds);
88
+ }
89
+ }, [checkedState, data, onCheckedChange, hierarchicalCheck]);
90
+ const checkIsExpanded = useCallback((id) => !!expandedState[id], [expandedState]);
91
+ const checkIsChecked = useCallback((id) => {
92
+ if (checkedId) {
93
+ return checkedId.includes(id);
94
+ }
95
+ return !!checkedState[id];
96
+ }, [checkedId, checkedState]);
97
+ const checkIsLoading = useCallback((id) => {
98
+ if (loadingId) {
99
+ return loadingId.includes(id);
100
+ }
101
+ }, [loadingId]);
102
+ return (_jsx("div", { className: "w-full", children: data.map((item, idx) => (_jsx(TreeItem, Object.assign({ classes: classes, isFirstLevel: true, isLastItem: idx === data.length - 1, checkIsExpanded: checkIsExpanded, checkIsChecked: checkIsChecked, onExpandChange: handleExpandChange, onCheckedChange: handleCheckedChange, checkIsLoading: checkIsLoading, renderIcon: renderIcon, renderElement: renderElement, renderTitle: renderTitle, renderRightSection: renderRightSection, enableSeparatorLine: enableSeparatorLine, disabled: disabled, showIcon: showIcon }, item), item.id))) }));
103
+ };
104
+ export default Tree;
@@ -0,0 +1,162 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import Tree from "./Tree";
4
+ import { ActionButton, Icon } from "@/index";
5
+ const exampleData = [
6
+ {
7
+ id: "1",
8
+ title: "Parent Folder 1",
9
+ children: [
10
+ {
11
+ id: "1.1",
12
+ title: "Child Folder 1.1",
13
+ children: [
14
+ { id: "1.1.1", title: "Sub Folder 1.1.1" },
15
+ { id: "1.1.2", title: "Sub Folder 1.1.2" },
16
+ ],
17
+ },
18
+ { id: "1.2", title: "Child Folder 1.2" },
19
+ ],
20
+ },
21
+ {
22
+ id: "2",
23
+ title: "Parent Folder 2",
24
+ children: [{ id: "2.1", title: "Child Folder 2.1" }],
25
+ },
26
+ { id: "3", title: "Parent Folder 3" },
27
+ ];
28
+ const commonProps = {
29
+ defaultExpandedId: ["1", "1.1"],
30
+ defaultCheckedId: ["1.1"],
31
+ defaultExpandAll: true,
32
+ defaultCheckAll: true,
33
+ hierarchicalCheck: true,
34
+ disabled: false,
35
+ showIcon: true,
36
+ };
37
+ // Storybook metadata
38
+ const meta = {
39
+ title: "Components/Tree",
40
+ component: Tree,
41
+ tags: ["autodocs"],
42
+ parameters: {
43
+ layout: "fullscreen",
44
+ },
45
+ decorators: [
46
+ (Story) => (_jsx("div", { className: "p-5 flex w-full bg-base-bg", children: _jsx(Story, {}) })),
47
+ ],
48
+ };
49
+ export default meta;
50
+ // Default story
51
+ export const Default = {
52
+ args: Object.assign(Object.assign({ data: exampleData }, commonProps), { showIcon: true }),
53
+ render: (args) => {
54
+ return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Tree, Object.assign({}, args)) }));
55
+ },
56
+ };
57
+ export const onClick = {
58
+ args: Object.assign({ data: exampleData.map((item) => (Object.assign(Object.assign({}, item), { onClickItem: (id) => alert("Click item " + id) }))) }, commonProps),
59
+ render: (args) => {
60
+ return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Tree, Object.assign({}, args)) }));
61
+ },
62
+ };
63
+ export const CustomIcon = {
64
+ args: Object.assign({ data: exampleData.map((item, idx) => (Object.assign(Object.assign(Object.assign({}, item), (idx === 0 && {
65
+ icon: _jsx(Icon, { name: "home" }),
66
+ })), (idx === 1 && {
67
+ renderIcon: ({ expanded, selected }) => (_jsx(Icon, { name: expanded ? "home" : "home-modern", className: selected ? "fill-info" : "fill-error" })),
68
+ })))) }, commonProps),
69
+ render: (args) => {
70
+ return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Tree, Object.assign({}, args, { renderIcon: ({ expanded, selected }) => (_jsx(Icon, { name: expanded ? "bell" : "bell-slash", className: selected ? "fill-primary" : "fill-secondary" })) })) }));
71
+ },
72
+ };
73
+ export const renderRightSection = {
74
+ args: Object.assign({ data: exampleData }, commonProps),
75
+ render: (args) => {
76
+ return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Tree, Object.assign({}, args, { renderRightSection: () => (_jsx(ActionButton, { variant: "icon", onClick: () => alert("Say hi!"), children: _jsx(Icon, { name: "ellipsis-vertical" }) })) })) }));
77
+ },
78
+ };
79
+ export const ControlShowExpandButton = {
80
+ args: {
81
+ data: exampleData.map((item) => (Object.assign(Object.assign({}, item), { showExpandButton: true }))),
82
+ },
83
+ render: (args) => {
84
+ return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Tree, Object.assign({}, args)) }));
85
+ },
86
+ };
87
+ export const Diabled = {
88
+ args: Object.assign(Object.assign({ data: exampleData }, commonProps), { disabled: true }),
89
+ render: (args) => {
90
+ return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Tree, Object.assign({}, args, { renderRightSection: () => (_jsx(ActionButton, { variant: "icon", onClick: () => alert("Say hi!"), children: _jsx(Icon, { name: "ellipsis-vertical" }) })) })) }));
91
+ },
92
+ };
93
+ export const DiabledEachItem = {
94
+ args: Object.assign(Object.assign({ data: exampleData.map((item, i) => (Object.assign(Object.assign({}, item), { disabled: i === 0 }))) }, commonProps), { disabled: undefined }),
95
+ render: (args) => {
96
+ return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Tree, Object.assign({}, args, { renderRightSection: () => (_jsx(ActionButton, { variant: "icon", onClick: () => alert("Say hi!"), children: _jsx(Icon, { name: "ellipsis-vertical" }) })) })) }));
97
+ },
98
+ };
99
+ export const ExpandLoadData = {
100
+ args: {},
101
+ render: (args) => {
102
+ const [data, setData] = useState([
103
+ {
104
+ id: "1",
105
+ title: "Parent Folder 1",
106
+ showExpandButton: true,
107
+ children: [],
108
+ },
109
+ {
110
+ id: "2",
111
+ title: "Parent Folder 2",
112
+ showExpandButton: true,
113
+ children: [],
114
+ },
115
+ {
116
+ id: "3",
117
+ title: "Parent Folder 3",
118
+ showExpandButton: true,
119
+ children: [],
120
+ },
121
+ ]);
122
+ const [loadingId, setLoadingId] = useState([]);
123
+ const [loadedId, setLoadedId] = useState([]);
124
+ const updateNode = (nodes, id, newChildren) => nodes.map((node) => {
125
+ var _a;
126
+ if (node.id === id) {
127
+ return Object.assign(Object.assign({}, node), { children: newChildren });
128
+ }
129
+ if ((_a = node.children) === null || _a === void 0 ? void 0 : _a.length) {
130
+ return Object.assign(Object.assign({}, node), { children: updateNode(node.children, id, newChildren) });
131
+ }
132
+ return node;
133
+ });
134
+ const handleOnExpandChange = (id, isExpand) => {
135
+ // *Note can you other way for improve should load if need with other way without loadedId
136
+ if (isExpand && !loadingId.includes(id) && !loadedId.includes(id)) {
137
+ setLoadingId((prev) => [...prev, id]);
138
+ setTimeout(() => {
139
+ // Mock child data
140
+ const newChildren = [
141
+ {
142
+ id: Date.now() + "1",
143
+ title: `Child of ${id} - 1`,
144
+ children: [],
145
+ showExpandButton: true,
146
+ },
147
+ {
148
+ id: Date.now() + "2",
149
+ title: `Child of ${id} - 2`,
150
+ children: [],
151
+ showExpandButton: true,
152
+ },
153
+ ];
154
+ setData((prevData) => updateNode(prevData, id, newChildren));
155
+ setLoadingId((prev) => prev.filter((val) => val !== id));
156
+ setLoadedId((prev) => [...prev, id]);
157
+ }, 1500);
158
+ }
159
+ };
160
+ return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Tree, Object.assign({}, args, { data: data, loadingId: loadingId, onExpandChange: handleOnExpandChange })) }));
161
+ },
162
+ };
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ActionButton, Checkbox, Loading } from "@/index";
3
+ import { cn } from "@/utils/cn";
4
+ import { useCallback, useEffect, useMemo } from "react";
5
+ import Icon from "../Icon/Icon";
6
+ const TreeItem = ({ id, title, classes, children, isFirstLevel = false, disabled, icon, showIcon, showExpandButton, enableSeparatorLine = true, isLastItem, checkIsExpanded, checkIsChecked, checkIsLoading, onExpandChange, onCheckedChange, onClickItem, renderIcon, renderElement, renderTitle, renderRightSection, }) => {
7
+ const isLoading = useMemo(() => checkIsLoading === null || checkIsLoading === void 0 ? void 0 : checkIsLoading(id), [checkIsLoading, id]);
8
+ const isChecked = useMemo(() => checkIsChecked(id), [checkIsChecked, id]);
9
+ const isExpanded = useMemo(() => checkIsExpanded(id), [checkIsExpanded, id]);
10
+ const hasChildren = useMemo(() => !!(children === null || children === void 0 ? void 0 : children.length), [children]);
11
+ const shouldExpandButton = useMemo(() => (showExpandButton !== undefined ? showExpandButton : hasChildren), [hasChildren, showExpandButton]);
12
+ const handleExpandToggle = useCallback(() => {
13
+ onExpandChange === null || onExpandChange === void 0 ? void 0 : onExpandChange(id, !isExpanded);
14
+ }, [id, isExpanded, onExpandChange]);
15
+ // TODO move to props
16
+ const lineSize = 2;
17
+ const horizontalLineWidth = 4;
18
+ const expandButtonSize = 30;
19
+ const spacing = 2;
20
+ const styles = {
21
+ branch: {
22
+ height: isLastItem
23
+ ? `calc(50% + ${lineSize}px)`
24
+ : `calc(100% + ${lineSize}px)`,
25
+ width: lineSize,
26
+ marginTop: -lineSize,
27
+ borderBottomLeftRadius: lineSize / 2,
28
+ },
29
+ horizontalLine: {
30
+ height: lineSize,
31
+ width: lineSize +
32
+ horizontalLineWidth +
33
+ (shouldExpandButton ? 0 : expandButtonSize + spacing),
34
+ marginLeft: -lineSize + 0.1,
35
+ borderBottomLeftRadius: lineSize / 2,
36
+ },
37
+ expandButton: {
38
+ width: expandButtonSize,
39
+ height: expandButtonSize,
40
+ },
41
+ childPadding: {
42
+ paddingLeft: isFirstLevel
43
+ ? expandButtonSize / 2 - lineSize / 2
44
+ : expandButtonSize / 2 + horizontalLineWidth - lineSize / 2,
45
+ },
46
+ };
47
+ useEffect(() => {
48
+ if (isExpanded && !isLoading && !hasChildren) {
49
+ handleExpandToggle();
50
+ }
51
+ }, [isLoading, handleExpandToggle]);
52
+ const handleOnClickItem = useCallback(() => {
53
+ onClickItem === null || onClickItem === void 0 ? void 0 : onClickItem(id);
54
+ }, [onClickItem, id]);
55
+ const defaultIcon = (_jsx(Icon, { name: isExpanded ? "folder-open" : "folder", className: "fill-warning" }));
56
+ const customIcon = icon !== null && icon !== void 0 ? icon : renderIcon === null || renderIcon === void 0 ? void 0 : renderIcon({
57
+ id,
58
+ expanded: isExpanded,
59
+ selected: isChecked,
60
+ });
61
+ const rightIcon = renderRightSection === null || renderRightSection === void 0 ? void 0 : renderRightSection({
62
+ id,
63
+ expanded: isExpanded,
64
+ selected: isChecked,
65
+ });
66
+ const titleContent = renderTitle
67
+ ? renderTitle({ id, title, expanded: isExpanded, selected: isChecked })
68
+ : title;
69
+ const elementWrapper = (content) => renderElement
70
+ ? renderElement({
71
+ id,
72
+ expanded: isExpanded,
73
+ selected: isChecked,
74
+ children: content,
75
+ styles,
76
+ onClick: handleOnClickItem,
77
+ })
78
+ : content;
79
+ return elementWrapper(_jsxs("div", { className: cn("flex flex-row w-full", classes === null || classes === void 0 ? void 0 : classes.elementWrapper), children: [_jsx("div", { className: cn("bg-grey-150", { "h-1/2": isLastItem }, classes === null || classes === void 0 ? void 0 : classes.branch), style: styles.branch }), _jsxs("div", { className: cn("flex flex-col w-full", classes === null || classes === void 0 ? void 0 : classes.itemWrapper), children: [_jsxs("div", { className: cn("flex items-center py-2 min-h-10", classes === null || classes === void 0 ? void 0 : classes.itemContainer), children: [!isFirstLevel && (_jsx("div", { className: cn("bg-grey-150", classes === null || classes === void 0 ? void 0 : classes.horizontalLine), style: styles.horizontalLine })), isFirstLevel && !shouldExpandButton && (_jsx("div", { className: cn("flex mr-[2px]", classes === null || classes === void 0 ? void 0 : classes.expandButton), style: styles.expandButton })), shouldExpandButton && (_jsx("div", { className: cn("flex mr-[2px]", classes === null || classes === void 0 ? void 0 : classes.expandButton), style: styles.expandButton, onClick: !isLoading && handleExpandToggle, children: _jsx(ActionButton, { variant: "icon", size: "sm", children: isLoading ? (_jsx(Loading, {})) : (_jsx(Icon, { name: isExpanded ? "chevron-down" : "chevron-right" })) }) })), _jsx(Checkbox, { id: id, className: cn("size-[16pt]", classes === null || classes === void 0 ? void 0 : classes.checkbox), checked: isChecked, disabled: disabled, onCheckedChange: (newChecked) => onCheckedChange === null || onCheckedChange === void 0 ? void 0 : onCheckedChange(id, newChecked) }), _jsxs("div", { className: cn("ml-2 gap-1 flex flex-1 items-center text-foreground", classes === null || classes === void 0 ? void 0 : classes.item), onClick: handleOnClickItem, children: [showIcon ? customIcon || defaultIcon : null, _jsx("div", { className: cn("flex flex-1 cursor-pointer text-subtitle5 text-ellipsis", classes === null || classes === void 0 ? void 0 : classes.title), children: titleContent })] }), rightIcon] }), isExpanded && hasChildren && (_jsx("div", { className: cn("flex flex-col", classes === null || classes === void 0 ? void 0 : classes.childrenWrapper), style: styles.childPadding, children: children === null || children === void 0 ? void 0 : children.map((child, idx) => (_jsx(TreeItem, Object.assign({ classes: classes, isLastItem: idx === children.length - 1, checkIsExpanded: checkIsExpanded, checkIsChecked: checkIsChecked, checkIsLoading: checkIsLoading, onExpandChange: onExpandChange, onCheckedChange: onCheckedChange, renderIcon: renderIcon, renderElement: renderElement, renderTitle: renderTitle, disabled: disabled, showIcon: showIcon }, child), child.id))) })), enableSeparatorLine && isFirstLevel && !isLastItem && (_jsx("div", { className: cn("bg-grey-150 w-full h-[2px] rounded", classes === null || classes === void 0 ? void 0 : classes.separatorLine) }))] })] }));
80
+ };
81
+ export default TreeItem;
@@ -0,0 +1,4 @@
1
+ import Tree from "./Tree";
2
+ import TreeItem from "./TreeItem";
3
+ export * from "./type";
4
+ export { Tree, TreeItem };
@@ -0,0 +1 @@
1
+ export {};
@@ -699,6 +699,9 @@ input[type=number] {
699
699
  .mr-4{
700
700
  margin-right: 1rem;
701
701
  }
702
+ .mr-\[2px\]{
703
+ margin-right: 2px;
704
+ }
702
705
  .mt-1{
703
706
  margin-top: 0.25rem;
704
707
  }
@@ -777,6 +780,10 @@ input[type=number] {
777
780
  width: 14px;
778
781
  height: 14px;
779
782
  }
783
+ .size-\[16pt\]{
784
+ width: 16pt;
785
+ height: 16pt;
786
+ }
780
787
  .size-\[30px\]{
781
788
  width: 30px;
782
789
  height: 30px;
@@ -789,6 +796,9 @@ input[type=number] {
789
796
  width: 100%;
790
797
  height: 100%;
791
798
  }
799
+ .h-1\/2{
800
+ height: 50%;
801
+ }
792
802
  .h-10{
793
803
  height: 2.5rem;
794
804
  }
@@ -819,6 +829,9 @@ input[type=number] {
819
829
  .h-\[24px\]{
820
830
  height: 24px;
821
831
  }
832
+ .h-\[2px\]{
833
+ height: 2px;
834
+ }
822
835
  .h-\[32px\]{
823
836
  height: 32px;
824
837
  }
@@ -859,6 +872,9 @@ input[type=number] {
859
872
  .max-h-screen{
860
873
  max-height: 100vh;
861
874
  }
875
+ .min-h-10{
876
+ min-height: 2.5rem;
877
+ }
862
878
  .w-1\/2{
863
879
  width: 50%;
864
880
  }
@@ -1132,6 +1148,9 @@ input[type=number] {
1132
1148
  text-overflow: ellipsis;
1133
1149
  white-space: nowrap;
1134
1150
  }
1151
+ .text-ellipsis{
1152
+ text-overflow: ellipsis;
1153
+ }
1135
1154
  .rounded{
1136
1155
  border-radius: 0.25rem;
1137
1156
  }
@@ -2701,6 +2720,9 @@ input[type=number] {
2701
2720
  .fill-error{
2702
2721
  fill: color-mix(in srgb, var(--state-color-error-default) calc(100% * 1), transparent);
2703
2722
  }
2723
+ .fill-info{
2724
+ fill: color-mix(in srgb, var(--state-color-info-default) calc(100% * 1), transparent);
2725
+ }
2704
2726
  .fill-inherit{
2705
2727
  fill: inherit;
2706
2728
  }
@@ -2719,6 +2741,12 @@ input[type=number] {
2719
2741
  .fill-primary-default{
2720
2742
  fill: color-mix(in srgb, var(--state-color-primary-default) calc(100% * 1), transparent);
2721
2743
  }
2744
+ .fill-secondary{
2745
+ fill: color-mix(in srgb, var(--state-color-secondary-default) calc(100% * 1), transparent);
2746
+ }
2747
+ .fill-warning{
2748
+ fill: color-mix(in srgb, var(--state-color-warning-default) calc(100% * 1), transparent);
2749
+ }
2722
2750
  .stroke-input-default-stroke{
2723
2751
  stroke: color-mix(in srgb, var(--input-color-default-stroke) calc(100% * 1), transparent);
2724
2752
  }
@@ -4974,8 +5002,8 @@ input[type=number] {
4974
5002
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);
4975
5003
  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
4976
5004
  }
4977
- .group:disabled .group-disabled\:bg-\[--switch-thumb-disabled-color\]{
4978
- background-color: var(--switch-thumb-disabled-color);
5005
+ .group:disabled .group-disabled\:\!bg-\[--switch-thumb-disabled-color\]{
5006
+ background-color: var(--switch-thumb-disabled-color) !important;
4979
5007
  }
4980
5008
  .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:top-2{
4981
5009
  top: 0.5rem;
@@ -5237,8 +5265,8 @@ input[type=number] {
5237
5265
  .data-\[disabled\]\:\!bg-\[var\(--dropdown-menu-disabled-bg\)\][data-disabled]{
5238
5266
  background-color: var(--dropdown-menu-disabled-bg) !important;
5239
5267
  }
5240
- .data-\[disabled\]\:bg-\[var\(--switch-disabled-color\)\][data-disabled]{
5241
- background-color: var(--switch-disabled-color);
5268
+ .data-\[disabled\]\:\!bg-\[var\(--switch-disabled-color\)\][data-disabled]{
5269
+ background-color: var(--switch-disabled-color) !important;
5242
5270
  }
5243
5271
  .data-\[loading\=true\]\:bg-button-error-flat-active[data-loading=true]{
5244
5272
  --tw-bg-opacity: 1;