@rovula/ui 0.0.54 → 0.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,3 +14,4 @@ export declare const ExpandLoadData: StoryObj<typeof Tree>;
14
14
  export declare const MaximumLevel: StoryObj<typeof Tree>;
15
15
  export declare const Leaf: StoryObj<typeof Tree>;
16
16
  export declare const HideCheckboxMode: StoryObj<typeof Tree>;
17
+ export declare const RadioMode: StoryObj<typeof Tree>;
@@ -29,6 +29,7 @@ export interface TreeItemProps extends TreeData {
29
29
  maxLevel?: number;
30
30
  checkIsExpanded: (id: string) => boolean;
31
31
  checkIsChecked: (id: string) => boolean;
32
+ checkAutoDisabled: (id: string) => boolean;
32
33
  checkIsLoading?: (id: string) => void;
33
34
  onExpandChange?: (id: string, expanded: boolean) => void;
34
35
  onCheckedChange?: (id: string, checked: boolean) => void;
@@ -90,4 +91,6 @@ export interface TreeProps extends Pick<TreeItemProps, "renderIcon" | "renderRig
90
91
  hierarchicalCheck?: boolean;
91
92
  checkable?: boolean;
92
93
  maxLevel?: number;
94
+ mode: "checkbox" | "radio";
95
+ autoDisabled?: boolean;
93
96
  }
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useState } from "react";
3
3
  import TreeItem from "./TreeItem";
4
4
  import { cn } from "@/utils/cn";
