Web: Components: added story for TreeMenu

This commit is contained in:
Artem Tarasov 2021-03-14 01:00:46 +03:00
parent e673f48751
commit bda09de462
5 changed files with 156 additions and 62 deletions

View File

@ -57,6 +57,7 @@ module.exports = {
"../toggle-button/*.stories.@(js|mdx)", "../toggle-button/*.stories.@(js|mdx)",
"../toggle-content/*.stories.@(js|mdx)", "../toggle-content/*.stories.@(js|mdx)",
"../tooltip/*.stories.@(js|mdx)", "../tooltip/*.stories.@(js|mdx)",
"../tree-menu/*.stories.@(js|mdx)",
], ],
addons: [ addons: [
"@storybook/addon-links", "@storybook/addon-links",

View File

@ -275,33 +275,70 @@ const TreeMenu = React.forwardRef((props, ref) => {
}); });
TreeMenu.propTypes = { TreeMenu.propTypes = {
/** Whether support checked */
checkable: PropTypes.bool, checkable: PropTypes.bool,
/** Whether can drag treeNode */
draggable: PropTypes.bool, draggable: PropTypes.bool,
/** Whether disabled the tree */
disabled: PropTypes.bool, disabled: PropTypes.bool,
/** Whether multiple select */
multiple: PropTypes.bool, multiple: PropTypes.bool,
/** Whether show icon */
showIcon: PropTypes.bool, showIcon: PropTypes.bool,
/** Whether show line */
showLine: PropTypes.bool, showLine: PropTypes.bool,
/** Expand all treeNodes */
defaultExpandAll: PropTypes.bool, defaultExpandAll: PropTypes.bool,
/** Auto expand parent treeNodes when init */
defaultExpandParent: PropTypes.bool, defaultExpandParent: PropTypes.bool,
icon: PropTypes.func, icon: PropTypes.func,
/** it execs when fire the tree's dragend event */
onDragEnd: PropTypes.func,
/** it execs when fire the tree's dragenter event */
onDragEnter: PropTypes.func,
/** it execs when fire the tree's dragleave event */
onDragLeave: PropTypes.func,
/** it execs when fire the tree's dragover event */
onDragOver: PropTypes.func,
/** it execs when fire the tree's dragstart event */
onDragStart: PropTypes.func, onDragStart: PropTypes.func,
/** it execs when fire the tree's drop event */
onDrop: PropTypes.func, onDrop: PropTypes.func,
/** fire on treeNode expand or not */
onExpand: PropTypes.func,
/** Trigger when a node is loaded. If you set the loadedKeys, you must handle onLoad to avoid infinity loop */
onLoad: PropTypes.func,
/** call when mouse enter a treeNode */
onMouseEnter: PropTypes.func,
/** call when mouse leave a treeNode */
onMouseLeave: PropTypes.func,
/** select current treeNode and show customized contextmenu */
onRightClick: PropTypes.func,
/** click the treeNode to fire */
onSelect: PropTypes.func,
/** load data asynchronously and the return value should be a promise */
loadData: PropTypes.func, loadData: PropTypes.func,
/** child elements */
children: PropTypes.oneOfType([ children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node), PropTypes.arrayOf(PropTypes.node),
PropTypes.node, PropTypes.node,
]), ]),
/** Accepts class */
className: PropTypes.string, className: PropTypes.string,
/** Accepts id */
id: PropTypes.string, id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
disableSwitch: PropTypes.bool, disableSwitch: PropTypes.bool,
/** to select the selection style of the active node */
isFullFillSelection: PropTypes.bool, isFullFillSelection: PropTypes.bool,
/** for setting the spacing between nodes */
gapBetweenNodes: PropTypes.string, gapBetweenNodes: PropTypes.string,
/** to set spacing between nodes on tablets and phones (if necessary) */
gapBetweenNodesTablet: PropTypes.string, gapBetweenNodesTablet: PropTypes.string,
/** swipe the root node to the left if there are no nested elements */
isEmptyRootNode: PropTypes.bool, isEmptyRootNode: PropTypes.bool,
}; };

View File

