Skip to content

Commit 381dd37

Browse files
committed
Add onContextMenu property
Resolves #237.
1 parent 6d77839 commit 381dd37

File tree

5 files changed

+62
-3
lines changed

5 files changed

+62
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
### New Features
2727

2828
* Add `checkKeys` property to allow specification of JavaScript keys to trigger check behavior
29+
* Add `onContextMenu` property, which will trigger whenever a user right-clicks a node (#237)
2930

3031
## [v1.8.0](https://github.com/jakezatecky/react-checkbox-tree/compare/v1.7.3...v1.8.0) (2022-09-06)
3132

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ Returns:
174174
| `showNodeIcon` | bool | If true, each node will show a parent or leaf icon. | `true` |
175175
| `showNodeTitle` | bool | If true, the `label` of each node will become the `title` of the resulting DOM node. Overridden by `node.title`. | `false` |
176176
| `onCheck` | function | onCheck handler: `function(checked, targetNode) {}` | `() => {}` |
177-
| `onClick` | function | onClick handler: `function(targetNode) {}`. If set, `onClick` will be called when a node's label has been clicked. | `() => {}` |
177+
| `onClick` | function | onClick handler: `function(targetNode) {}`. If set, `onClick` will be called when a node's label has been clicked. | `null` |
178+
| `onContextMenu` | function | onContextMenu handler: `function(event, targetNode) {}`. Triggers when right-clicking a node element. | `null` |
178179
| `onExpand` | function | onExpand handler: `function(expanded, targetNode) {}` | `() => {}` |
179180

180181
#### `onCheck` and `onExpand`

src/js/CheckboxTree.jsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class CheckboxTree extends React.Component {
5656
showNodeTitle: PropTypes.bool,
5757
onCheck: PropTypes.func,
5858
onClick: PropTypes.func,
59+
onContextMenu: PropTypes.func,
5960
onExpand: PropTypes.func,
6061
};
6162

@@ -83,6 +84,7 @@ class CheckboxTree extends React.Component {
8384
showNodeTitle: false,
8485
onCheck: () => {},
8586
onClick: null,
87+
onContextMenu: null,
8688
onExpand: () => {},
8789
};
8890

@@ -102,6 +104,7 @@ class CheckboxTree extends React.Component {
102104
};
103105

104106
this.onCheck = this.onCheck.bind(this);
107+
this.onContextMenu = this.onContextMenu.bind(this);
105108
this.onExpand = this.onExpand.bind(this);
106109
this.onNodeClick = this.onNodeClick.bind(this);
107110
this.onExpandAll = this.onExpandAll.bind(this);
@@ -132,6 +135,14 @@ class CheckboxTree extends React.Component {
132135
return newState;
133136
}
134137

138+
onContextMenu(node) {
139+
const { onContextMenu } = this.props;
140+
141+
return (event) => {
142+
onContextMenu(event, node);
143+
};
144+
}
145+
135146
onCheck(nodeInfo) {
136147
const { checkModel, noCascade, onCheck } = this.props;
137148
const { model } = this.state;
@@ -250,6 +261,13 @@ class CheckboxTree extends React.Component {
250261
return null;
251262
}
252263

264+
// Prepare node information for context menu usage
265+
const nodeContext = {
266+
...node,
267+
checked: flatNode.checkState,
268+
expanded: flatNode.expanded,
269+
};
270+
253271
return (
254272
<TreeNode
255273
key={key}
@@ -272,6 +290,7 @@ class CheckboxTree extends React.Component {
272290
value={node.value}
273291
onCheck={this.onCheck}
274292
onClick={onClick && this.onNodeClick}
293+
onContextMenu={this.onContextMenu(nodeContext)}
275294
onExpand={this.onExpand}
276295
>
277296
{children}

src/js/components/TreeNode.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class TreeNode extends React.PureComponent {
3737
title: PropTypes.string,
3838
treeId: PropTypes.string,
3939
onClick: PropTypes.func,
40+
onContextMenu: PropTypes.func,
4041
};
4142

4243
static defaultProps = {
@@ -48,6 +49,7 @@ class TreeNode extends React.PureComponent {
4849
title: null,
4950
treeId: null,
5051
onClick: null,
52+
onContextMenu: null,
5153
};
5254

5355
constructor(props) {
@@ -154,7 +156,7 @@ class TreeNode extends React.PureComponent {
154156
}
155157

156158
renderBareLabel(children) {
157-
const { onClick, title } = this.props;
159+
const { title, onClick, onContextMenu } = this.props;
158160
const clickable = onClick !== null;
159161

160162
return (
@@ -165,6 +167,7 @@ class TreeNode extends React.PureComponent {
165167
role="button"
166168
tabIndex={0}
167169
onClick={this.onClick}
170+
onContextMenu={onContextMenu}
168171
onKeyPress={this.onClick}
169172
>
170173
{children}
@@ -182,13 +185,14 @@ class TreeNode extends React.PureComponent {
182185
treeId,
183186
value,
184187
onClick,
188+
onContextMenu,
185189
} = this.props;
186190
const clickable = onClick !== null;
187191
const valueId = String(value).split(' ').join('_');
188192
const inputId = treeId ? `${treeId}-${valueId}` : null;
189193

190194
const render = [(
191-
<label key={0} htmlFor={inputId} title={title}>
195+
<label key={0} htmlFor={inputId} title={title} onContextMenu={onContextMenu}>
192196
<NativeCheckbox
193197
checked={checked === 1}
194198
disabled={disabled}
@@ -217,6 +221,7 @@ class TreeNode extends React.PureComponent {
217221
role="button"
218222
tabIndex={0}
219223
onClick={this.onClick}
224+
onContextMenu={onContextMenu}
220225
onKeyPress={this.onClick}
221226
>
222227
{children}

test/CheckboxTree.jsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,39 @@ describe('<CheckboxTree />', () => {
926926
});
927927
});
928928

929+
describe('onContextMenu', () => {
930+
it('should provide the target node\'s information when right-clicking a label', async () => {
931+
let actualNode = null;
932+
933+
render(
934+
<CheckboxTree
935+
nodes={[
936+
{
937+
value: 'jupiter',
938+
label: 'Jupiter',
939+
children: [
940+
{ value: 'io', label: 'Io' },
941+
{ value: 'europa', label: 'Europa' },
942+
],
943+
},
944+
]}
945+
onContextMenu={(event, node) => {
946+
actualNode = node;
947+
}}
948+
/>,
949+
);
950+
951+
const user = userEvent.setup();
952+
await user.pointer({
953+
target: screen.getByText('Jupiter'),
954+
keys: '[MouseRight]',
955+
});
956+
957+
assert.equal(actualNode.value, 'jupiter');
958+
assert.isFalse(actualNode.expanded);
959+
});
960+
});
961+
929962
describe('onExpand', () => {
930963
it('should toggle the expansion state of the target node', async () => {
931964
let actualExpanded = null;

0 commit comments

Comments
 (0)