5
- const Tree = ({ classes, data, defaultExpandedId, defaultCheckedId, checkedId, loadingId, lineSize, horizontalLineWidth, expandButtonSize, spacing, renderIcon, renderRightSection, renderElement, renderTitle, onExpandChange, onCheckedChange, onClickItem, onCheckedItem, defaultExpandAll = false, defaultCheckAll = false, hierarchicalCheck = false, showIcon = true, disabled, enableSeparatorLine = true, checkable = true, maxLevel, }) => {
5
+ const Tree = ({ classes, data, defaultExpandedId, defaultCheckedId, checkedId, loadingId, lineSize, horizontalLineWidth, expandButtonSize, spacing, renderIcon, renderRightSection, renderElement, renderTitle, onExpandChange, onCheckedChange, onClickItem, onCheckedItem, defaultExpandAll = false, defaultCheckAll = false, hierarchicalCheck = false, showIcon = true, disabled, enableSeparatorLine = true, checkable = true, maxLevel, mode, autoDisabled = false, }) => {
6
6
  const [checkedState, setCheckedState] = useState({});
7
7
  const [expandedState, setExpandedState] = useState({});
8
8
  const traverseTree = (nodes, callback) => {
@@ -47,11 +47,23 @@ const Tree = ({ classes, data, defaultExpandedId, defaultCheckedId, checkedId, l
47
47
  setCheckedState(initialCheckedState);
48
48
  }
49
49
  }, [data, defaultCheckedId, defaultCheckAll]);
50
+ useEffect(() => {
51
+ if (checkedId !== undefined) {
52
+ setCheckedState(checkedId.reduce((prev, cur) => (Object.assign(Object.assign({}, prev), { [cur]: true })), {}));
53
+ }
54
+ }, [checkedId]);
50
55
  const handleExpandChange = useCallback((id, expanded) => {
51
56
  onExpandChange === null || onExpandChange === void 0 ? void 0 : onExpandChange(id, expanded);
52
57
  setExpandedState((prev) => (Object.assign(Object.assign({}, prev), { [id]: expanded })));
53
58
  }, [onExpandChange]);
54
59
  const handleCheckedChange = useCallback((id, checked) => {
60
+ if (mode === "radio") {
61
+ let newState = { [id]: checked };
62
+ onCheckedItem === null || onCheckedItem === void 0 ? void 0 : onCheckedItem(id, checked);
63
+ setCheckedState(newState);
64
+ onCheckedChange === null || onCheckedChange === void 0 ? void 0 : onCheckedChange(newState);
65
+ return;
66
+ }
55
67
  onCheckedItem === null || onCheckedItem === void 0 ? void 0 : onCheckedItem(id, checked);
56
68
  let newState = Object.assign(Object.assign({}, checkedState), { [id]: checked });
57
69
  if (hierarchicalCheck) {
@@ -89,7 +101,15 @@ const Tree = ({ classes, data, defaultExpandedId, defaultCheckedId, checkedId, l
89
101
  if (onCheckedChange) {
90
102
  onCheckedChange === null || onCheckedChange === void 0 ? void 0 : onCheckedChange(newState);
91
103
  }
92
- }, [checkedState, data, onCheckedChange, hierarchicalCheck, onCheckedItem]);
104
+ }, [
105
+ checkedState,
106
+ data,
107
+ onCheckedChange,
108
+ hierarchicalCheck,
109
+ onCheckedItem,
110
+ mode,
111
+ autoDisabled,
112
+ ]);
93
113
  const checkIsExpanded = useCallback((id) => !!expandedState[id], [expandedState]);
94
114
  const checkIsChecked = useCallback((id) => {
95
115
  if (checkedId) {
@@ -102,6 +122,13 @@ const Tree = ({ classes, data, defaultExpandedId, defaultCheckedId, checkedId, l
102
122
  return loadingId.includes(id);
103
123
  }
104
124
  }, [loadingId]);
105
- return (_jsx("div", { className: cn("w-full", classes === null || classes === void 0 ? void 0 : classes.container), 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, lineSize: lineSize, horizontalLineWidth: horizontalLineWidth, expandButtonSize: expandButtonSize, spacing: spacing, notifyClickItem: onClickItem, maxLevel: maxLevel, currentLevel: 1, checkable: checkable }, item), item.id))) }));
125
+ const checkAutoDisabled = useCallback((id) => {
126
+ var _a;
127
+ if (autoDisabled && Object.values(checkedState).filter(Boolean).length) {
128
+ return (_a = (!(checkedState === null || checkedState === void 0 ? void 0 : checkedState[id]) || disabled)) !== null && _a !== void 0 ? _a : false;
129
+ }
130
+ return false;
131
+ }, [checkedState, disabled, autoDisabled]);
132
+ return (_jsx("div", { className: cn("w-full", classes === null || classes === void 0 ? void 0 : classes.container), 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, checkAutoDisabled: checkAutoDisabled, checkIsLoading: checkIsLoading, renderIcon: renderIcon, renderElement: renderElement, renderTitle: renderTitle, renderRightSection: renderRightSection, enableSeparatorLine: enableSeparatorLine, disabled: checkAutoDisabled(item.id), showIcon: showIcon, lineSize: lineSize, horizontalLineWidth: horizontalLineWidth, expandButtonSize: expandButtonSize, spacing: spacing, notifyClickItem: onClickItem, maxLevel: maxLevel, currentLevel: 1, checkable: checkable }, item), item.id))) }));
106
133
  };
107
134
  export default Tree;
@@ -1,7 +1,7 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
3
  import Tree from "./Tree";
4
- import { ActionButton, Icon } from "@/index";
4
+ import { ActionButton, Button, Icon } from "@/index";
5
5
  import { exampleData, exampleData2, exampleLeafData, sections, } from "./example-data";
6
6
  const commonProps = {
7
7
  defaultExpandedId: ["1", "1.1"],
@@ -197,3 +197,16 @@ export const HideCheckboxMode = {
197
197
  return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Tree, Object.assign({}, args)) }));
198
198
  },
199
199
  };
