@rovula/ui 0.0.46 → 0.0.48
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 +49 -28
- 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/Table/Table.d.ts +1 -0
- package/dist/cjs/types/components/Table/Table.stories.d.ts +2 -0
- package/dist/cjs/types/components/Tree/Tree.d.ts +45 -0
- package/dist/cjs/types/components/Tree/Tree.stories.d.ts +5 -0
- package/dist/components/Switch/Switch.js +15 -1
- package/dist/components/Switch/Switch.stories.js +2 -7
- package/dist/components/Table/Table.js +2 -2
- package/dist/components/Tree/Tree.js +138 -0
- package/dist/components/Tree/Tree.stories.js +53 -0
- package/dist/esm/bundle.css +49 -28
- package/dist/esm/bundle.js +2 -2
- 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/Table/Table.d.ts +1 -0
- package/dist/esm/types/components/Table/Table.stories.d.ts +2 -0
- package/dist/esm/types/components/Tree/Tree.d.ts +45 -0
- package/dist/esm/types/components/Tree/Tree.stories.d.ts +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/src/theme/global.css +1264 -37
- package/dist/theme/global.css +1 -0
- package/dist/theme/themes/SKL/baseline.css +12 -0
- package/dist/theme/themes/SKL/color.css +78 -0
- package/dist/theme/themes/SKL/components/action-button.css +127 -0
- package/dist/theme/themes/SKL/components/button.css +512 -0
- package/dist/theme/themes/SKL/components/dropdown-menu.css +27 -0
- package/dist/theme/themes/SKL/components/loading.css +11 -0
- package/dist/theme/themes/SKL/components/navbar.css +8 -0
- package/dist/theme/themes/SKL/components/progress-bar.css +8 -0
- package/dist/theme/themes/SKL/components/switch.css +30 -0
- package/dist/theme/themes/SKL/palette.css +145 -0
- package/dist/theme/themes/SKL/state.css +86 -0
- package/dist/theme/themes/SKL/transparent.css +68 -0
- package/dist/theme/themes/SKL/typography.css +199 -0
- package/dist/theme/themes/SKL/variables.css +28 -0
- package/dist/theme/themes/xspector/baseline.css +1 -0
- package/dist/theme/themes/xspector/components/switch.css +30 -0
- package/dist/theme/tokens/baseline.css +2 -1
- package/dist/theme/tokens/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 +37 -9
- package/src/components/Table/Table.tsx +7 -2
- package/src/components/Tree/Tree.stories.tsx +66 -0
- package/src/components/Tree/Tree.tsx +331 -0
- package/src/theme/global.css +1 -0
- package/src/theme/themes/SKL/baseline.css +12 -0
- package/src/theme/themes/SKL/color.css +78 -0
- package/src/theme/themes/SKL/components/action-button.css +127 -0
- package/src/theme/themes/SKL/components/button.css +512 -0
- package/src/theme/themes/SKL/components/dropdown-menu.css +27 -0
- package/src/theme/themes/SKL/components/loading.css +11 -0
- package/src/theme/themes/SKL/components/navbar.css +8 -0
- package/src/theme/themes/SKL/components/progress-bar.css +8 -0
- package/src/theme/themes/SKL/components/switch.css +30 -0
- package/src/theme/themes/SKL/palette.css +145 -0
- package/src/theme/themes/SKL/state.css +86 -0
- package/src/theme/themes/SKL/transparent.css +68 -0
- package/src/theme/themes/SKL/typography.css +199 -0
- package/src/theme/themes/SKL/variables.css +28 -0
- package/src/theme/themes/xspector/baseline.css +1 -0
- package/src/theme/themes/xspector/components/switch.css +30 -0
- package/src/theme/tokens/baseline.css +2 -1
- package/src/theme/tokens/components/switch.css +30 -0
|
@@ -2,19 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
|
5
|
-
|
|
6
5
|
import { cn } from "@/utils/cn";
|
|
7
6
|
|
|
7
|
+
const switchBaseClasses =
|
|
8
|
+
"group inline-flex h-3 w-[32px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors";
|
|
9
|
+
|
|
10
|
+
const switchStateClasses = {
|
|
11
|
+
unchecked:
|
|
12
|
+
"data-[state=unchecked]:bg-[var(--switch-default-color)] hover:data-[state=unchecked]:bg-[var(--switch-hover-color)]",
|
|
13
|
+
checked:
|
|
14
|
+
"data-[state=checked]:bg-[var(--switch-active-color)] hover:data-[state=checked]:bg-[var(--switch-active-hover-color)]",
|
|
15
|
+
disabled:
|
|
16
|
+
"data-[disabled]:cursor-not-allowed data-[disabled]:!bg-[var(--switch-disabled-color)] data-[disabled]:pointer-events-none",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const thumbBaseClasses =
|
|
20
|
+
"block size-4 rounded-full shadow-lg transition-transform";
|
|
21
|
+
const thumbStateClasses = {
|
|
22
|
+
unchecked:
|
|
23
|
+
"data-[state=unchecked]:bg-[var(--switch-thumb-default-color)] data-[state=unchecked]:-translate-x-[2px]",
|
|
24
|
+
checked:
|
|
25
|
+
"data-[state=checked]:bg-[var(--switch-thumb-active-color)] data-[state=checked]:translate-x-4",
|
|
26
|
+
hover:
|
|
27
|
+
"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
|
+
hoverColor:
|
|
29
|
+
"group-hover:data-[state=checked]:bg-[var(--switch-thumb-active-hover-color)] group-hover:data-[state=unchecked]:bg-[var(--switch-thumb-hover-color)]",
|
|
30
|
+
disabled: "group-disabled:!bg-[--switch-thumb-disabled-color]",
|
|
31
|
+
};
|
|
32
|
+
|
|
8
33
|
const Switch = React.forwardRef<
|
|
9
34
|
React.ElementRef<typeof SwitchPrimitives.Root>,
|
|
10
35
|
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
|
11
36
|
>(({ className, ...props }, ref) => (
|
|
12
37
|
<SwitchPrimitives.Root
|
|
13
38
|
className={cn(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
39
|
+
switchBaseClasses,
|
|
40
|
+
switchStateClasses.unchecked,
|
|
41
|
+
switchStateClasses.checked,
|
|
42
|
+
switchStateClasses.disabled,
|
|
18
43
|
className
|
|
19
44
|
)}
|
|
20
45
|
{...props}
|
|
@@ -22,14 +47,17 @@ const Switch = React.forwardRef<
|
|
|
22
47
|
>
|
|
23
48
|
<SwitchPrimitives.Thumb
|
|
24
49
|
className={cn(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
50
|
+
thumbBaseClasses,
|
|
51
|
+
thumbStateClasses.unchecked,
|
|
52
|
+
thumbStateClasses.checked,
|
|
53
|
+
thumbStateClasses.hover,
|
|
54
|
+
thumbStateClasses.hoverColor,
|
|
55
|
+
thumbStateClasses.disabled
|
|
29
56
|
)}
|
|
30
57
|
/>
|
|
31
58
|
</SwitchPrimitives.Root>
|
|
32
59
|
));
|
|
60
|
+
|
|
33
61
|
Switch.displayName = SwitchPrimitives.Root.displayName;
|
|
34
62
|
|
|
35
63
|
export { Switch };
|
|
@@ -5,10 +5,14 @@ import { cn } from "@/utils/cn";
|
|
|
5
5
|
const Table = React.forwardRef<
|
|
6
6
|
HTMLTableElement,
|
|
7
7
|
{
|
|
8
|
+
rootClassName?: string;
|
|
8
9
|
rootRef?: React.LegacyRef<HTMLDivElement>;
|
|
9
10
|
} & React.HTMLAttributes<HTMLTableElement>
|
|
10
|
-
>(({ className, rootRef, ...props }, ref) => (
|
|
11
|
-
<div
|
|
11
|
+
>(({ rootClassName, className, rootRef, ...props }, ref) => (
|
|
12
|
+
<div
|
|
13
|
+
className={cn("relative h-full w-full overflow-auto", rootClassName)}
|
|
14
|
+
ref={rootRef}
|
|
15
|
+
>
|
|
12
16
|
<table
|
|
13
17
|
ref={ref}
|
|
14
18
|
className={cn("w-full caption-bottom text-sm border-collapse", className)}
|
|
@@ -16,6 +20,7 @@ const Table = React.forwardRef<
|
|
|
16
20
|
/>
|
|
17
21
|
</div>
|
|
18
22
|
));
|
|
23
|
+
|
|
19
24
|
Table.displayName = "Table";
|
|
20
25
|
|
|
21
26
|
const TableHeader = React.forwardRef<
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Tree } from "./Tree";
|
|
4
|
+
|
|
5
|
+
// Example data for testing the Tree component (as plain objects)
|
|
6
|
+
const exampleData = [
|
|
7
|
+
{
|
|
8
|
+
id: "1",
|
|
9
|
+
title: "Parent Folder 1",
|
|
10
|
+
children: [
|
|
11
|
+
{
|
|
12
|
+
id: "1.1",
|
|
13
|
+
title: "Child Folder 1.1",
|
|
14
|
+
children: [
|
|
15
|
+
{ id: "1.1.1", title: "Sub Folder 1.1.1" },
|
|
16
|
+
{ id: "1.1.2", title: "Sub Folder 1.1.2" },
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
{ id: "1.2", title: "Child Folder 1.2" },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "2",
|
|
24
|
+
title: "Parent Folder 2",
|
|
25
|
+
children: [{ id: "2.1", title: "Child Folder 2.1" }],
|
|
26
|
+
},
|
|
27
|
+
{ id: "3", title: "Parent Folder 3" },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// Storybook metadata
|
|
31
|
+
const meta: Meta<typeof Tree> = {
|
|
32
|
+
title: "Components/Tree",
|
|
33
|
+
component: Tree,
|
|
34
|
+
tags: ["autodocs"],
|
|
35
|
+
parameters: {
|
|
36
|
+
layout: "fullscreen",
|
|
37
|
+
},
|
|
38
|
+
decorators: [
|
|
39
|
+
(Story) => (
|
|
40
|
+
<div className="p-5 flex w-full bg-base-bg">
|
|
41
|
+
<Story />
|
|
42
|
+
</div>
|
|
43
|
+
),
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default meta;
|
|
48
|
+
|
|
49
|
+
// Default story
|
|
50
|
+
export const Default: StoryObj<typeof Tree> = {
|
|
51
|
+
args: {
|
|
52
|
+
data: exampleData,
|
|
53
|
+
defaultExpandedId: ["1", "1.1"],
|
|
54
|
+
defaultCheckedId: ["1.1"],
|
|
55
|
+
defaultExpandAll: true,
|
|
56
|
+
defaultCheckAll: true,
|
|
57
|
+
hierarchicalCheck: true,
|
|
58
|
+
},
|
|
59
|
+
render: (args) => {
|
|
60
|
+
return (
|
|
61
|
+
<div className="flex flex-row gap-4 w-full">
|
|
62
|
+
<Tree {...args} />
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
},
|
|
66
|
+
};
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { ActionButton, Checkbox, Icon, Loading, cn } from "@/index";
|
|
2
|
+
import React, {
|
|
3
|
+
FC,
|
|
4
|
+
ReactNode,
|
|
5
|
+
useCallback,
|
|
6
|
+
useMemo,
|
|
7
|
+
useState,
|
|
8
|
+
useEffect,
|
|
9
|
+
} from "react";
|
|
10
|
+
|
|
11
|
+
export type TreeData = {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
icon?: ReactNode;
|
|
15
|
+
children?: TreeData[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export interface TreeItemProps extends TreeData {
|
|
19
|
+
isFirstLevel?: boolean;
|
|
20
|
+
isLastItem: boolean;
|
|
21
|
+
checkIsExpanded: (id: string) => boolean;
|
|
22
|
+
checkIsChecked: (id: string) => boolean;
|
|
23
|
+
onExpandChange?: (id: string, expanded: boolean) => void;
|
|
24
|
+
onCheckedChange?: (id: string, checked: boolean) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const TreeItem: FC<TreeItemProps> = ({
|
|
28
|
+
id,
|
|
29
|
+
title,
|
|
30
|
+
children,
|
|
31
|
+
isFirstLevel = false,
|
|
32
|
+
isLastItem,
|
|
33
|
+
checkIsExpanded,
|
|
34
|
+
checkIsChecked,
|
|
35
|
+
onExpandChange,
|
|
36
|
+
onCheckedChange,
|
|
37
|
+
}) => {
|
|
38
|
+
const isChecked = useMemo(() => checkIsChecked(id), [checkIsChecked, id]);
|
|
39
|
+
const isExpanded = useMemo(() => checkIsExpanded(id), [checkIsExpanded, id]);
|
|
40
|
+
const hasChildren = useMemo(() => !!children?.length, [children]);
|
|
41
|
+
|
|
42
|
+
const handleExpandToggle = useCallback(() => {
|
|
43
|
+
onExpandChange?.(id, !isExpanded);
|
|
44
|
+
}, [id, isExpanded, onExpandChange]);
|
|
45
|
+
|
|
46
|
+
// TODO move to props
|
|
47
|
+
const lineSize = 2;
|
|
48
|
+
const horizontalLineWidth = 4;
|
|
49
|
+
const expandButtonSize = 30;
|
|
50
|
+
const spacing = 2;
|
|
51
|
+
|
|
52
|
+
const styles = {
|
|
53
|
+
branch: {
|
|
54
|
+
height: isLastItem
|
|
55
|
+
? `calc(50% + ${lineSize}px)`
|
|
56
|
+
: `calc(100% + ${lineSize}px)`,
|
|
57
|
+
width: lineSize,
|
|
58
|
+
marginTop: -lineSize,
|
|
59
|
+
borderBottomLeftRadius: lineSize / 2,
|
|
60
|
+
},
|
|
61
|
+
horizontalLine: {
|
|
62
|
+
height: lineSize,
|
|
63
|
+
width:
|
|
64
|
+
lineSize +
|
|
65
|
+
horizontalLineWidth +
|
|
66
|
+
(hasChildren ? 0 : expandButtonSize + spacing),
|
|
67
|
+
marginLeft: -lineSize + 0.1,
|
|
68
|
+
borderBottomLeftRadius: lineSize / 2,
|
|
69
|
+
},
|
|
70
|
+
expandButton: {
|
|
71
|
+
width: expandButtonSize,
|
|
72
|
+
height: expandButtonSize,
|
|
73
|
+
},
|
|
74
|
+
childPadding: {
|
|
75
|
+
paddingLeft: isFirstLevel
|
|
76
|
+
? expandButtonSize / 2 - lineSize / 2
|
|
77
|
+
: expandButtonSize / 2 + horizontalLineWidth - lineSize / 2,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className="flex flex-row w-full">
|
|
83
|
+
<div
|
|
84
|
+
className={cn("bg-grey-150", { "h-1/2": isLastItem })}
|
|
85
|
+
style={styles.branch}
|
|
86
|
+
/>
|
|
87
|
+
<div className="flex flex-col w-full">
|
|
88
|
+
<div className="flex items-center py-2 min-h-10">
|
|
89
|
+
{!isFirstLevel && (
|
|
90
|
+
<div className="bg-grey-150" style={styles.horizontalLine} />
|
|
91
|
+
)}
|
|
92
|
+
|
|
93
|
+
{isFirstLevel && !hasChildren && (
|
|
94
|
+
<div className="flex mr-[2px]" style={styles.expandButton} />
|
|
95
|
+
)}
|
|
96
|
+
|
|
97
|
+
{hasChildren && (
|
|
98
|
+
<div className="flex mr-[2px]" style={styles.expandButton}>
|
|
99
|
+
<ActionButton
|
|
100
|
+
variant="icon"
|
|
101
|
+
size="sm"
|
|
102
|
+
onClick={handleExpandToggle}
|
|
103
|
+
>
|
|
104
|
+
<Icon name={isExpanded ? "chevron-down" : "chevron-right"} />
|
|
105
|
+
</ActionButton>
|
|
106
|
+
</div>
|
|
107
|
+
)}
|
|
108
|
+
<Checkbox
|
|
109
|
+
id={id}
|
|
110
|
+
className="size-[16pt]"
|
|
111
|
+
checked={isChecked}
|
|
112
|
+
onCheckedChange={(newChecked) =>
|
|
113
|
+
onCheckedChange?.(id, newChecked as boolean)
|
|
114
|
+
}
|
|
115
|
+
/>
|
|
116
|
+
<div className="ml-2 gap-1 flex items-center text-foreground">
|
|
117
|
+
<Icon
|
|
118
|
+
name={isExpanded ? "folder-open" : "folder"}
|
|
119
|
+
className="fill-warning"
|
|
120
|
+
/>
|
|
121
|
+
<label
|
|
122
|
+
htmlFor={id}
|
|
123
|
+
className="flex-1 cursor-pointer text-subtitle5 text-ellipsis"
|
|
124
|
+
>
|
|
125
|
+
{title}
|
|
126
|
+
</label>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
{isExpanded && hasChildren && (
|
|
130
|
+
<div className="flex flex-col" style={styles.childPadding}>
|
|
131
|
+
{children?.map((child, idx) => (
|
|
132
|
+
<TreeItem
|
|
133
|
+
key={child.id}
|
|
134
|
+
{...child}
|
|
135
|
+
isLastItem={idx === children.length - 1}
|
|
136
|
+
checkIsExpanded={checkIsExpanded}
|
|
137
|
+
checkIsChecked={checkIsChecked}
|
|
138
|
+
onExpandChange={onExpandChange}
|
|
139
|
+
onCheckedChange={onCheckedChange}
|
|
140
|
+
/>
|
|
141
|
+
))}
|
|
142
|
+
</div>
|
|
143
|
+
)}
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
export type TreeProps = {
|
|
149
|
+
data: TreeData[];
|
|
150
|
+
defaultExpandedId?: string[];
|
|
151
|
+
defaultCheckedId?: string[];
|
|
152
|
+
checkedId?: string[];
|
|
153
|
+
onCheckedChange?: (checkedId: string[]) => void;
|
|
154
|
+
defaultExpandAll?: boolean;
|
|
155
|
+
defaultCheckAll?: boolean;
|
|
156
|
+
hierarchicalCheck?: boolean;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const Tree: FC<TreeProps> = ({
|
|
160
|
+
data,
|
|
161
|
+
defaultExpandedId = [],
|
|
162
|
+
defaultCheckedId = [],
|
|
163
|
+
checkedId,
|
|
164
|
+
onCheckedChange,
|
|
165
|
+
defaultExpandAll = false,
|
|
166
|
+
defaultCheckAll = false,
|
|
167
|
+
hierarchicalCheck = false,
|
|
168
|
+
}) => {
|
|
169
|
+
const [checkedState, setCheckedState] = useState<Record<string, boolean>>({});
|
|
170
|
+
const [expandedState, setExpandedState] = useState<Record<string, boolean>>(
|
|
171
|
+
{}
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const traverseTree = (
|
|
175
|
+
nodes: TreeData[],
|
|
176
|
+
callback: (node: TreeData) => void
|
|
177
|
+
) => {
|
|
178
|
+
nodes.forEach((node) => {
|
|
179
|
+
callback(node);
|
|
180
|
+
if (node.children) {
|
|
181
|
+
traverseTree(node.children, callback);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
if (defaultExpandAll) {
|
|
188
|
+
const allExpanded: Record<string, boolean> = {};
|
|
189
|
+
traverseTree(data, (node) => {
|
|
190
|
+
allExpanded[node.id] = true;
|
|
191
|
+
});
|
|
192
|
+
setExpandedState(allExpanded);
|
|
193
|
+
} else {
|
|
194
|
+
const initialExpandedState = defaultExpandedId.reduce((acc, id) => {
|
|
195
|
+
acc[id] = true;
|
|
196
|
+
return acc;
|
|
197
|
+
}, {} as Record<string, boolean>);
|
|
198
|
+
setExpandedState(initialExpandedState);
|
|
199
|
+
}
|
|
200
|
+
}, [data, defaultExpandedId, defaultExpandAll]);
|
|
201
|
+
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
if (defaultCheckAll) {
|
|
204
|
+
const allChecked: Record<string, boolean> = {};
|
|
205
|
+
traverseTree(data, (node) => {
|
|
206
|
+
allChecked[node.id] = true;
|
|
207
|
+
});
|
|
208
|
+
setCheckedState(allChecked);
|
|
209
|
+
} else if (!checkedId) {
|
|
210
|
+
const initialCheckedState = defaultCheckedId.reduce((acc, id) => {
|
|
211
|
+
acc[id] = true;
|
|
212
|
+
return acc;
|
|
213
|
+
}, {} as Record<string, boolean>);
|
|
214
|
+
setCheckedState(initialCheckedState);
|
|
215
|
+
}
|
|
216
|
+
}, [data, defaultCheckedId, checkedId, defaultCheckAll]);
|
|
217
|
+
|
|
218
|
+
const handleExpandChange = useCallback((id: string, expanded: boolean) => {
|
|
219
|
+
setExpandedState((prev) => ({ ...prev, [id]: expanded }));
|
|
220
|
+
}, []);
|
|
221
|
+
|
|
222
|
+
const handleCheckedChange = useCallback(
|
|
223
|
+
(id: string, checked: boolean) => {
|
|
224
|
+
let newState = { ...checkedState, [id]: checked };
|
|
225
|
+
|
|
226
|
+
if (hierarchicalCheck) {
|
|
227
|
+
const updateCheckedState = (
|
|
228
|
+
nodeId: string,
|
|
229
|
+
isChecked: boolean,
|
|
230
|
+
state: Record<string, boolean>
|
|
231
|
+
) => {
|
|
232
|
+
state[nodeId] = isChecked;
|
|
233
|
+
|
|
234
|
+
// Update children recursively
|
|
235
|
+
const updateChildren = (parentId: string, isChecked: boolean) => {
|
|
236
|
+
traverseTree(data, (node) => {
|
|
237
|
+
if (node.id === parentId && node.children) {
|
|
238
|
+
node.children.forEach((child) => {
|
|
239
|
+
state[child.id] = isChecked;
|
|
240
|
+
updateChildren(child.id, isChecked);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// Update parents recursively
|
|
247
|
+
const updateParents = (
|
|
248
|
+
childId: string,
|
|
249
|
+
state: Record<string, boolean>
|
|
250
|
+
) => {
|
|
251
|
+
traverseTree(data, (node) => {
|
|
252
|
+
if (node.children?.some((child) => child.id === childId)) {
|
|
253
|
+
const allChildrenChecked = node.children.every(
|
|
254
|
+
(child) => state[child.id]
|
|
255
|
+
);
|
|
256
|
+
state[node.id] = allChildrenChecked;
|
|
257
|
+
updateParents(node.id, state);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
updateChildren(nodeId, isChecked);
|
|
263
|
+
updateParents(nodeId, state);
|
|
264
|
+
|
|
265
|
+
return state;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
newState = updateCheckedState(id, checked, newState);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
setCheckedState(newState);
|
|
272
|
+
|
|
273
|
+
if (onCheckedChange) {
|
|
274
|
+
const checkedIds = Object.keys(newState).filter((key) => newState[key]);
|
|
275
|
+
onCheckedChange(checkedIds);
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
[checkedState, data, onCheckedChange, hierarchicalCheck]
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const checkIsExpanded = useCallback(
|
|
282
|
+
(id: string) => !!expandedState[id],
|
|
283
|
+
[expandedState]
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
const checkIsChecked = useCallback(
|
|
287
|
+
(id: string) => {
|
|
288
|
+
if (checkedId) {
|
|
289
|
+
return checkedId.includes(id);
|
|
290
|
+
}
|
|
291
|
+
return !!checkedState[id];
|
|
292
|
+
},
|
|
293
|
+
[checkedId, checkedState]
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
return (
|
|
297
|
+
<div className="w-full">
|
|
298
|
+
{data.map((item, idx) => (
|
|
299
|
+
<TreeItem
|
|
300
|
+
key={item.id}
|
|
301
|
+
{...item}
|
|
302
|
+
isFirstLevel
|
|
303
|
+
isLastItem={idx === data.length - 1}
|
|
304
|
+
checkIsExpanded={checkIsExpanded}
|
|
305
|
+
checkIsChecked={checkIsChecked}
|
|
306
|
+
onExpandChange={handleExpandChange}
|
|
307
|
+
onCheckedChange={handleCheckedChange}
|
|
308
|
+
/>
|
|
309
|
+
))}
|
|
310
|
+
</div>
|
|
311
|
+
);
|
|
312
|
+
};
|
|
313
|
+
/**
|
|
314
|
+
* TODO
|
|
315
|
+
* -----
|
|
316
|
+
* - Custom style
|
|
317
|
+
* - Custom icon, elm and render props -> callback with selected*expanded
|
|
318
|
+
* - OnClick item
|
|
319
|
+
* - OnClick expandButton
|
|
320
|
+
* - disabled props
|
|
321
|
+
* - right section icon
|
|
322
|
+
* - props for show icon, line
|
|
323
|
+
* - props for render item
|
|
324
|
+
* - OnLoad mode
|
|
325
|
+
* -----
|
|
326
|
+
* - props onLoad item
|
|
327
|
+
* - props for hasChildren * for check to trigger on load
|
|
328
|
+
* - animate expand
|
|
329
|
+
* - check duplicate reversive on updateChildren
|
|
330
|
+
* - write storybook
|
|
331
|
+
*/
|
package/src/theme/global.css
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
@import url(palette.css);
|
|
2
|
+
@import url(state.css);
|
|
3
|
+
@import url(color.css);
|
|
4
|
+
@import url(transparent.css);
|
|
5
|
+
@import url(variables.css);
|
|
6
|
+
@import url(typography.css);
|
|
7
|
+
@import url(components/button.css);
|
|
8
|
+
@import url(components/action-button.css);
|
|
9
|
+
@import url(components/loading.css);
|
|
10
|
+
@import url(components/navbar.css);
|
|
11
|
+
@import url(components/dropdown-menu.css);
|
|
12
|
+
@import url(components/switch.css);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
|
|
2
|
+
:root[data-theme="SKL"] {
|
|
3
|
+
/* Base from design */
|
|
4
|
+
--input-color-default-text: #9e9e9e;
|
|
5
|
+
--input-color-default-stroke: #cfcfcf;
|
|
6
|
+
--input-color-filled-text: #4f4f4f;
|
|
7
|
+
--input-color-active-stroke: #9e9e9e;
|
|
8
|
+
--input-color-disable-text: #919eab;
|
|
9
|
+
--input-color-disable-stroke: #e7ebed;
|
|
10
|
+
--input-color-disable-bg: #f2f5f5;
|
|
11
|
+
--input-color-label-bg: #ffffff;/* #2d2e30; */
|
|
12
|
+
--input-color-error: #ed2f15;
|
|
13
|
+
|
|
14
|
+
/* Function button */
|
|
15
|
+
--function-default-solid: var(--state-color-primary-default);
|
|
16
|
+
--function-default-hover: var(--state-color-primary-hover);
|
|
17
|
+
--function-default-hover-bg: var(--state-color-primary-hover-bg);
|
|
18
|
+
--function-default-stroke: var(--state-color-primary-stroke);
|
|
19
|
+
--function-default-icon: #ffffff;
|
|
20
|
+
--function-default-outline-icon: var(--state-color-primary-default);
|
|
21
|
+
--function-active-solid: var(--state-color-secondary-default);
|
|
22
|
+
--function-active-hover: var(--state-color-secondary-hover);
|
|
23
|
+
--function-active-hover-bg: var(--state-color-secondary-hover-bg);
|
|
24
|
+
--function-active-stroke: var(--state-color-secondary-stroke);
|
|
25
|
+
--function-active-icon: #ffffff;
|
|
26
|
+
|
|
27
|
+
--text-black: #000000;
|
|
28
|
+
--text-dark: #18283a;
|
|
29
|
+
--text-medium: #4b5b6d;
|
|
30
|
+
--text-light: #8e98a4;
|
|
31
|
+
--text-grey-dark: #4f4f4f;
|
|
32
|
+
--text-grey-medium: #7e7e7e;
|
|
33
|
+
--text-grey-light: #9e9e9e;
|
|
34
|
+
--text-white: #ffffff;
|
|
35
|
+
|
|
36
|
+
--base-color-bg: #f5f5f5;
|
|
37
|
+
--base-color-bg2: #f5f5f5;
|
|
38
|
+
--base-color-bg3: #d8d8d8;
|
|
39
|
+
--base-color-workspace-stroke: #e2e2e2;
|
|
40
|
+
--base-color-guideline-stroke: #c5c5c5;
|
|
41
|
+
--base-color-popup: #ffffff;
|
|
42
|
+
--base-color-popup-hightlight: #343638;
|
|
43
|
+
--base-color-popup-curtain: rgba(0 0 0 / 0.6);
|
|
44
|
+
--common-white: #ffffff;
|
|
45
|
+
--common-black: #000000;
|
|
46
|
+
|
|
47
|
+
/* ------- Addon base ---------- */
|
|
48
|
+
--background: var(--base-color-bg);
|
|
49
|
+
--foreground: var(--common-black);
|
|
50
|
+
|
|
51
|
+
--primary: var(--primary-ramps-primary-100);
|
|
52
|
+
--primary: var(--secondary-ramps-secondary-100);
|
|
53
|
+
--tertiary: var(--tertiary-ramps-tertiary-100);
|
|
54
|
+
--info: var(--info-info-100);
|
|
55
|
+
--success: var(--success-success-100);
|
|
56
|
+
--warning: var(--warning-warning-100);
|
|
57
|
+
--error: var(--error-error-100);
|
|
58
|
+
--grey: var(--grey-grey-100);
|
|
59
|
+
--grey2: var(--grey2-grey2-100);
|
|
60
|
+
|
|
61
|
+
--primary-foreground: var(--state-color-primary-text-solid);
|
|
62
|
+
--secondary-foreground: var(--state-color-secondary-text-solid);
|
|
63
|
+
--tertiary-foreground: var(--state-color-tertiary-text-solid);
|
|
64
|
+
--info-foreground: var(--state-color-info-text-solid);
|
|
65
|
+
--success-foreground: var(--state-color-success-text-solid);
|
|
66
|
+
--warning-foreground: var(--state-color-warning-text-solid);
|
|
67
|
+
--error-foreground: var(--state-color-error-text-solid);
|
|
68
|
+
--grey-foreground: var(--common-black);
|
|
69
|
+
--grey2-foreground: var(--common-black);
|
|
70
|
+
|
|
71
|
+
--surface: var(--base-color-bg);
|
|
72
|
+
--surface-foreground: var(--common-black);
|
|
73
|
+
|
|
74
|
+
--primary-foreground: var(--common-white);
|
|
75
|
+
--secondary-foreground: var(--common-white);
|
|
76
|
+
|
|
77
|
+
--base-color-popup-foreground: var(--text-dark);
|
|
78
|
+
}
|