@ -359,8 +359,11 @@ const TreeNodeMenu = styled(TreeNode)`
`; `;
TreeNodeMenu.propTypes = { TreeNodeMenu.propTypes = {
/** The number of new elements in the node */
newItems: PropTypes.number, newItems: PropTypes.number,
/** to display the badge */
showBadge: PropTypes.bool, showBadge: PropTypes.bool,
/** call when click on badge */
onBadgeClick: PropTypes.func, onBadgeClick: PropTypes.func,
}; };
TreeNodeMenu.defaultProps = { theme: Base }; TreeNodeMenu.defaultProps = { theme: Base };

View File

@ -1,21 +1,9 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { storiesOf } from "@storybook/react";
import {
withKnobs,
boolean,
text,
select,
number,
} from "@storybook/addon-knobs/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import TreeMenu from "."; import TreeMenu from ".";
import TreeNode from "./sub-components/tree-node"; import TreeNode from "./sub-components/tree-node";
import { Icons } from "../icons"; import ExpanderDownIcon from "../public/static/images/expander-down.react.svg";
import { action } from "@storybook/addon-actions"; import ExpanderRightIcon from "../public/static/images/expander-right.react.svg";
import ExpanderDownIcon from "../../../../../public/images/expander-down.react.svg"; import CatalogFolderIcon from "../public/static/images/catalog.folder.react.svg";
import ExpanderRightIcon from "../../../../../public/images/expander-right.react.svg";
const iconNames = Object.keys(Icons);
const treeData = [ const treeData = [
{ {
@ -24,13 +12,19 @@ const treeData = [
}, },
]; ];
const TreeMenuStory = (props) => { const Template = ({
// eslint-disable-next-line react/prop-types data,
const { data } = props; title,
newItems,
showBadge,
onSelect,
onLoad,
onCheck,
onRightClick,
...args
}) => {
const [gData, setGData] = useState(data); const [gData, setGData] = useState(data);
const [autoExpandParent, setAutoExpandParent] = useState(true); const [autoExpandParent, setAutoExpandParent] = useState(true);
const [expandedKeys, setExpandedKeys] = useState([ const [expandedKeys, setExpandedKeys] = useState([
"0-0-key", "0-0-key",
"0-0-0-key", "0-0-0-key",
@ -107,6 +101,7 @@ const TreeMenuStory = (props) => {
} }
setGData(treeData); setGData(treeData);
}; };
const onExpand = (expandedKeys) => { const onExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys); setExpandedKeys(expandedKeys);
setAutoExpandParent(false); setAutoExpandParent(false);
@ -117,15 +112,18 @@ const TreeMenuStory = (props) => {
if (item.children && item.children.length) { if (item.children && item.children.length) {
return ( return (
<TreeNode <TreeNode
title={text("title", "Title")} title={title}
key={item.key} key={item.key}
icon={React.createElement( icon={
Icons[select("icon", iconNames, "CatalogFolderIcon")], <CatalogFolderIcon
{ size: "scale", isfill: true, color: "dimgray" } size="scale"
)} //isfill=true,
color="dimgray"
/>
}
onBadgeClick={onBadgeClick} onBadgeClick={onBadgeClick}
newItems={number("newItems", 0)} newItems={newItems}
showBadge={boolean("showBadge", false)} showBadge={showBadge}
> >
{getTreeNodes(item.children)} {getTreeNodes(item.children)}
</TreeNode> </TreeNode>
@ -134,11 +132,12 @@ const TreeMenuStory = (props) => {
return ( return (
<TreeNode <TreeNode
key={item.key} key={item.key}
title={text("title", "Title")} title={title}
icon={React.createElement( icon={React.createElement(CatalogFolderIcon, {
Icons[select("icon", iconNames, "CatalogFolderIcon")], size: "scale",
{ size: "scale", isfill: true, color: "dimgray" } //isfill: true,
)} color: "dimgray",
})}
></TreeNode> ></TreeNode>
); );
}); });
@ -149,33 +148,16 @@ const TreeMenuStory = (props) => {
return null; return null;
} }
if (obj.expanded) { if (obj.expanded) {
return <ExpanderDownIcon size="scale" isfill={true} color="dimgray" />; return <ExpanderDownIcon width="8px" color="dimgray" />;
} else { } else {
return ( return <ExpanderRightIcon width="8px" color="dimgray" />;
<ExpanderRightIcon
size="scale"
isfill={true}
color="dimgray"
></ExpanderRightIcon>
);
} }
}; };
return ( return (
<div style={{ width: "250px", margin: "20px" }}> <div style={{ width: "250px", margin: "20px" }}>
<TreeMenu <TreeMenu
checkable={boolean("checkable", false)} {...args}
draggable={boolean("draggable", false)}
disabled={boolean("disabled", false)}
badgeLabel={number("badgeLabel")}
multiple={boolean("multiple", false)}
showIcon={boolean("showIcon", true)}
isFullFillSelection={boolean("isFullFillSelection", true)}
gapBetweenNodes={text("gapBetweenNodes")}
gapBetweenNodesTablet={text("gapBetweenNodesTablet")}
isEmptyRootNode={boolean("isEmptyRootNode", false)}
defaultExpandAll={boolean("defaultExpandAll", false)}
defaultExpandParent={boolean("defaultExpandParent", true)}
onExpand={onExpand} onExpand={onExpand}
autoExpandParent={autoExpandParent} autoExpandParent={autoExpandParent}
expandedKeys={expandedKeys} expandedKeys={expandedKeys}
@ -183,10 +165,10 @@ const TreeMenuStory = (props) => {
onDrop={(info) => onDrop(info)} onDrop={(info) => onDrop(info)}
onDragEnter={onDragEnter} onDragEnter={onDragEnter}
switcherIcon={switcherIcon} switcherIcon={switcherIcon}
onSelect={action("select")} onSelect={() => onSelect("select")}
onLoad={action("load")} onLoad={() => onLoad("load")}
onCheck={action("check")} onCheck={() => onCheck("check")}
onRightClick={action("rightClick")} onRightClick={() => onRightClick("rightClick")}
> >
{getTreeNodes(gData)} {getTreeNodes(gData)}
</TreeMenu> </TreeMenu>
@ -194,7 +176,19 @@ const TreeMenuStory = (props) => {
); );
}; };
storiesOf("Components|Tree", module) export const basic = Template.bind({});
.addDecorator(withKnobs) basic.args = {
.addDecorator(withReadme(Readme)) checkable: false,
.add("base", () => <TreeMenuStory data={treeData} />); draggable: false,
disabled: false,
multiple: false,
showIcon: true,
isFullFillSelection: true,
isEmptyRootNode: false,
defaultExpandAll: false,
defaultExpandParent: true,
data: treeData,
title: "Title",
newItems: 0,
showBadge: false,
};

View File

@ -0,0 +1,59 @@
import { Story, ArgsTable, Canvas, Meta } from "@storybook/addon-docs/blocks";
import * as stories from "./tree-menu.stories.js";
import TreeMenu from "./";
import TreeNode from "./sub-components/tree-node.js";
<Meta
title="Components/TreeMenu"
component={TreeMenu}
subcomponents={{ TreeMenu, TreeNode }}
parameters={{
source: {
code: stories.basic,
},
}}
argTypes={{
onSelect: { action: "onSelect" },
onLoad: { action: "onLoad" },
onCheck: { action: "onCheck" },
onRightClick: { action: "onRightClick" },
}}
/>
# TreeMenu
Tree menu description
<Canvas>
<Story story={stories.basic} name="Default" />
</Canvas>
<ArgsTable story="Default" />
### Usage
```js
import TreeMenu from "@appserver/components/tree-menu";
```
```jsx
<TreeMenu data={data} />
```
### Properties TreeNode
| Props | Type | Required | Values | Default | Description |
| ----------------- | :----------------: | :------: | :----: | :-----: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `checkable` | `bool` | - | - | - | control node checkable if Tree is checkable |
| `className` | `string` | - | - | - | additional class to treeNode |
| `disableCheckbox` | `bool` | - | - | `false` | whether disable the treeNode' checkbox |
| `disabled` | `bool` | - | - | `false` | whether disabled the treeNode |
| `icon` | `element`,`func` | - | - | `false` | customize icon. When you pass component, whose render will receive full TreeNode props as component props |
| `isLeaf` | `bool` | - | - | `false` | whether it's leaf node |
| `key` | `bool` | - | - | - | it's used with tree props's (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys. you'd better to set it, and it must be unique in the tree's all treeNodes |
| `style` | `object` | - | - | - | set style to treeNode |
| `title` | `string`,`element` | - | - | - | tree/subTree's title |
| `newItems` | `number` | - | - | - | The number of new elements in the node |
| `onBadgeClick` | `func` | - | - | - | call when click on badge |
| `showBadge` | `bool` | - | - | - | to display the badge |