200
+ export const RadioMode = {
201
+ args: {
202
+ data: exampleData,
203
+ mode: "radio",
204
+ autoDisabled: true,
205
+ },
206
+ render: (args) => {
207
+ const [checkedId, onCheckedId] = useState(["1"]);
208
+ return (_jsxs("div", { className: "flex flex-col gap-4 w-full", children: [_jsx("div", { children: _jsx(Button, { variant: "outline", onClick: () => onCheckedId([]), children: "Clear" }) }), _jsx(Tree, Object.assign({}, args, { checkedId: checkedId, onCheckedChange: (state) => {
209
+ onCheckedId(Object.keys(state).filter((key) => state === null || state === void 0 ? void 0 : state[key]));
210
+ } }))] }));
211
+ },
212
+ };
@@ -3,7 +3,7 @@ import { ActionButton, Checkbox, Loading } from "@/index";
3
3
  import { cn } from "@/utils/cn";
4
4
  import { useCallback, useEffect, useMemo } from "react";
5
5
  import Icon from "../Icon/Icon";
6
- const TreeItem = ({ id, title, classes, children, isFirstLevel = false, isLeaf = false, disabled, icon, showIcon, showExpandButton, enableSeparatorLine = true, isLastItem, checkable, checkIsExpanded, checkIsChecked, checkIsLoading, onExpandChange, onCheckedChange, onClickItem, renderIcon, renderElement, renderTitle, renderRightSection, lineSize = 2, horizontalLineWidth = 4, expandButtonSize = 30, spacing = 2, currentLevel = 1, maxLevel = 10, notifyClickItem, }) => {
6
+ const TreeItem = ({ id, title, classes, children, isFirstLevel = false, isLeaf = false, disabled, icon, showIcon, showExpandButton, enableSeparatorLine = true, isLastItem, checkable, checkIsExpanded, checkIsChecked, checkAutoDisabled, checkIsLoading, onExpandChange, onCheckedChange, onClickItem, renderIcon, renderElement, renderTitle, renderRightSection, lineSize = 2, horizontalLineWidth = 4, expandButtonSize = 30, spacing = 2, currentLevel = 1, maxLevel = 10, notifyClickItem, }) => {
7
7
  const isLoading = useMemo(() => checkIsLoading === null || checkIsLoading === void 0 ? void 0 : checkIsLoading(id), [checkIsLoading, id]);
8
8
  const isChecked = useMemo(() => checkIsChecked(id), [checkIsChecked, id]);
9
9
  const isExpanded = useMemo(() => checkIsExpanded(id), [checkIsExpanded, id]);
@@ -57,7 +57,7 @@ const TreeItem = ({ id, title, classes, children, isFirstLevel = false, isLeaf =
57
57
  onClickItem === null || onClickItem === void 0 ? void 0 : onClickItem(id);
58
58
  notifyClickItem === null || notifyClickItem === void 0 ? void 0 : notifyClickItem(id);
59
59
  }, [onClickItem, notifyClickItem, id]);
60
- const defaultIcon = (_jsx(Icon, { name: isExpanded ? "folder-open" : "folder", className: "fill-warning" }));
60
+ const defaultIcon = (_jsx(Icon, { name: isExpanded ? "folder-open" : "folder", className: "fill-warning size-[18px]" }));
61
61
  const customIcon = icon !== null && icon !== void 0 ? icon : renderIcon === null || renderIcon === void 0 ? void 0 : renderIcon({
62
62
  id,
63
63
  expanded: isExpanded,
@@ -83,8 +83,8 @@ const TreeItem = ({ id, title, classes, children, isFirstLevel = false, isLeaf =
83
83
  : content;
84
84
  return elementWrapper(_jsx("div", { className: cn("flex flex-row w-full", classes === null || classes === void 0 ? void 0 : classes.elementWrapper), children: _jsxs("div", { className: cn("flex flex-col w-full", classes === null || classes === void 0 ? void 0 : classes.itemWrapper), children: [_jsxs("div", { className: cn("flex flex-row flex-1", classes === null || classes === void 0 ? void 0 : classes.rowWrapperClasses), children: [_jsxs("div", { className: cn("flex flex-col h-full", classes === null || classes === void 0 ? void 0 : classes.columnWrapperClasses), children: [!isFirstLevel && (_jsx("div", { className: cn("flex w-[2px] h-1/2 bg-grey-150", classes === null || classes === void 0 ? void 0 : classes.branch), style: styles.branch })), !isFirstLevel &&
85
85
  !isLastItem &&
86
- ((isExpanded && (hasChildren || isLoading)) || !isExpanded) && (_jsx("div", { className: cn("flex w-[2px] h-1/2 bg-grey-150", classes === null || classes === void 0 ? void 0 : classes.branch), style: styles.branch }))] }), _jsxs("div", { className: cn("flex flex-1 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" })) }) })), shouldShowCheckbox ? (_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) })) : (_jsx("div", { className: isFirstLevel && checkable
87
- ? cn("size-[16pt]", classes === null || classes === void 0 ? void 0 : classes.checkbox)
88
- : "" })), _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 && currentLevel < (maxLevel || Infinity) && (_jsxs("div", { className: cn("flex flex-row overflow-hidden max-h-screen", classes === null || classes === void 0 ? void 0 : classes.expandedChildrenWrapper), children: [!isFirstLevel && !isLastItem && (_jsx("div", { className: cn("flex w-[2px] h-full bg-grey-150", classes === null || classes === void 0 ? void 0 : classes.branch), style: styles.branch })), _jsx("div", { className: cn("flex flex-col overflow-hidden max-h-screen", classes === null || classes === void 0 ? void 0 : classes.expandedChildrenWrapperInner), 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, lineSize: lineSize, horizontalLineWidth: horizontalLineWidth, expandButtonSize: expandButtonSize, spacing: spacing, notifyClickItem: notifyClickItem, maxLevel: maxLevel, currentLevel: currentLevel + 1, checkable: checkable }, 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) }))] }) }));
86
+ ((isExpanded && (hasChildren || isLoading)) || !isExpanded) && (_jsx("div", { className: cn("flex w-[2px] h-1/2 bg-grey-150", classes === null || classes === void 0 ? void 0 : classes.branch), style: styles.branch }))] }), _jsxs("div", { className: cn("flex flex-1 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" })) }) })), shouldShowCheckbox ? (_jsx(Checkbox, { id: id, className: cn("size-[16px]", 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) })) : (_jsx("div", { className: isFirstLevel && checkable
87
+ ? cn("size-[16px]", classes === null || classes === void 0 ? void 0 : classes.checkbox)
88
+ : "" })), _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 && currentLevel < (maxLevel || Infinity) && (_jsxs("div", { className: cn("flex flex-row overflow-hidden max-h-screen", classes === null || classes === void 0 ? void 0 : classes.expandedChildrenWrapper), children: [!isFirstLevel && !isLastItem && (_jsx("div", { className: cn("flex w-[2px] h-full bg-grey-150", classes === null || classes === void 0 ? void 0 : classes.branch), style: styles.branch })), _jsx("div", { className: cn("flex flex-col overflow-hidden max-h-screen", classes === null || classes === void 0 ? void 0 : classes.expandedChildrenWrapperInner), 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, checkAutoDisabled: checkAutoDisabled, checkIsLoading: checkIsLoading, onExpandChange: onExpandChange, onCheckedChange: onCheckedChange, renderIcon: renderIcon, renderElement: renderElement, renderTitle: renderTitle, disabled: checkAutoDisabled(child.id), showIcon: showIcon, lineSize: lineSize, horizontalLineWidth: horizontalLineWidth, expandButtonSize: expandButtonSize, spacing: spacing, notifyClickItem: notifyClickItem, maxLevel: maxLevel, currentLevel: currentLevel + 1, checkable: checkable }, 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) }))] }) }));
89
89
  };
90
90
  export default TreeItem;
@@ -783,9 +783,13 @@ input[type=number] {
783
783
  width: 14px;
784
784
  height: 14px;
785
785
  }
786
- .size-\[16pt\]{
787
- width: 16pt;
788
- height: 16pt;
786
+ .size-\[16px\]{
787
+ width: 16px;
788
+ height: 16px;
789
+ }
790
+ .size-\[18px\]{
791
+ width: 18px;
792
+ height: 18px;
789
793
  }
790
794
  .size-\[30px\]{
791
795
  width: 30px;