@mui/x-tree-view 7.7.1 → 7.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +166 -1
  2. package/RichTreeView/RichTreeView.js +12 -5
  3. package/SimpleTreeView/SimpleTreeView.js +12 -5
  4. package/TreeItem/TreeItem.js +19 -4
  5. package/TreeItem/TreeItemContent.js +5 -2
  6. package/TreeItem/useTreeItemState.d.ts +1 -0
  7. package/TreeItem/useTreeItemState.js +21 -4
  8. package/TreeItem2/TreeItem2.d.ts +3 -3
  9. package/TreeItem2Provider/TreeItem2Provider.d.ts +0 -1
  10. package/TreeView/TreeView.js +12 -5
  11. package/hooks/useTreeItem2Utils/useTreeItem2Utils.js +16 -3
  12. package/index.js +1 -1
  13. package/internals/hooks/useInstanceEventHandler.d.ts +2 -2
  14. package/internals/models/plugin.d.ts +5 -1
  15. package/internals/models/treeView.d.ts +1 -3
  16. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +13 -1
  17. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +17 -7
  18. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +1 -2
  19. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +2 -2
  20. package/internals/plugins/useTreeViewItems/useTreeViewItems.js +10 -1
  21. package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +7 -1
  22. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +15 -5
  23. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +12 -4
  24. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +25 -16
  25. package/internals/useTreeView/useTreeViewModels.d.ts +1 -1
  26. package/internals/utils/cleanupTracking/TimerBasedCleanupTracking.d.ts +0 -1
  27. package/internals/utils/publishTreeViewEvent.d.ts +1 -1
  28. package/internals/utils/warning.d.ts +1 -1
  29. package/modern/RichTreeView/RichTreeView.js +12 -5
  30. package/modern/SimpleTreeView/SimpleTreeView.js +12 -5
  31. package/modern/TreeItem/TreeItem.js +19 -4
  32. package/modern/TreeItem/TreeItemContent.js +5 -2
  33. package/modern/TreeItem/useTreeItemState.js +21 -4
  34. package/modern/TreeView/TreeView.js +12 -5
  35. package/modern/hooks/useTreeItem2Utils/useTreeItem2Utils.js +16 -3
  36. package/modern/index.js +1 -1
  37. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +13 -1
  38. package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +1 -2
  39. package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.js +10 -1
  40. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +15 -5
  41. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +12 -4
  42. package/modern/useTreeItem2/useTreeItem2.js +18 -2
  43. package/node/RichTreeView/RichTreeView.js +12 -5
  44. package/node/SimpleTreeView/SimpleTreeView.js +12 -5
  45. package/node/TreeItem/TreeItem.js +19 -4
  46. package/node/TreeItem/TreeItemContent.js +5 -2
  47. package/node/TreeItem/useTreeItemState.js +21 -4
  48. package/node/TreeView/TreeView.js +12 -5
  49. package/node/hooks/useTreeItem2Utils/useTreeItem2Utils.js +16 -3
  50. package/node/index.js +1 -1
  51. package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +13 -1
  52. package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +1 -2
  53. package/node/internals/plugins/useTreeViewItems/useTreeViewItems.js +10 -1
  54. package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +15 -5
  55. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +12 -4
  56. package/node/useTreeItem2/useTreeItem2.js +18 -2
  57. package/package.json +3 -3
  58. package/useTreeItem2/useTreeItem2.d.ts +2 -2
  59. package/useTreeItem2/useTreeItem2.js +18 -2
  60. package/useTreeItem2/useTreeItem2.types.d.ts +3 -0
@@ -72,6 +72,8 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
72
72
  current: PropTypes.shape({
73
73
  focusItem: PropTypes.func.isRequired,
74
74
  getItem: PropTypes.func.isRequired,
75
+ getItemDOMElement: PropTypes.func.isRequired,
76
+ selectItem: PropTypes.func.isRequired,
75
77
  setItemExpansion: PropTypes.func.isRequired
76
78
  })
77
79
  }),
@@ -116,6 +118,11 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
116
118
  * Used when the item's expansion is controlled.
117
119
  */
118
120
  expandedItems: PropTypes.arrayOf(PropTypes.string),
