/* eslint-disable max-depth */ import {number, withKnobs} from '@storybook/addon-knobs'; import {storiesOf} from '@storybook/react'; import React, {FC, useCallback, useEffect, useRef} from 'react'; import AutoSizer from 'react-virtualized-auto-sizer'; import { TreeWalker, TreeWalkerValue, VariableSizeNodeData, VariableSizeNodePublicState, VariableSizeTree, } from '../src'; import {NodeComponentProps} from '../src/Tree'; document.body.style.margin = '0'; document.body.style.display = 'flex'; document.body.style.minHeight = '100vh'; const root = document.getElementById('root')!; root.style.margin = '10px 0 0 10px'; root.style.flex = '1'; type TreeNode = Readonly<{ children: TreeNode[]; id: number; name: string; }>; type NodeMeta = Readonly<{ nestingLevel: number; node: TreeNode; }>; type ExtendedData = VariableSizeNodeData & Readonly<{ isLeaf: boolean; name: string; nestingLevel: number; }>; let nodeId = 0; const createNode = (depth: number = 0) => { const node: TreeNode = { children: [], id: nodeId, name: `test-${nodeId}`, }; nodeId += 1; if (depth === 5) { return node; } for (let i = 0; i < 10; i++) { node.children.push(createNode(depth + 1)); } return node; }; const rootNode = createNode(); const defaultGapStyle = {marginLeft: 10}; const defaultButtonStyle = {fontFamily: 'Courier New'}; const Node: FC >> = ({ height, data: {isLeaf, name, nestingLevel}, isOpen, resize, style, setOpen, treeData: itemSize, }) => { const canOpen = height <= itemSize; const halfSize = itemSize / 2; const toggleNodeSize = useCallback( () => resize(canOpen ? height + halfSize : height - halfSize, true), [height, resize], ); return (
{!isLeaf && (
)}
{name}
); }; type TreePresenterProps = Readonly<{ itemSize: number; }>; const getNodeData = ( node: TreeNode, nestingLevel: number, itemSize: number, ): TreeWalkerValue => ({ data: { defaultHeight: itemSize, id: node.id.toString(), isLeaf: node.children.length === 0, isOpenByDefault: true, name: node.name, nestingLevel, }, nestingLevel, node, }); const TreePresenter: FC = ({itemSize}) => { const tree = useRef>(null); const treeWalker = useCallback( function* treeWalker(): ReturnType> { yield getNodeData(rootNode, 0, itemSize); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition while (true) { const parentMeta = yield; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < parentMeta.node.children.length; i++) { yield getNodeData( parentMeta.node.children[i], parentMeta.nestingLevel + 1, itemSize, ); } } }, [itemSize], ); useEffect(() => { // eslint-disable-next-line @typescript-eslint/no-floating-promises tree.current?.recomputeTree({ refreshNodes: true, useDefaultHeight: true, }); }, [itemSize]); return ( {({height}) => ( {Node} )} ); }; storiesOf('Tree', module) .addDecorator(withKnobs) .add('VariableSizeTree', () => ( ));