Skip to content

Commit

Permalink
refactor(types): adds typings for Tree
Browse files Browse the repository at this point in the history
* removes redundant props (textLayout, styles)
  • Loading branch information
bkrem committed Jan 30, 2020
1 parent f07f821 commit 407c40a
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 241 deletions.
3 changes: 3 additions & 0 deletions demo/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,9 @@ class App extends Component {
depthFactor={this.state.depthFactor}
textLayout={this.state.textLayout}
styles={this.state.styles}
onUpdate={(...args) => {console.log(args)}}
onClick={(...args) => { console.log('onClick'); console.log(args) }}
onLinkClick={(...args) => { console.log('onLinkClick'); console.log(args) }}
/>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"@babel/preset-react": "^7.8.3",
"@babel/preset-typescript": "^7.8.3",
"@types/react": "^16.9.17",
"babel-eslint": "^10.0.3",
"babel-jest": "^24.9.0",
"coveralls": "^3.0.0",
"enzyme": "^3.4.4",
Expand Down
18 changes: 14 additions & 4 deletions src/Link/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import React from 'react';
import React, { SyntheticEvent } from 'react';
import { svg, select } from 'd3';
import { Orientation, NodeData, LinkData, PathFunctionOption, PathFunction } from '../types/common';
import {
Orientation,
EnhancedTreeNode,
TreeLink,
PathFunctionOption,
PathFunction,
} from '../types/common';
import './style.css';

type LinkEventHandler = (source: NodeData, target: NodeData, evt: Event) => void;
type LinkEventHandler = (
source: EnhancedTreeNode,
target: EnhancedTreeNode,
evt: SyntheticEvent
) => void;

type LinkProps = {
linkData: LinkData;
linkData: TreeLink;
orientation: Orientation;
pathFunc: PathFunctionOption | PathFunction;
transitionDuration: number;
Expand Down
33 changes: 7 additions & 26 deletions src/Node/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import React from 'react';
import React, { SyntheticEvent } from 'react';
import { select } from 'd3';
import SvgTextElement from './SvgTextElement';
import ForeignObjectElement from './ForeignObjectElement';
import { Orientation, NodeData, FIXME } from '../types/common';
import { Orientation, EnhancedTreeNode, FIXME, NodeElement } from '../types/common';
import './style.css';

type NodeEventHandler = (id: string, evt: Event) => void;
type NodeEventHandler = (id: string, evt: SyntheticEvent) => void;

type NodeProps = {
nodeData: NodeData;
nodeElement: {
shape: string;
baseProps: FIXME;
branchNodeProps: FIXME;
leafNodeProps: FIXME;
};
nodeData: EnhancedTreeNode;
nodeElement: NodeElement;
nodeLabelProps: FIXME;
nodeLabelComponent?: FIXME;
nodeSize: {
Expand All @@ -26,10 +21,8 @@ type NodeProps = {
onClick: NodeEventHandler;
onMouseOver: NodeEventHandler;
onMouseOut: NodeEventHandler;
textLayout: FIXME;
subscriptions: object;
allowForeignObjects: boolean;
styles?: object;
};

type NodeState = {
Expand All @@ -40,18 +33,6 @@ type NodeState = {
export default class Node extends React.Component<NodeProps, NodeState> {
static defaultProps = {
nodeLabelComponent: null,
styles: {
node: {
circle: {},
name: {},
attributes: {},
},
leafNode: {
circle: {},
name: {},
attributes: {},
},
},
};

private nodeRef: SVGGElement = null;
Expand Down Expand Up @@ -127,11 +108,11 @@ export default class Node extends React.Component<NodeProps, NodeState> {

renderNodeElement = () => {
const { nodeElement, nodeData } = this.props;
const { shape, baseProps, leafNodeProps, branchNodeProps } = nodeElement;
const { tag, baseProps, leafNodeProps = {}, branchNodeProps = {} } = nodeElement;
const elemProps = nodeData._children
? { ...baseProps, ...branchNodeProps }
: { ...baseProps, ...leafNodeProps };
return shape === 'none' ? null : React.createElement(shape, elemProps);
return tag === 'none' ? null : React.createElement(tag, elemProps);
};

renderNodeLabelElement = () => {
Expand Down
49 changes: 24 additions & 25 deletions src/Node/tests/index.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { shallow, mount } from 'enzyme';

import Node from '../index';
import Node from '../index.tsx';

describe('<Node />', () => {
const nodeData = {
Expand All @@ -23,7 +23,7 @@ describe('<Node />', () => {
y: 321,
},
nodeElement: {
shape: 'circle',
tag: 'circle',
baseProps: {
r: 10,
},
Expand All @@ -44,7 +44,6 @@ describe('<Node />', () => {
y: -10,
},
subscriptions: {},
styles: {},
allowForeignObjects: false,
};

Expand All @@ -62,7 +61,7 @@ describe('<Node />', () => {
it('applies correct base className if `nodeData._children` is defined', () => {
const leafNodeComponent = shallow(<Node {...mockProps} />);
const nodeComponent = shallow(
<Node {...mockProps} nodeData={{ ...nodeData, _children: [] }} />,
<Node {...mockProps} nodeData={{ ...nodeData, _children: [] }} />
);

expect(leafNodeComponent.find('g').prop('className')).toBe('leafNodeBase');
Expand Down Expand Up @@ -116,7 +115,7 @@ describe('<Node />', () => {

expect(renderedComponent.instance().applyTransform).toHaveBeenCalledWith(
fixture,
mockProps.transitionDuration,
mockProps.transitionDuration
);
});

Expand All @@ -136,14 +135,14 @@ describe('<Node />', () => {

expect(renderedComponent.instance().applyTransform).toHaveBeenCalledWith(
initialTransform,
mockProps.transitionDuration,
mockProps.transitionDuration
);

renderedComponent.setProps(updatedProps);

expect(renderedComponent.instance().applyTransform).toHaveBeenCalledWith(
updatedTransform,
mockProps.transitionDuration,
mockProps.transitionDuration
);
});

Expand All @@ -153,7 +152,7 @@ describe('<Node />', () => {
const renderedComponent = mount(<Node {...thisProps} />);
const nextProps = { ...thisProps, orientation: 'vertical' };
expect(
renderedComponent.instance().shouldNodeTransform(renderedComponent.props(), nextProps),
renderedComponent.instance().shouldNodeTransform(renderedComponent.props(), nextProps)
).toBe(true);
});

Expand All @@ -163,63 +162,63 @@ describe('<Node />', () => {
const nextProps = { ...mockProps, subscriptions: { ...subscriptions, initialDepth: 1 } };

expect(
renderedComponent.instance().shouldNodeTransform(renderedComponent.props(), nextProps),
renderedComponent.instance().shouldNodeTransform(renderedComponent.props(), nextProps)
).toBe(true);
});
});

// TODO: should default to circle shape if not provided
// TODO: should default to circle tag if not provided
describe('NodeElement', () => {
it('allows passing SVG shape elements + baseProps to be used as the node element', () => {
const fixture = { shape: 'ellipse', baseProps: { rx: 20, ry: 10 } };
it('allows passing SVG tag + baseProps to be used as the node element', () => {
const fixture = { tag: 'ellipse', baseProps: { rx: 20, ry: 10 } };
const props = { ...mockProps, nodeElement: fixture };
const renderedComponent = shallow(<Node {...props} />);

expect(renderedComponent.find(fixture.shape).length).toBe(1);
expect(renderedComponent.find(fixture.shape).props()).toEqual(fixture.baseProps);
expect(renderedComponent.find(fixture.tag).length).toBe(1);
expect(renderedComponent.find(fixture.tag).props()).toEqual(fixture.baseProps);
});
it('renders the appropriate SVG element if `props.nodeElement` is defined', () => {
const props = { ...mockProps, nodeElement: { shape: 'rect', baseProps: { y: 123 } } };
const props = { ...mockProps, nodeElement: { tag: 'rect', baseProps: { y: 123 } } };
const renderedComponent = shallow(<Node {...props} />);
expect(renderedComponent.find('rect').length).toBe(1);
expect(renderedComponent.find('rect').prop('y')).toBe(123);
});

it('renders nothing if `nodeElement.shape` is set to `none`', () => {
const props = { ...mockProps, nodeElement: { shape: 'none' } };
it('renders nothing if `nodeElement.tag` is set to `none`', () => {
const props = { ...mockProps, nodeElement: { tag: 'none' } };
const renderedComponent = shallow(<Node {...props} />);
expect(renderedComponent.instance().renderNodeElement({})).toBe(null);
});

it('merges `branchNodeProps` into `baseProps` if node has `_children`', () => {
const fixture = {
nodeElement: {
shape: 'rect',
tag: 'rect',
branchNodeProps: { fill: 'green', r: 20 },
},
};
// const leafNodeComponent = shallow(<Node {...mockProps} />);
const renderedComponent = shallow(
<Node {...mockProps} {...fixture} nodeData={{ ...nodeData, _children: [{}] }} />,
<Node {...mockProps} {...fixture} nodeData={{ ...nodeData, _children: [{}] }} />
);

expect(renderedComponent.find(fixture.nodeElement.shape).props()).toEqual(
fixture.nodeElement.branchNodeProps,
expect(renderedComponent.find(fixture.nodeElement.tag).props()).toEqual(
fixture.nodeElement.branchNodeProps
);
});

it('merges `leafNodeProps` into `baseProps` if node has no children', () => {
const fixture = {
nodeElement: {
shape: 'rect',
tag: 'rect',
leafNodeProps: { fill: 'red', r: 15 },
},
};
// const leafNodeComponent = shallow(<Node {...mockProps} />);
const renderedComponent = shallow(<Node {...mockProps} {...fixture} />);

expect(renderedComponent.find(fixture.nodeElement.shape).props()).toEqual(
fixture.nodeElement.leafNodeProps,
expect(renderedComponent.find(fixture.nodeElement.tag).props()).toEqual(
fixture.nodeElement.leafNodeProps
);
});

Expand Down Expand Up @@ -251,7 +250,7 @@ describe('<Node />', () => {

it('renders a ForeignObjectElement if `props.allowForeignObjects && props.nodeLabelComponent`', () => {
const renderedComponent = shallow(
<Node {...mockProps} nodeLabelComponent={{ render: <div /> }} allowForeignObjects />,
<Node {...mockProps} nodeLabelComponent={{ render: <div /> }} allowForeignObjects />
);
expect(renderedComponent.find('ForeignObjectElement').length).toBe(1);
});
Expand Down
Loading

0 comments on commit 407c40a

Please sign in to comment.