121
+ /**
122
+ * The slot that triggers the item's expansion when clicked.
123
+ * @default 'content'
124
+ */
125
+ expansionTrigger: PropTypes.oneOf(['content', 'iconContainer']),
119
126
  /**
120
127
  * Unstable features, breaking changes might be introduced.
121
128
  * For each feature, if the flag is not explicitly set to `true`,
@@ -142,34 +149,34 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
142
149
  multiSelect: PropTypes.bool,
143
150
  /**
144
151
  * Callback fired when tree items are expanded/collapsed.
145
- * @param {React.SyntheticEvent} event The event source of the callback.
152
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
146
153
  * @param {array} itemIds The ids of the expanded items.
147
154
  */
148
155
  onExpandedItemsChange: PropTypes.func,
149
156
  /**
150
157
  * Callback fired when a tree item is expanded or collapsed.
151
- * @param {React.SyntheticEvent} event The event source of the callback.
158
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
152
159
  * @param {array} itemId The itemId of the modified item.
153
160
  * @param {array} isExpanded `true` if the item has just been expanded, `false` if it has just been collapsed.
154
161
  */
155
162
  onItemExpansionToggle: PropTypes.func,
156
163
  /**
157
164
  * Callback fired when tree items are focused.
158
- * @param {React.SyntheticEvent} event The event source of the callback **Warning**: This is a generic event not a focus event.
165
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change. **Warning**: This is a generic event not a focus event.
159
166
  * @param {string} itemId The id of the focused item.
160
167
  * @param {string} value of the focused item.
161
168
  */
162
169
  onItemFocus: PropTypes.func,
163
170
  /**
164
171
  * Callback fired when a tree item is selected or deselected.
165
- * @param {React.SyntheticEvent} event The event source of the callback.
172
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
166
173
  * @param {array} itemId The itemId of the modified item.
167
174
  * @param {array} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
168
175
  */
169
176
  onItemSelectionToggle: PropTypes.func,
170
177
  /**
171
178
  * Callback fired when tree items are selected/deselected.
172
- * @param {React.SyntheticEvent} event The event source of the callback
179
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
173
180
  * @param {string[] | string} itemIds The ids of the selected items.
174
181
  * When `multiSelect` is `true`, this is an array of strings; when false (default) a string.
175
182
  */
@@ -57,10 +57,18 @@ export const useTreeItem2Utils = ({
57
57
  if (event.shiftKey) {
58
58
  instance.expandSelectionRange(event, itemId);
59
59
  } else {
60
- instance.selectItem(event, itemId, true);
60
+ instance.selectItem({
61
+ event,
62
+ itemId,
63
+ keepExistingSelection: true
64
+ });
61
65
  }
62
66
  } else {
63
- instance.selectItem(event, itemId, false);
67
+ instance.selectItem({
68
+ event,
69
+ itemId,
70
+ shouldBeSelected: true
71
+ });
64
72
  }
65
73
  };
