@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.
- package/dist/cjs/bundle.css +32 -4
- package/dist/cjs/bundle.js +3 -3
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/cjs/types/components/Switch/Switch.stories.d.ts +1 -6
- package/dist/cjs/types/components/Tree/Tree.d.ts +4 -0
- package/dist/cjs/types/components/Tree/Tree.stories.d.ts +12 -0
- package/dist/cjs/types/components/Tree/TreeItem.d.ts +4 -0
- package/dist/cjs/types/components/Tree/index.d.ts +4 -0
- package/dist/cjs/types/components/Tree/type.d.ts +76 -0
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/components/Switch/Switch.js +2 -2
- package/dist/components/Switch/Switch.stories.js +2 -7
- package/dist/components/Tree/Tree.js +104 -0
- package/dist/components/Tree/Tree.stories.js +162 -0
- package/dist/components/Tree/TreeItem.js +81 -0
- package/dist/components/Tree/index.js +4 -0
- package/dist/components/Tree/type.js +1 -0
- package/dist/esm/bundle.css +32 -4
- package/dist/esm/bundle.js +1 -1
- package/dist/esm/bundle.js.map +1 -1
- package/dist/esm/types/components/Switch/Switch.stories.d.ts +1 -6
- package/dist/esm/types/components/Tree/Tree.d.ts +4 -0
- package/dist/esm/types/components/Tree/Tree.stories.d.ts +12 -0
- package/dist/esm/types/components/Tree/TreeItem.d.ts +4 -0
- package/dist/esm/types/components/Tree/index.d.ts +4 -0
- package/dist/esm/types/components/Tree/type.d.ts +76 -0
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/index.d.ts +82 -2
- package/dist/index.js +1 -0
- package/dist/src/theme/global.css +75 -14
- package/dist/theme/themes/SKL/color.css +10 -10
- package/dist/theme/themes/xspector/baseline.css +1 -0
- package/dist/theme/themes/xspector/components/switch.css +30 -0
- package/package.json +1 -1
- package/src/components/Switch/Switch.stories.tsx +2 -7
- package/src/components/Switch/Switch.tsx +2 -2
- package/src/components/Tree/Tree.stories.tsx +288 -0
- package/src/components/Tree/Tree.tsx +192 -0
- package/src/components/Tree/TreeItem.tsx +231 -0
- package/src/components/Tree/index.ts +5 -0
- package/src/components/Tree/type.ts +90 -0
- package/src/index.ts +1 -0
- package/src/theme/themes/SKL/color.css +10 -10
- package/src/theme/themes/xspector/baseline.css +1 -0
- 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
|
-
|
|
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,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,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]
|
|
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
|
|
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
|
-
|
|
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 @@
|
|
|
1
|
+
export {};
|
package/dist/esm/bundle.css
CHANGED
|
@@ -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
|
|
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\]
|
|
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;
|