Skip to content

Commit 8ad82e2

Browse files
committed
Add EventTrap for handling selection & expansion of rows in TreeGrid
1 parent a52fec1 commit 8ad82e2

File tree

6 files changed

+77
-60
lines changed

6 files changed

+77
-60
lines changed

components/tree-grid/__docs__/storybook-stories.jsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ storiesOf(TREE_GRID, module)
1111
<div className="slds-p-around_medium">{getStory()}</div>
1212
))
1313
.add('Default', () => <Default action={action} />)
14-
.add('Single Select', () => (
15-
<Default action={action} selectRows="single" />
16-
))
14+
.add('Single Select', () => <Default action={action} selectRows="single" />)
1715
.add('w/o Border', () => <Default action={action} isBorderless />)
1816
.add('Single Select w/o Border', () => (
1917
<Default action={action} selectRows="single" isBorderless />

components/tree-grid/__examples__/default.jsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ class Example extends React.Component {
182182
nodes: this.props.nodes || sampleData,
183183
isIndeterminate: false,
184184
allSelect: false,
185-
selectedNode: null
185+
selectedNode: null,
186186
};
187187

188188
getNodes = (node) =>
@@ -236,8 +236,7 @@ class Example extends React.Component {
236236
eventName: 'Select Branch',
237237
data,
238238
});
239-
if(this.props.selectRows !== "single")
240-
{
239+
if (this.props.selectRows !== 'single') {
241240
const curr = this.state.nodes;
242241
curr[data.node.id].selected = data.selected;
243242
const selectedCount = this.countSelected(curr['0'].nodes);
@@ -250,12 +249,13 @@ class Example extends React.Component {
250249
isIndeterminate = null;
251250
}
252251
this.setState({ nodes: curr, isIndeterminate, allSelect });
253-
}
254-
else {
252+
} else {
255253
const { nodes, selectedNode } = this.state;
256254
nodes[data.node.id].selected = true;
257-
if(selectedNode != null) { nodes[selectedNode].selected = false; }
258-
this.setState({ nodes, selectedNode: data.node.id })
255+
if (selectedNode != null) {
256+
nodes[selectedNode].selected = false;
257+
}
258+
this.setState({ nodes, selectedNode: data.node.id });
259259
}
260260
};
261261

@@ -290,7 +290,7 @@ class Example extends React.Component {
290290
<IconSettings iconPath="/assets/icons">
291291
<div style={{ overflow: 'auto' }}>
292292
<TreeGrid
293-
id="example"
293+
id="example-tree-grid"
294294
nodes={this.state.nodes['0'].nodes}
295295
isBorderless={this.props.isBorderless}
296296
getNodes={this.getNodes}
@@ -335,7 +335,7 @@ class Example extends React.Component {
335335
id="file-more-actions"
336336
iconCategory="utility"
337337
iconName="chevrondown"
338-
iconVariant="small"
338+
iconVariant="container"
339339
iconSize="x-small"
340340
align="right"
341341
onSelect={(event, data) => {
@@ -367,7 +367,7 @@ class Example extends React.Component {
367367
id="file-more-actions"
368368
iconCategory="utility"
369369
iconName="chevrondown"
370-
iconVariant="small"
370+
iconVariant="container"
371371
iconSize="x-small"
372372
align="right"
373373
onSelect={(event, data) => {
@@ -399,7 +399,7 @@ class Example extends React.Component {
399399
id="file-more-actions"
400400
iconCategory="utility"
401401
iconName="chevrondown"
402-
iconVariant="small"
402+
iconVariant="container"
403403
iconSize="x-small"
404404
align="right"
405405
onSelect={(event, data) => {
@@ -434,7 +434,7 @@ class Example extends React.Component {
434434
id="file-more-actions"
435435
iconCategory="utility"
436436
iconName="chevrondown"
437-
iconVariant="small"
437+
iconVariant="container"
438438
iconSize="x-small"
439439
align="right"
440440
onSelect={(event, data) => {
@@ -466,7 +466,7 @@ class Example extends React.Component {
466466
id="file-more-actions"
467467
iconCategory="utility"
468468
iconName="chevrondown"
469-
iconVariant="small"
469+
iconVariant="container"
470470
iconSize="x-small"
471471
align="right"
472472
onSelect={(event, data) => {

components/tree-grid/__examples__/headless.jsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,18 @@ class Example extends React.Component {
135135
this.setState({ nodes: updated });
136136
};
137137

138+
findChildren = (node) => {
139+
if (node.type === 'branch') {
140+
let list = [];
141+
node.nodes.forEach((child) => {
142+
const c = this.findChildren(this.state.nodes[child]);
143+
list = [...c, child, ...list];
144+
});
145+
return list;
146+
}
147+
return [];
148+
};
149+
138150
handleSelection = (event, data) => {
139151
log({
140152
action: this.props.action,

components/tree-grid/column.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import React from 'react';
99
import PropTypes from 'prop-types';
1010
import classNames from 'classnames';
11+
import isFunction from 'lodash.isfunction';
1112

1213
import Icon from '../icon';
1314

@@ -35,7 +36,7 @@ const TreeGridColumn = (props) => {
3536
>
3637
<a
3738
className="slds-th__action slds-text-link_reset"
38-
href="javascript:void(0);"
39+
onClick={isFunction(props.onClick) ? props.onClick : null}
3940
role="button"
4041
tabIndex="-1"
4142
>
@@ -77,7 +78,6 @@ TreeGridColumn.propTypes = {
7778
assistiveText: PropTypes.shape({
7879
sortBy: PropTypes.string,
7980
}),
80-
children: PropTypes.element,
8181
/**
8282
* Some columns, such as "date last viewed" or "date recently updated," should sort descending first, since that is what the user probably wants. How often does one want to see their oldest files first in a table? If sortable and the `DataTable`'s parent has not defined the sort order, then ascending (A at the top to Z at the bottom) is the default sort order on first click.
8383
*/

components/tree-grid/index.jsx

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import classNames from 'classnames';
1010
// shortid is a short, non-sequential, url-friendly, unique id generator
1111
import shortid from 'shortid';
1212
import assign from 'lodash.assign';
13+
import isFunction from 'lodash.isfunction';
1314

1415
import { TREE_GRID } from '../../utilities/constants';
1516
import TreeGridColumn from './column';
@@ -73,15 +74,15 @@ const propTypes = {
7374
/**
7475
* Callback function for selection of rows
7576
*/
76-
onSelect: PropTypes.func.isRequired,
77+
onSelect: PropTypes.func,
7778
/**
7879
* Callback function for selection of all rows
7980
*/
80-
onSelectAll: PropTypes.func.isRequired,
81+
onSelectAll: PropTypes.func,
8182
/**
8283
* Callback function for expansion of rows
8384
*/
84-
onExpand: PropTypes.func.isRequired,
85+
onExpand: PropTypes.func,
8586
/**
8687
* Whether the TreeGrid is headless
8788
*/
@@ -168,16 +169,10 @@ class TreeGrid extends React.Component {
168169
});
169170
};
170171

171-
handleSelection = (event, data) => {
172-
this.props.onSelect(event, data);
173-
};
174-
175172
handleSelectAll = (event, data) => {
176-
this.props.onSelectAll(event, data);
177-
};
178-
179-
handleExpansion = (event, data) => {
180-
this.props.onExpand(event, data);
173+
if (isFunction(this.props.onSelectAll)) {
174+
this.props.onSelectAll(event, data);
175+
}
181176
};
182177

183178
render() {
@@ -193,7 +188,6 @@ class TreeGrid extends React.Component {
193188
const { children, ...columnProps } = child.props;
194189

195190
const props = assign({}, this.props);
196-
delete props.children;
197191
assign(props, columnProps);
198192

199193
columns.push({
@@ -208,6 +202,7 @@ class TreeGrid extends React.Component {
208202
id={this.getId()}
209203
aria-readonly="true"
210204
aria-multiselectable={this.props.selectRows === 'multiple'}
205+
/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role */
211206
role="treegrid"
212207
className={classNames(
213208
'slds-table',
@@ -272,8 +267,8 @@ class TreeGrid extends React.Component {
272267
flattenedNodes={this.state.flattenedNodes}
273268
focusedNodeIndex={this.state.focusedNodeIndex}
274269
columns={columns}
275-
onSelect={this.handleSelection}
276-
onExpand={this.handleExpansion}
270+
onSelect={this.props.onSelect}
271+
onExpand={this.props.onExpand}
277272
onFocus={this.handleFocus}
278273
selectRows={this.props.selectRows}
279274
moreActionsDropdown={this.props.moreActionsDropdown}

components/tree-grid/private/item.jsx

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,19 @@ import PropTypes from 'prop-types';
33
import classNames from 'classnames';
44
import shortid from 'shortid';
55
import findIndex from 'lodash.findindex';
6+
import isFunction from 'lodash.isfunction';
67

78
import { TREE_GRID_ITEM } from '../../../utilities/constants';
89
import Checkbox from '../../checkbox';
910
import TreeGridCell from './cell';
1011

12+
import EventUtil from '../../../utilities/event';
1113
import KEYS from '../../../utilities/key-code';
1214
import mapKeyEventCallbacks from '../../../utilities/key-callbacks';
1315

1416
const Item = (props) => {
1517
const isFocused = props.treeIndex === props.focusedNodeIndex;
1618

17-
const handleExpansion = (event) => {
18-
props.onExpand(event, {
19-
node: props.row,
20-
expanded: !props.row.expanded,
21-
});
22-
};
23-
24-
const handleSelection = (event) => {
25-
props.onSelect(event, {
26-
node: props.row,
27-
selected: !props.row.selected,
28-
});
29-
};
30-
3119
const findNextNode = (flattenedNodes, node) => {
3220
const nodes = flattenedNodes.map((flattenedNode) => flattenedNode.node);
3321
const index = findIndex(nodes, { id: node.id });
@@ -43,6 +31,26 @@ const Item = (props) => {
4331
return flattenedNodes[index];
4432
};
4533

34+
const handleExpansion = (event) => {
35+
if (isFunction(props.onExpand)) {
36+
EventUtil.trap(event);
37+
props.onExpand(event, {
38+
node: props.row,
39+
expanded: !props.row.expanded,
40+
});
41+
}
42+
};
43+
44+
const handleSelection = (event) => {
45+
if (isFunction(props.onSelect)) {
46+
EventUtil.trap(event);
47+
props.onSelect(event, {
48+
node: props.row,
49+
selected: !props.row.selected,
50+
});
51+
}
52+
};
53+
4654
const handleKeyDownDown = (event) => {
4755
const flattenedNode = findNextNode(props.flattenedNodes, props.row);
4856
props.onFocus(event, flattenedNode);
@@ -54,21 +62,25 @@ const Item = (props) => {
5462
};
5563

5664
const handleKeyDownLeft = (event) => {
57-
props.onExpand(event, {
58-
node: props.row,
59-
expanded: false,
60-
});
65+
if (props.row.nodes !== undefined) {
66+
if (isFunction(props.onExpand)) {
67+
props.onExpand(event, {
68+
node: props.row,
69+
expanded: false,
70+
});
71+
}
72+
}
6173
};
6274

6375
const handleKeyDownRight = (event) => {
64-
props.onExpand(event, {
65-
node: props.row,
66-
expanded: true,
67-
});
68-
};
69-
70-
const handleKeyDownEnter = (event) => {
71-
handleSelection(event);
76+
if (props.row.nodes !== undefined) {
77+
if (isFunction(props.onExpand)) {
78+
props.onExpand(event, {
79+
node: props.row,
80+
expanded: true,
81+
});
82+
}
83+
}
7284
};
7385

7486
const handleKeyDown = (event) => {
@@ -78,7 +90,7 @@ const Item = (props) => {
7890
[KEYS.UP]: { callback: (e) => handleKeyDownUp(e) },
7991
[KEYS.LEFT]: { callback: (e) => handleKeyDownLeft(e) },
8092
[KEYS.RIGHT]: { callback: (e) => handleKeyDownRight(e) },
81-
[KEYS.ENTER]: { callback: (e) => handleKeyDownEnter(e) },
93+
[KEYS.ENTER]: { callback: (e) => handleSelection(e) },
8294
},
8395
});
8496
};

0 commit comments

Comments
 (0)