From 65ff55317327331008dcca708775bdf8bd0e856f Mon Sep 17 00:00:00 2001 From: "Phillip M. Hoff" Date: Thu, 27 Oct 2016 10:09:08 -0700 Subject: [PATCH 1/4] Add onNodeExpansionChanged handler. --- examples/src/App.js | 13 +++++++++++++ src/JSONNestedNode.js | 17 +++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/examples/src/App.js b/examples/src/App.js index be68c26..56e9a2c 100755 --- a/examples/src/App.js +++ b/examples/src/App.js @@ -158,6 +158,19 @@ const App = () => ( shouldExpandNode={() => false} /> +

Expansion Notifications

+
+ false} + onNodeExpansionChanged={ + (keyPath, data, level, expanded) => { + console.log(`Node ${expanded ? 'expanded' : 'collapsed'}: ${keyPath}`); + } + } + /> +
); diff --git a/src/JSONNestedNode.js b/src/JSONNestedNode.js index 2edf6de..4895c82 100644 --- a/src/JSONNestedNode.js +++ b/src/JSONNestedNode.js @@ -76,7 +76,8 @@ export default class JSONNestedNode extends React.Component { level: PropTypes.number.isRequired, sortObjectKeys: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), isCircular: PropTypes.bool, - expandable: PropTypes.bool + expandable: PropTypes.bool, + onNodeExpansionChanged: PropTypes.func }; static defaultProps = { @@ -166,5 +167,17 @@ export default class JSONNestedNode extends React.Component { ); } - handleClick = () => this.setState({ expanded: !this.state.expanded }); + handleClick = () => { + this.setState( + { expanded: !this.state.expanded }, + () => { + if (this.props.onNodeExpansionChanged) { + this.props.onNodeExpansionChanged( + this.props.keyPath, + this.props.data, + this.props.level, + this.state.expanded); + } + }); + } } From 482af3246b6aa3a36ceca8b321a7993281c6fb64 Mon Sep 17 00:00:00 2001 From: "Phillip M. Hoff" Date: Thu, 27 Oct 2016 10:12:17 -0700 Subject: [PATCH 2/4] Update documentation. --- README.md | 1 + package.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db36046..e62a178 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ For `labelRenderer`, you can provide a full path - [see this PR](https://github. - `shouldExpandNode: function(keyName, data, level)` - determines if node should be expanded (root is expanded by default) - `hideRoot: Boolean` - if `true`, the root node is hidden. - `sortObjectKeys: Boolean | function(a, b)` - sorts object keys with compare function (optional). Isn't applied to iterable maps like `Immutable.Map`. +- `onNodeExpansionChanged: function(keyName, data, level, expanded)` - invoked when a node is expanded or collapsed. ### Credits diff --git a/package.json b/package.json index b53cd2c..5c3cc66 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "author": "Shu Uesugi (http://github.com/chibicode)", "contributors": [ "Dave Vedder (http://www.eskimospy.com/)", - "Daniele Zannotti (http://www.github.com/dzannotti)" + "Daniele Zannotti (http://www.github.com/dzannotti)", + "Phillip Hoff (http://www.github.com/philliphoff)" ], "license": "MIT", "bugs": { From b4b2f82ff52709876605a3e0b99e8aab56211c53 Mon Sep 17 00:00:00 2001 From: "Phillip M. Hoff" Date: Wed, 2 Nov 2016 16:32:16 -0700 Subject: [PATCH 3/4] Added chang-ing event and dynamic expansion option. --- examples/src/App.js | 5 ++++ src/JSONNestedNode.js | 58 ++++++++++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/examples/src/App.js b/examples/src/App.js index 56e9a2c..5bfc644 100755 --- a/examples/src/App.js +++ b/examples/src/App.js @@ -164,6 +164,11 @@ const App = () => ( data={data} theme={theme} shouldExpandNode={() => false} + onNodeExpansionChanging={ + (keyPath, data, level, expanded) => { + console.log(`Node ${expanded ? 'expanding' : 'collapsing'}: ${keyPath}`); + } + } onNodeExpansionChanged={ (keyPath, data, level, expanded) => { console.log(`Node ${expanded ? 'expanded' : 'collapsed'}: ${keyPath}`); diff --git a/src/JSONNestedNode.js b/src/JSONNestedNode.js index 4895c82..017270a 100644 --- a/src/JSONNestedNode.js +++ b/src/JSONNestedNode.js @@ -77,7 +77,9 @@ export default class JSONNestedNode extends React.Component { sortObjectKeys: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), isCircular: PropTypes.bool, expandable: PropTypes.bool, - onNodeExpansionChanged: PropTypes.func + onNodeExpansionChanging: PropTypes.func, + onNodeExpansionChanged: PropTypes.func, + isNodeExpansionDynamic: PropTypes.bool }; static defaultProps = { @@ -99,7 +101,7 @@ export default class JSONNestedNode extends React.Component { }; } - shouldComponentUpdate = shouldPureComponentUpdate; + shouldComponentUpdate = this.props.isNodeExpansionDynamic ? undefined : shouldPureComponentUpdate; render() { const { @@ -115,7 +117,13 @@ export default class JSONNestedNode extends React.Component { labelRenderer, expandable } = this.props; - const expanded = this.state.expanded; + const expanded = + this.props.isNodeExpansionDynamic + && this.props.shouldExpandNode + && !this.props.isCircular + ? this.props.shouldExpandNode(this.props.keyPath, this.props.data, this.props.level) + : this.state.expanded; + const renderedChildren = expanded || (hideRoot && this.props.level === 0) ? renderChildNodes({ ...this.props, level: this.props.level + 1 }) : null; @@ -132,6 +140,30 @@ export default class JSONNestedNode extends React.Component { ); const stylingArgs = [keyPath, nodeType, expanded, expandable]; + const handleClick = () => { + const newState = !expanded; + + if (this.props.onNodeExpansionChanging) { + this.props.onNodeExpansionChanging( + this.props.keyPath, + this.props.data, + this.props.level, + newState); + } + + this.setState( + { expanded: newState }, + () => { + if (this.props.onNodeExpansionChanged) { + this.props.onNodeExpansionChanged( + this.props.keyPath, + this.props.data, + this.props.level, + this.state.expanded); + } + }); + }; + return hideRoot ? (
    • @@ -145,18 +177,18 @@ export default class JSONNestedNode extends React.Component { styling={styling} nodeType={nodeType} expanded={expanded} - onClick={this.handleClick} + onClick={handleClick} /> } {renderedItemString} @@ -166,18 +198,4 @@ export default class JSONNestedNode extends React.Component { ); } - - handleClick = () => { - this.setState( - { expanded: !this.state.expanded }, - () => { - if (this.props.onNodeExpansionChanged) { - this.props.onNodeExpansionChanged( - this.props.keyPath, - this.props.data, - this.props.level, - this.state.expanded); - } - }); - } } From 1cff71b9f22ba2ae53ecb0a3d37b23e35a145f0b Mon Sep 17 00:00:00 2001 From: "Phillip M. Hoff" Date: Fri, 4 Nov 2016 13:14:56 -0700 Subject: [PATCH 4/4] Document new options. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e62a178..92e4946 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,9 @@ For `labelRenderer`, you can provide a full path - [see this PR](https://github. - `shouldExpandNode: function(keyName, data, level)` - determines if node should be expanded (root is expanded by default) - `hideRoot: Boolean` - if `true`, the root node is hidden. - `sortObjectKeys: Boolean | function(a, b)` - sorts object keys with compare function (optional). Isn't applied to iterable maps like `Immutable.Map`. +- `onNodeExpansionChanging: function(keyName, data, level, expanded)` - invoked when a node is expanding or collapsing. - `onNodeExpansionChanged: function(keyName, data, level, expanded)` - invoked when a node is expanded or collapsed. +- `isNodeExpansionDynamic: Boolean` - if `true`, `shouldExpandNode` will be called each render to determine the expansion state of a node, rather than just once during mount ### Credits