66
74
  const handleCheckboxSelection = event => {
@@ -68,7 +76,12 @@ export const useTreeItem2Utils = ({
68
76
  if (multiSelect && hasShift) {
69
77
  instance.expandSelectionRange(event, itemId);
70
78
  } else {
71
- instance.selectItem(event, itemId, multiSelect, event.target.checked);
79
+ instance.selectItem({
80
+ event,
81
+ itemId,
82
+ keepExistingSelection: multiSelect,
83
+ shouldBeSelected: event.target.checked
84
+ });
72
85
  }
73
86
  };
74
87
  const interactions = {
package/modern/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view v7.7.1
2
+ * @mui/x-tree-view v7.9.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -53,6 +53,12 @@ export const useTreeViewExpansion = ({
53
53
  setExpandedItems(event, newExpanded);
54
54
  }
55
55
  };
56
+ const expansionTrigger = React.useMemo(() => {
57
+ if (params.expansionTrigger) {
58
+ return params.expansionTrigger;
59
+ }
60
+ return 'content';
61
+ }, [params.expansionTrigger]);
56
62
  return {
57
63
  publicAPI: {
58
64
  setItemExpansion
@@ -63,6 +69,11 @@ export const useTreeViewExpansion = ({
63
69
  setItemExpansion,
64
70
  toggleItemExpansion,
65
71
  expandAllSiblings
72
+ },
73
+ contextValue: {
74
+ expansion: {
75
+ expansionTrigger
76
+ }
66
77
  }
67
78
  };
68
79
  };
@@ -79,5 +90,6 @@ useTreeViewExpansion.params = {
79
90
  expandedItems: true,
80
91
  defaultExpandedItems: true,
81
92
  onExpandedItemsChange: true,
82
- onItemExpansionToggle: true
93
+ onItemExpansionToggle: true,
94
+ expansionTrigger: true
83
95
  };
@@ -43,8 +43,7 @@ export const useTreeViewFocus = ({
43
43
  return itemMeta && (itemMeta.parentId == null || instance.isItemExpanded(itemMeta.parentId));
44
44
  };
45
45
  const innerFocusItem = (event, itemId) => {
46
- const itemMeta = instance.getItemMeta(itemId);
47
- const itemElement = document.getElementById(instance.getTreeItemIdAttribute(itemId, itemMeta.idAttribute));
46
+ const itemElement = instance.getItemDOMElement(itemId);
48
47
  if (itemElement) {
49
48
  itemElement.focus();
50
49
  }
@@ -92,6 +92,13 @@ export const useTreeViewItems = ({
92
92
  return state.items.itemChildrenIndexes[parentId][itemId];
93
93
  }, [instance, state.items.itemChildrenIndexes]);
94
94
  const getItemOrderedChildrenIds = React.useCallback(itemId => state.items.itemOrderedChildrenIds[itemId ?? TREE_VIEW_ROOT_PARENT_ID] ?? [], [state.items.itemOrderedChildrenIds]);
95
+ const getItemDOMElement = itemId => {
96
+ const itemMeta = instance.getItemMeta(itemId);
97
+ if (itemMeta == null) {
98
+ return null;
99
+ }
100
+ return document.getElementById(instance.getTreeItemIdAttribute(itemId, itemMeta.idAttribute));
101
+ };
95
102
  const isItemNavigable = itemId => {
96
103
  if (params.disabledItemsFocusable) {
97
104
  return true;
@@ -145,13 +152,15 @@ export const useTreeViewItems = ({
145
152
  }
146
153
  }),
147
154
  publicAPI: {
148
- getItem
155
+ getItem,
156
+ getItemDOMElement
149
157
  },
150
158
  instance: {
151
159
  getItemMeta,
152
160
  getItem,
153
161
  getItemsToRender,
154
162
  getItemIndex,
163
+ getItemDOMElement,
155
164
  getItemOrderedChildrenIds,
156
165
  isItemDisabled,
157
166
  isItemNavigable,
@@ -74,10 +74,13 @@ export const useTreeViewKeyboardNavigation = ({
74
74
  event.preventDefault();
75
75
  if (params.multiSelect && event.shiftKey) {
76
76
  instance.expandSelectionRange(event, itemId);
77
- } else if (params.multiSelect) {
78
- instance.selectItem(event, itemId, true);
79
77
  } else {
80
- instance.selectItem(event, itemId, false);
78
+ instance.selectItem({
79
+ event,
80
+ itemId,
81
+ keepExistingSelection: params.multiSelect,
82
+ shouldBeSelected: params.multiSelect ? undefined : true
83
+ });
81
84
  }
82
85
  break;
83
86
  }
@@ -92,9 +95,16 @@ export const useTreeViewKeyboardNavigation = ({
92
95
  } else if (canToggleItemSelection(itemId)) {
93
96
  if (params.multiSelect) {
94
97
  event.preventDefault();
95
- instance.selectItem(event, itemId, true);
98
+ instance.selectItem({
99
+ event,
100
+ itemId,
101
+ keepExistingSelection: true
102
+ });
96
103
  } else if (!instance.isItemSelected(itemId)) {
97
- instance.selectItem(event, itemId, false);
104
+ instance.selectItem({
105
+ event,
106
+ itemId
107
+ });
98
108
  event.preventDefault();
99
109
  }
100
110
  }
@@ -46,7 +46,12 @@ export const useTreeViewSelection = ({
46
46
  models.selectedItems.setControlledValue(newSelectedItems);
47
47
  };
48
48
  const isItemSelected = itemId => selectedItemsMap.has(itemId);
49
- const selectItem = (event, itemId, keepExistingSelection, newValue) => {
49
+ const selectItem = ({
50
+ event,
51
+ itemId,
52
+ keepExistingSelection = false,
53
+ shouldBeSelected
54
+ }) => {
50
55
  if (params.disableSelection) {
51
56
  return;
52
57
  }
@@ -54,16 +59,16 @@ export const useTreeViewSelection = ({
54
59
  if (keepExistingSelection) {
55
60
  const cleanSelectedItems = convertSelectedItemsToArray(models.selectedItems.value);
56
61
  const isSelectedBefore = instance.isItemSelected(itemId);
57
- if (isSelectedBefore && (newValue === false || newValue == null)) {
62
+ if (isSelectedBefore && (shouldBeSelected === false || shouldBeSelected == null)) {
58
63
  newSelected = cleanSelectedItems.filter(id => id !== itemId);
59
- } else if (!isSelectedBefore && (newValue === true || newValue == null)) {
64
+ } else if (!isSelectedBefore && (shouldBeSelected === true || shouldBeSelected == null)) {
60
65
  newSelected = [itemId].concat(cleanSelectedItems);
61
66
  } else {
62
67
  newSelected = cleanSelectedItems;
63
68
  }
64
69
  } else {
65
70
  // eslint-disable-next-line no-lonely-if
66
- if (newValue === false) {
71
+ if (shouldBeSelected === false || shouldBeSelected == null && instance.isItemSelected(itemId)) {
67
72
  newSelected = params.multiSelect ? [] : null;
68
73
  } else {
69
74
  newSelected = params.multiSelect ? [itemId] : itemId;
@@ -142,6 +147,9 @@ export const useTreeViewSelection = ({
142
147
  getRootProps: () => ({
143
148
  'aria-multiselectable': params.multiSelect
144
149
  }),
150
+ publicAPI: {
151
+ selectItem
152
+ },
145
153
  instance: {
146
154
  isItemSelected,
147
155
  selectItem,
@@ -13,6 +13,9 @@ export const useTreeItem2 = parameters => {
13
13
  disableSelection,
14
14
  checkboxSelection
15
15
  },
16
+ expansion: {
17
+ expansionTrigger
18
+ },
16
19
  disabledItemsFocusable,
17
20
  indentationAtItemLevel,
18
21
  instance,
@@ -69,7 +72,9 @@ export const useTreeItem2 = parameters => {
69
72
  if (event.defaultMuiPrevented || checkboxRef.current?.contains(event.target)) {
70
73
  return;
71
74
  }
72
- interactions.handleExpansion(event);
75
+ if (expansionTrigger === 'content') {
76
+ interactions.handleExpansion(event);
77
+ }
73
78
  if (!checkboxSelection) {
74
79
  interactions.handleSelection(event);
75
80
  }
@@ -95,6 +100,15 @@ export const useTreeItem2 = parameters => {
95
100
  }
96
101
  interactions.handleCheckboxSelection(event);
97
102
  };
103
+ const createIconContainerHandleClick = otherHandlers => event => {
104
+ otherHandlers.onClick?.(event);
105
+ if (event.defaultMuiPrevented) {
106
+ return;
107
+ }
108
+ if (expansionTrigger === 'iconContainer') {
109
+ interactions.handleExpansion(event);
110
+ }
111
+ };
98
112
  const getRootProps = (externalProps = {}) => {
99
113
  const externalEventHandlers = _extends({}, extractEventHandlers(parameters), extractEventHandlers(externalProps));
100
114
  let ariaSelected;
@@ -162,7 +176,9 @@ export const useTreeItem2 = parameters => {
162
176
  };
163
177
  const getIconContainerProps = (externalProps = {}) => {
164
178
  const externalEventHandlers = extractEventHandlers(externalProps);
165
- return _extends({}, externalEventHandlers, externalProps);
179
+ return _extends({}, externalEventHandlers, externalProps, {
180
+ onClick: createIconContainerHandleClick(externalEventHandlers)
181
+ });
166
182
  };
167
183
  const getGroupTransitionProps = (externalProps = {}) => {
168
184
  const externalEventHandlers = extractEventHandlers(externalProps);
@@ -146,6 +146,8 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
146
146
  current: _propTypes.default.shape({
147
147
  focusItem: _propTypes.default.func.isRequired,
148
148
  getItem: _propTypes.default.func.isRequired,
149
+ getItemDOMElement: _propTypes.default.func.isRequired,
150
+ selectItem: _propTypes.default.func.isRequired,
149
151
  setItemExpansion: _propTypes.default.func.isRequired
150
152
  })
151
153
  }),
@@ -186,6 +188,11 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
186
188
  * Used when the item's expansion is controlled.
187
189
  */
188
190
  expandedItems: _propTypes.default.arrayOf(_propTypes.default.string),
191
+ /**
192
+ * The slot that triggers the item's expansion when clicked.
193
+ * @default 'content'
194
+ */
195
+ expansionTrigger: _propTypes.default.oneOf(['content', 'iconContainer']),
189
196
  /**
190
197
  * Unstable features, breaking changes might be introduced.
191
198
  * For each feature, if the flag is not explicitly set to `true`,
@@ -238,34 +245,34 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
238
245
  multiSelect: _propTypes.default.bool,
239
246
  /**
240
247
  * Callback fired when tree items are expanded/collapsed.
241
- * @param {React.SyntheticEvent} event The event source of the callback.
248
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
242
249
  * @param {array} itemIds The ids of the expanded items.
243
250
  */
244
251
  onExpandedItemsChange: _propTypes.default.func,
245
252
  /**
246
253
  * Callback fired when a tree item is expanded or collapsed.
247
- * @param {React.SyntheticEvent} event The event source of the callback.
254
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
248
255
  * @param {array} itemId The itemId of the modified item.
249
256
  * @param {array} isExpanded `true` if the item has just been expanded, `false` if it has just been collapsed.
250
257
  */
251
258
  onItemExpansionToggle: _propTypes.default.func,
252
259
  /**
253
260
  * Callback fired when tree items are focused.
254
- * @param {React.SyntheticEvent} event The event source of the callback **Warning**: This is a generic event not a focus event.
261
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change. **Warning**: This is a generic event not a focus event.
255
262
  * @param {string} itemId The id of the focused item.
256
263
  * @param {string} value of the focused item.
257
264
  */
258
265
  onItemFocus: _propTypes.default.func,
259
266
  /**
260
267
  * Callback fired when a tree item is selected or deselected.
261
- * @param {React.SyntheticEvent} event The event source of the callback.
268
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
262
269
  * @param {array} itemId The itemId of the modified item.
263
270
  * @param {array} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
264
271
  */
265
272
  onItemSelectionToggle: _propTypes.default.func,
266
273
  /**
267
274
  * Callback fired when tree items are selected/deselected.
268
- * @param {React.SyntheticEvent} event The event source of the callback
275
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
269
276
  * @param {string[] | string} itemIds The ids of the selected items.
270
277
  * When `multiSelect` is `true`, this is an array of strings; when false (default) a string.
271
278
  */
@@ -104,6 +104,8 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
104
104
  current: _propTypes.default.shape({
105
105
  focusItem: _propTypes.default.func.isRequired,
106
106
  getItem: _propTypes.default.func.isRequired,
107
+ getItemDOMElement: _propTypes.default.func.isRequired,
108
+ selectItem: _propTypes.default.func.isRequired,
107
109
  setItemExpansion: _propTypes.default.func.isRequired
108
110
  })
109
111
  }),
@@ -148,6 +150,11 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
148
150
  * Used when the item's expansion is controlled.
149
151
  */
150
152
  expandedItems: _propTypes.default.arrayOf(_propTypes.default.string),
153
+ /**
154
+ * The slot that triggers the item's expansion when clicked.
155
+ * @default 'content'
156
+ */
157
+ expansionTrigger: _propTypes.default.oneOf(['content', 'iconContainer']),
151
158
  /**
152
159
  * Unstable features, breaking changes might be introduced.
153
160
  * For each feature, if the flag is not explicitly set to `true`,
@@ -174,34 +181,34 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
174
181
  multiSelect: _propTypes.default.bool,
175
182
  /**
176
183
  * Callback fired when tree items are expanded/collapsed.
177
- * @param {React.SyntheticEvent} event The event source of the callback.
184
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
178
185
  * @param {array} itemIds The ids of the expanded items.
179
186
  */
180
187
  onExpandedItemsChange: _propTypes.default.func,
181
188
  /**
182
189
  * Callback fired when a tree item is expanded or collapsed.
183
- * @param {React.SyntheticEvent} event The event source of the callback.
190
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
184
191
  * @param {array} itemId The itemId of the modified item.
185
192
  * @param {array} isExpanded `true` if the item has just been expanded, `false` if it has just been collapsed.
186
193
  */
187
194
  onItemExpansionToggle: _propTypes.default.func,
188
195
  /**
189
196
  * Callback fired when tree items are focused.
190
- * @param {React.SyntheticEvent} event The event source of the callback **Warning**: This is a generic event not a focus event.
197
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change. **Warning**: This is a generic event not a focus event.
191
198
  * @param {string} itemId The id of the focused item.
192
199
  * @param {string} value of the focused item.
193
200
  */
194
201
  onItemFocus: _propTypes.default.func,
195
202
  /**
196
203
  * Callback fired when a tree item is selected or deselected.
197
- * @param {React.SyntheticEvent} event The event source of the callback.
204
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
198
205
  * @param {array} itemId The itemId of the modified item.
199
206
  * @param {array} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
200
207
  */
201
208
  onItemSelectionToggle: _propTypes.default.func,
202
209
  /**
203
210
  * Callback fired when tree items are selected/deselected.
204
- * @param {React.SyntheticEvent} event The event source of the callback
211
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
205
212
  * @param {string[] | string} itemIds The ids of the selected items.
206
213
  * When `multiSelect` is `true`, this is an array of strings; when false (default) a string.
207
214
  */
@@ -25,6 +25,7 @@ var _useTreeViewContext = require("../internals/TreeViewProvider/useTreeViewCont
25
25
  var _icons = require("../icons");
26
26
  var _TreeItem2Provider = require("../TreeItem2Provider");
27
27
  var _TreeViewItemDepthContext = require("../internals/TreeViewItemDepthContext");
28
+ var _useTreeItemState = require("./useTreeItemState");
28
29
  var _jsxRuntime = require("react/jsx-runtime");
29
30
  const _excluded = ["children", "className", "slots", "slotProps", "ContentComponent", "ContentProps", "itemId", "id", "label", "onClick", "onMouseDown", "onFocus", "onBlur", "onKeyDown"],
30
31
  _excluded2 = ["ownerState"],
@@ -177,6 +178,9 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
177
178
  selection: {
178
179
  multiSelect
179
180
  },
181
+ expansion: {
182
+ expansionTrigger
183
+ },
180
184
  disabledItemsFocusable,
181
185
  indentationAtItemLevel,
182
186
  instance
@@ -202,6 +206,13 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
202
206
  onKeyDown
203
207
  } = props,
204
208
  other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
209
+ const {
210
+ expanded,
211
+ focused,
212
+ selected,
213
+ disabled,
214
+ handleExpansion
215
+ } = (0, _useTreeItemState.useTreeItemState)(itemId);
205
216
  const {
206
217
  contentRef,
207
218
  rootRef
@@ -222,10 +233,6 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
222
233
  return Boolean(reactChildren);
223
234
  };
224
235
  const expandable = isExpandable(children);
225
- const expanded = instance.isItemExpanded(itemId);
226
- const focused = instance.isItemFocused(itemId);
227
- const selected = instance.isItemSelected(itemId);
228
- const disabled = instance.isItemDisabled(itemId);
229
236
  const ownerState = (0, _extends2.default)({}, props, {
230
237
  expanded,
231
238
  focused,
@@ -249,6 +256,11 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
249
256
  } : {}),
250
257
  className: classes.groupTransition
251
258
  });
259
+ const handleIconContainerClick = event => {
260
+ if (expansionTrigger === 'iconContainer') {
261
+ handleExpansion(event);
262
+ }
263
+ };
252
264
  const ExpansionIcon = expanded ? slots.collapseIcon : slots.expandIcon;
253
265
  const _useSlotProps = (0, _utils.useSlotProps)({
254
266
  elementType: ExpansionIcon,
@@ -258,6 +270,9 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
258
270
  return (0, _extends2.default)({}, (0, _utils.resolveComponentProps)(contextIcons.slotProps.collapseIcon, tempOwnerState), (0, _utils.resolveComponentProps)(inSlotProps?.collapseIcon, tempOwnerState));
259
271
  }
260
272
  return (0, _extends2.default)({}, (0, _utils.resolveComponentProps)(contextIcons.slotProps.expandIcon, tempOwnerState), (0, _utils.resolveComponentProps)(inSlotProps?.expandIcon, tempOwnerState));
273
+ },
274
+ additionalProps: {
275
+ onClick: handleIconContainerClick
261
276
  }
262
277
  }),
263
278
  expansionIconProps = (0, _objectWithoutPropertiesLoose2.default)(_useSlotProps, _excluded2);
@@ -42,7 +42,8 @@ const TreeItemContent = exports.TreeItemContent = /*#__PURE__*/React.forwardRef(
42
42
  handleExpansion,
43
43
  handleSelection,
44
44
  handleCheckboxSelection,
45
- preventSelection
45
+ preventSelection,
46
+ expansionTrigger
46
47
  } = (0, _useTreeItemState.useTreeItemState)(itemId);
47
48
  const icon = iconProp || expansionIcon || displayIcon;
48
49
  const checkboxRef = React.useRef(null);
@@ -56,7 +57,9 @@ const TreeItemContent = exports.TreeItemContent = /*#__PURE__*/React.forwardRef(
56
57
  if (checkboxRef.current?.contains(event.target)) {
57
58
  return;
58
59
  }
59
- handleExpansion(event);
60
+ if (expansionTrigger === 'content') {
61
+ handleExpansion(event);
62
+ }
60
63
  if (!checkboxSelection) {
61
64
  handleSelection(event);
62
65
  }
@@ -12,6 +12,9 @@ function useTreeItemState(itemId) {
12
12
  multiSelect,
13
13
  checkboxSelection,
14
14
  disableSelection
15
+ },
16
+ expansion: {
17
+ expansionTrigger
15
18
  }
16
19
  } = (0, _useTreeViewContext.useTreeViewContext)();
17
20
  const expandable = instance.isItemExpandable(itemId);
@@ -42,10 +45,18 @@ function useTreeItemState(itemId) {
42
45
  if (event.shiftKey) {
43
46
  instance.expandSelectionRange(event, itemId);
44
47
  } else {
45
- instance.selectItem(event, itemId, true);
48
+ instance.selectItem({
49
+ event,
50
+ itemId,
51
+ keepExistingSelection: true
52
+ });
46
53
  }
47
54
  } else {
48
- instance.selectItem(event, itemId, false);
55
+ instance.selectItem({
56
+ event,
57
+ itemId,
58
+ shouldBeSelected: true
59
+ });
49
60
  }
50
61
  }
51
62
  };
@@ -57,7 +68,12 @@ function useTreeItemState(itemId) {
57
68
  if (multiSelect && hasShift) {
58
69
  instance.expandSelectionRange(event, itemId);
59
70
  } else {
60
- instance.selectItem(event, itemId, multiSelect, event.target.checked);
71
+ instance.selectItem({
72
+ event,
73
+ itemId,
74
+ keepExistingSelection: multiSelect,
75
+ shouldBeSelected: event.target.checked
76
+ });
61
77
  }
62
78
  };
63
79
  const preventSelection = event => {
@@ -76,6 +92,7 @@ function useTreeItemState(itemId) {
76
92
  handleExpansion,
77
93
  handleSelection,
78
94
  handleCheckboxSelection,
79
- preventSelection
95
+ preventSelection,
96
+ expansionTrigger
80
97
  };
81
98
  }
@@ -81,6 +81,8 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
81
81
  current: _propTypes.default.shape({
82
82
  focusItem: _propTypes.default.func.isRequired,
83
83
  getItem: _propTypes.default.func.isRequired,
84
+ getItemDOMElement: _propTypes.default.func.isRequired,
85
+ selectItem: _propTypes.default.func.isRequired,
84
86
  setItemExpansion: _propTypes.default.func.isRequired
85
87
  })
86
88
  }),
@@ -125,6 +127,11 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
125
127
  * Used when the item's expansion is controlled.
126
128
  */
127
129
  expandedItems: _propTypes.default.arrayOf(_propTypes.default.string),
130
+ /**
131
+ * The slot that triggers the item's expansion when clicked.
132
+ * @default 'content'
133
+ */
134
+ expansionTrigger: _propTypes.default.oneOf(['content', 'iconContainer']),
128
135
  /**
129
136
  * Unstable features, breaking changes might be introduced.
130
137
  * For each feature, if the flag is not explicitly set to `true`,
@@ -151,34 +158,34 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
151
158
  multiSelect: _propTypes.default.bool,
152
159
  /**
153
160
  * Callback fired when tree items are expanded/collapsed.
154
- * @param {React.SyntheticEvent} event The event source of the callback.
161
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
155
162
  * @param {array} itemIds The ids of the expanded items.
156
163
  */
157
164
  onExpandedItemsChange: _propTypes.default.func,
158
165
  /**
159
166
  * Callback fired when a tree item is expanded or collapsed.
160
- * @param {React.SyntheticEvent} event The event source of the callback.
167
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
161
168
  * @param {array} itemId The itemId of the modified item.
162
169
  * @param {array} isExpanded `true` if the item has just been expanded, `false` if it has just been collapsed.
163
170
  */
164
171
  onItemExpansionToggle: _propTypes.default.func,
165
172
  /**
166
173
  * Callback fired when tree items are focused.
167
- * @param {React.SyntheticEvent} event The event source of the callback **Warning**: This is a generic event not a focus event.
174
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change. **Warning**: This is a generic event not a focus event.
168
175
  * @param {string} itemId The id of the focused item.
169
176
  * @param {string} value of the focused item.
170
177
  */
171
178
  onItemFocus: _propTypes.default.func,
172
179
  /**
173
180
  * Callback fired when a tree item is selected or deselected.
174
- * @param {React.SyntheticEvent} event The event source of the callback.
181
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
175
182
  * @param {array} itemId The itemId of the modified item.
176
183
  * @param {array} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
177
184
  */
178
185
  onItemSelectionToggle: _propTypes.default.func,
179
186
  /**
180
187
  * Callback fired when tree items are selected/deselected.
181
- * @param {React.SyntheticEvent} event The event source of the callback
188
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
182
189
  * @param {string[] | string} itemIds The ids of the selected items.
183
190
  * When `multiSelect` is `true`, this is an array of strings; when false (default) a string.
184
191
  */
@@ -63,10 +63,18 @@ const useTreeItem2Utils = ({
63
63
  if (event.shiftKey) {
64
64
  instance.expandSelectionRange(event, itemId);
65
65
  } else {
66
- instance.selectItem(event, itemId, true);
66
+ instance.selectItem({
67
+ event,
68
+ itemId,
69
+ keepExistingSelection: true
70
+ });
67
71
  }
68
72
  } else {
69
- instance.selectItem(event, itemId, false);
73
+ instance.selectItem({
74
+ event,
75
+ itemId,
76
+ shouldBeSelected: true
77
+ });
70
78
  }
71
79
  };
72
80
  const handleCheckboxSelection = event => {
@@ -74,7 +82,12 @@ const useTreeItem2Utils = ({
74
82
  if (multiSelect && hasShift) {
75
83
  instance.expandSelectionRange(event, itemId);
76
84
  } else {
77
- instance.selectItem(event, itemId, multiSelect, event.target.checked);
85
+ instance.selectItem({
86
+ event,
87
+ itemId,
88
+ keepExistingSelection: multiSelect,
89
+ shouldBeSelected: event.target.checked
90
+ });
78
91
  }
79
92
  };
80
93
  const interactions = {