@mui/x-tree-view 7.8.0 → 7.10.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 +140 -0
  2. package/RichTreeView/RichTreeView.js +9 -5
  3. package/SimpleTreeView/SimpleTreeView.js +9 -5
  4. package/TreeItem/useTreeItemState.js +16 -3
  5. package/TreeView/TreeView.js +9 -5
  6. package/hooks/useTreeItem2Utils/useTreeItem2Utils.js +16 -3
  7. package/index.js +1 -1
  8. package/internals/corePlugins/corePlugins.d.ts +1 -1
  9. package/internals/corePlugins/corePlugins.js +2 -1
  10. package/internals/corePlugins/useTreeViewOptionalPlugins/index.d.ts +2 -0
  11. package/internals/corePlugins/useTreeViewOptionalPlugins/index.js +1 -0
  12. package/internals/corePlugins/useTreeViewOptionalPlugins/useTreeViewOptionalPlugins.d.ts +3 -0
  13. package/internals/corePlugins/useTreeViewOptionalPlugins/useTreeViewOptionalPlugins.js +12 -0
  14. package/internals/corePlugins/useTreeViewOptionalPlugins/useTreeViewOptionalPlugins.types.d.ts +8 -0
  15. package/internals/corePlugins/useTreeViewOptionalPlugins/useTreeViewOptionalPlugins.types.js +1 -0
  16. package/internals/models/plugin.d.ts +1 -0
  17. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +7 -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 +28 -3
  21. package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +20 -9
  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/useTreeView.js +2 -1
  26. package/internals/utils/plugins.d.ts +2 -0
  27. package/internals/utils/plugins.js +4 -0
  28. package/modern/RichTreeView/RichTreeView.js +9 -5
  29. package/modern/SimpleTreeView/SimpleTreeView.js +9 -5
  30. package/modern/TreeItem/useTreeItemState.js +16 -3
  31. package/modern/TreeView/TreeView.js +9 -5
  32. package/modern/hooks/useTreeItem2Utils/useTreeItem2Utils.js +16 -3
  33. package/modern/index.js +1 -1
  34. package/modern/internals/corePlugins/corePlugins.js +2 -1
  35. package/modern/internals/corePlugins/useTreeViewOptionalPlugins/index.js +1 -0
  36. package/modern/internals/corePlugins/useTreeViewOptionalPlugins/useTreeViewOptionalPlugins.js +12 -0
  37. package/modern/internals/corePlugins/useTreeViewOptionalPlugins/useTreeViewOptionalPlugins.types.js +1 -0
  38. package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +1 -2
  39. package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.js +28 -3
  40. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +15 -5
  41. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +12 -4
  42. package/modern/internals/useTreeView/useTreeView.js +2 -1
  43. package/modern/internals/utils/plugins.js +4 -0
  44. package/node/RichTreeView/RichTreeView.js +9 -5
  45. package/node/SimpleTreeView/SimpleTreeView.js +9 -5
  46. package/node/TreeItem/useTreeItemState.js +16 -3
  47. package/node/TreeView/TreeView.js +9 -5
  48. package/node/hooks/useTreeItem2Utils/useTreeItem2Utils.js +16 -3
  49. package/node/index.js +1 -1
  50. package/node/internals/corePlugins/corePlugins.js +2 -1
  51. package/node/internals/corePlugins/useTreeViewOptionalPlugins/index.js +12 -0
  52. package/node/internals/corePlugins/useTreeViewOptionalPlugins/useTreeViewOptionalPlugins.js +19 -0
  53. package/node/internals/corePlugins/useTreeViewOptionalPlugins/useTreeViewOptionalPlugins.types.js +5 -0
  54. package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +1 -2
  55. package/node/internals/plugins/useTreeViewItems/useTreeViewItems.js +28 -3
  56. package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +15 -5
  57. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +12 -4
  58. package/node/internals/useTreeView/useTreeView.js +2 -1
  59. package/node/internals/utils/plugins.js +11 -0
  60. package/package.json +3 -3
@@ -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,
@@ -2,47 +2,55 @@ import * as React from 'react';
2
2
  import type { DefaultizedProps, TreeViewPluginSignature } from '../../models';
3
3
  import { UseTreeViewItemsSignature } from '../useTreeViewItems';
4
4
  import { UseTreeViewExpansionSignature } from '../useTreeViewExpansion';
5
- export interface UseTreeViewSelectionInstance {
5
+ export interface UseTreeViewSelectionPublicAPI {
6
+ /**
7
+ * Select or deselect an item.
8
+ * @param {object} params The params of the method.
9
+ * @param {React.SyntheticEvent} params.event The DOM event that triggered the change.
10
+ * @param {string} params.itemId The id of the item to select or deselect.
11
+ * @param {boolean} params.keepExistingSelection If `true`, the other already selected items will remain selected, otherwise, they will be deselected. This parameter is only relevant when `multiSelect` is `true`
12
+ * @param {boolean | undefined} params.shouldBeSelected If `true` the item will be selected. If `false` the item will be deselected. If not defined, the item's new selection status will be the opposite of its current one.
13
+ */
14
+ selectItem: (params: {
15
+ event: React.SyntheticEvent;
16
+ itemId: string;
17
+ keepExistingSelection?: boolean;
18
+ shouldBeSelected?: boolean;
19
+ }) => void;
20
+ }
21
+ export interface UseTreeViewSelectionInstance extends UseTreeViewSelectionPublicAPI {
6
22
  /**
7
23
  * Check if an item is selected.
8
24
  * @param {TreeViewItemId} itemId The id of the item to check.
9
25
  * @returns {boolean} `true` if the item is selected, `false` otherwise.
10
26
  */
11
27
  isItemSelected: (itemId: string) => boolean;
12
- /**
13
- * Select or deselect an item.
14
- * @param {React.SyntheticEvent} event The event source of the callback.
15
- * @param {string} itemId The id of the item to select or deselect.
16
- * @param {boolean} keepExistingSelection If `true`, don't remove the other selected items.
17
- * @param {boolean | undefined} newValue The new selection status of the item. If not defined, the new state will be the opposite of the current state.
18
- */
19
- selectItem: (event: React.SyntheticEvent, itemId: string, keepExistingSelection: boolean, newValue?: boolean) => void;
20
28
  /**
21
29
  * Select all the navigable items in the tree.
22
- * @param {React.SyntheticEvent} event The event source of the callback.
30
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
23
31
  */
24
32
  selectAllNavigableItems: (event: React.SyntheticEvent) => void;
25
33
  /**
26
34
  * Expand the current selection range up to the given item.
27
- * @param {React.SyntheticEvent} event The event source of the callback.
35
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
28
36
  * @param {string} itemId The id of the item to expand the selection to.
29
37
  */
30
38
  expandSelectionRange: (event: React.SyntheticEvent, itemId: string) => void;
31
39
  /**
32
40
  * Expand the current selection range from the first navigable item to the given item.
33
- * @param {React.SyntheticEvent} event The event source of the callback.
41
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
34
42
  * @param {string} itemId The id of the item up to which the selection range should be expanded.
35
43
  */
36
44
  selectRangeFromStartToItem: (event: React.SyntheticEvent, itemId: string) => void;
37
45
  /**
38
46
  * Expand the current selection range from the given item to the last navigable item.
39
- * @param {React.SyntheticEvent} event The event source of the callback.
47
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
40
48
  * @param {string} itemId The id of the item from which the selection range should be expanded.
41
49
  */
42
50
  selectRangeFromItemToEnd: (event: React.SyntheticEvent, itemId: string) => void;
43
51
  /**
44
52
  * Update the selection when navigating with ArrowUp / ArrowDown keys.
45
- * @param {React.SyntheticEvent} event The event source of the callback.
53
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
46
54
  * @param {string} currentItemId The id of the active item before the keyboard navigation.
47
55
  * @param {string} nextItemId The id of the active item after the keyboard navigation.
48
56
  */
@@ -78,14 +86,14 @@ export interface UseTreeViewSelectionParameters<Multiple extends boolean | undef
78
86
  checkboxSelection?: boolean;
79
87
  /**
80
88
  * Callback fired when tree items are selected/deselected.
81
- * @param {React.SyntheticEvent} event The event source of the callback
89
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
82
90
  * @param {string[] | string} itemIds The ids of the selected items.
83
91
  * When `multiSelect` is `true`, this is an array of strings; when false (default) a string.
84
92
  */
85
93
  onSelectedItemsChange?: (event: React.SyntheticEvent, itemIds: TreeViewSelectionValue<Multiple>) => void;
86
94
  /**
87
95
  * Callback fired when a tree item is selected or deselected.
88
- * @param {React.SyntheticEvent} event The event source of the callback.
96
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
89
97
  * @param {array} itemId The itemId of the modified item.
90
98
  * @param {array} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
91
99
  */
@@ -99,6 +107,7 @@ export type UseTreeViewSelectionSignature = TreeViewPluginSignature<{
99
107
  params: UseTreeViewSelectionParameters<any>;
100
108
  defaultizedParams: UseTreeViewSelectionDefaultizedParameters<any>;
101
109
  instance: UseTreeViewSelectionInstance;
110
+ publicAPI: UseTreeViewSelectionPublicAPI;
102
111
  contextValue: UseTreeViewSelectionContextValue;
103
112
  modelNames: 'selectedItems';
104
113
  dependencies: [
@@ -119,7 +119,8 @@ export const useTreeView = ({
119
119
  state,
120
120
  setState,
121
121
  rootRef: innerRootRef,
122
- models
122
+ models,
123
+ plugins
123
124
  });
124
125
  if (pluginResponse.getRootProps) {
125
126
  rootPropsGetters.push(pluginResponse.getRootProps);
@@ -0,0 +1,2 @@
1
+ import { TreeViewAnyPluginSignature, TreeViewInstance, TreeViewPlugin } from '../models';
2
+ export declare const hasPlugin: <TSignature extends TreeViewAnyPluginSignature, TInstance extends TreeViewInstance<[], [TSignature]>>(instance: TInstance, plugin: TreeViewPlugin<TSignature>) => instance is Omit<TInstance, keyof TSignature["instance"]> & TSignature["instance"];
@@ -0,0 +1,4 @@
1
+ export const hasPlugin = (instance, plugin) => {
2
+ const plugins = instance.getAvailablePlugins();
3
+ return plugins.has(plugin);
4
+ };
@@ -137,6 +137,10 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
137
137
  current: PropTypes.shape({
138
138
  focusItem: PropTypes.func.isRequired,
139
139
  getItem: PropTypes.func.isRequired,
140
+ getItemDOMElement: PropTypes.func.isRequired,
141
+ getItemOrderedChildrenIds: PropTypes.func.isRequired,
142
+ getItemTree: PropTypes.func.isRequired,
143
+ selectItem: PropTypes.func.isRequired,
140
144
  setItemExpansion: PropTypes.func.isRequired
141
145
  })
142
146
  }),
@@ -234,34 +238,34 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
234
238
  multiSelect: PropTypes.bool,
235
239
  /**
236
240
  * Callback fired when tree items are expanded/collapsed.
237
- * @param {React.SyntheticEvent} event The event source of the callback.
241
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
238
242
  * @param {array} itemIds The ids of the expanded items.
239
243
  */
240
244
  onExpandedItemsChange: PropTypes.func,
241
245
  /**
242
246
  * Callback fired when a tree item is expanded or collapsed.
243
- * @param {React.SyntheticEvent} event The event source of the callback.
247
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
244
248
  * @param {array} itemId The itemId of the modified item.
245
249
  * @param {array} isExpanded `true` if the item has just been expanded, `false` if it has just been collapsed.
246
250
  */
247
251
  onItemExpansionToggle: PropTypes.func,
248
252
  /**
249
253
  * Callback fired when tree items are focused.
250
- * @param {React.SyntheticEvent} event The event source of the callback **Warning**: This is a generic event not a focus event.
254
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change. **Warning**: This is a generic event not a focus event.
251
255
  * @param {string} itemId The id of the focused item.
252
256
  * @param {string} value of the focused item.
253
257
  */
254
258
  onItemFocus: PropTypes.func,
255
259
  /**
256
260
  * Callback fired when a tree item is selected or deselected.
257
- * @param {React.SyntheticEvent} event The event source of the callback.
261
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
258
262
  * @param {array} itemId The itemId of the modified item.
259
263
  * @param {array} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
260
264
  */
261
265
  onItemSelectionToggle: PropTypes.func,
262
266
  /**
263
267
  * Callback fired when tree items are selected/deselected.
264
- * @param {React.SyntheticEvent} event The event source of the callback
268
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
265
269
  * @param {string[] | string} itemIds The ids of the selected items.
266
270
  * When `multiSelect` is `true`, this is an array of strings; when false (default) a string.
267
271
  */
@@ -95,6 +95,10 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
95
95
  current: PropTypes.shape({
96
96
  focusItem: PropTypes.func.isRequired,
97
97
  getItem: PropTypes.func.isRequired,
98
+ getItemDOMElement: PropTypes.func.isRequired,
99
+ getItemOrderedChildrenIds: PropTypes.func.isRequired,
100
+ getItemTree: PropTypes.func.isRequired,
101
+ selectItem: PropTypes.func.isRequired,
98
102
  setItemExpansion: PropTypes.func.isRequired
99
103
  })
100
104
  }),
@@ -170,34 +174,34 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
170
174
  multiSelect: PropTypes.bool,
171
175
  /**
172
176
  * Callback fired when tree items are expanded/collapsed.
173
- * @param {React.SyntheticEvent} event The event source of the callback.
177
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
174
178
  * @param {array} itemIds The ids of the expanded items.
175
179
  */
176
180
  onExpandedItemsChange: PropTypes.func,
177
181
  /**
178
182
  * Callback fired when a tree item is expanded or collapsed.
179
- * @param {React.SyntheticEvent} event The event source of the callback.
183
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
180
184
  * @param {array} itemId The itemId of the modified item.
181
185
  * @param {array} isExpanded `true` if the item has just been expanded, `false` if it has just been collapsed.
182
186
  */
183
187
  onItemExpansionToggle: PropTypes.func,
184
188
  /**
185
189
  * Callback fired when tree items are focused.
186
- * @param {React.SyntheticEvent} event The event source of the callback **Warning**: This is a generic event not a focus event.
190
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change. **Warning**: This is a generic event not a focus event.
187
191
  * @param {string} itemId The id of the focused item.
188
192
  * @param {string} value of the focused item.
189
193
  */
190
194
  onItemFocus: PropTypes.func,
191
195
  /**
192
196
  * Callback fired when a tree item is selected or deselected.
193
- * @param {React.SyntheticEvent} event The event source of the callback.
197
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
194
198
  * @param {array} itemId The itemId of the modified item.
195
199
  * @param {array} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
196
200
  */
197
201
  onItemSelectionToggle: PropTypes.func,
198
202
  /**
199
203
  * Callback fired when tree items are selected/deselected.
200
- * @param {React.SyntheticEvent} event The event source of the callback
204
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
201
205
  * @param {string[] | string} itemIds The ids of the selected items.
202
206
  * When `multiSelect` is `true`, this is an array of strings; when false (default) a string.
203
207
  */
@@ -39,10 +39,18 @@ export function useTreeItemState(itemId) {
39
39
  if (event.shiftKey) {
40
40
  instance.expandSelectionRange(event, itemId);
41
41
  } else {
42
- instance.selectItem(event, itemId, true);
42
+ instance.selectItem({
43
+ event,
44
+ itemId,
45
+ keepExistingSelection: true
46
+ });
43
47
  }
44
48
  } else {
45
- instance.selectItem(event, itemId, false);
49
+ instance.selectItem({
50
+ event,
51
+ itemId,
52
+ shouldBeSelected: true
53
+ });
46
54
  }
47
55
  }
48
56
  };
@@ -54,7 +62,12 @@ export function useTreeItemState(itemId) {
54
62
  if (multiSelect && hasShift) {
55
63
  instance.expandSelectionRange(event, itemId);
56
64
  } else {
57
- instance.selectItem(event, itemId, multiSelect, event.target.checked);
65
+ instance.selectItem({
66
+ event,
67
+ itemId,
68
+ keepExistingSelection: multiSelect,
69
+ shouldBeSelected: event.target.checked
70
+ });
58
71
  }
59
72
  };
60
73
  const preventSelection = event => {
@@ -72,6 +72,10 @@ 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
+ getItemOrderedChildrenIds: PropTypes.func.isRequired,
77
+ getItemTree: PropTypes.func.isRequired,
78
+ selectItem: PropTypes.func.isRequired,
75
79
  setItemExpansion: PropTypes.func.isRequired
76
80
  })
77
81
  }),
@@ -147,34 +151,34 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
147
151
  multiSelect: PropTypes.bool,
148
152
  /**
149
153
  * Callback fired when tree items are expanded/collapsed.
150
- * @param {React.SyntheticEvent} event The event source of the callback.
154
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
151
155
  * @param {array} itemIds The ids of the expanded items.
152
156
  */
153
157
  onExpandedItemsChange: PropTypes.func,
154
158
  /**
155
159
  * Callback fired when a tree item is expanded or collapsed.
156
- * @param {React.SyntheticEvent} event The event source of the callback.
160
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
157
161
  * @param {array} itemId The itemId of the modified item.
158
162
  * @param {array} isExpanded `true` if the item has just been expanded, `false` if it has just been collapsed.
159
163
  */
160
164
  onItemExpansionToggle: PropTypes.func,
161
165
  /**
162
166
  * Callback fired when tree items are focused.
163
- * @param {React.SyntheticEvent} event The event source of the callback **Warning**: This is a generic event not a focus event.
167
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change. **Warning**: This is a generic event not a focus event.
164
168
  * @param {string} itemId The id of the focused item.
165
169
  * @param {string} value of the focused item.
166
170
  */
167
171
  onItemFocus: PropTypes.func,
168
172
  /**
169
173
  * Callback fired when a tree item is selected or deselected.
170
- * @param {React.SyntheticEvent} event The event source of the callback.
174
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
171
175
  * @param {array} itemId The itemId of the modified item.
172
176
  * @param {array} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
173
177
  */
174
178
  onItemSelectionToggle: PropTypes.func,
175
179
  /**
176
180
  * Callback fired when tree items are selected/deselected.
177
- * @param {React.SyntheticEvent} event The event source of the callback
181
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change.
178
182
  * @param {string[] | string} itemIds The ids of the selected items.
179
183
  * When `multiSelect` is `true`, this is an array of strings; when false (default) a string.
180
184
  */
@@ -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.8.0
2
+ * @mui/x-tree-view v7.10.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -1,7 +1,8 @@
1
1
  import { useTreeViewInstanceEvents } from './useTreeViewInstanceEvents';
2
+ import { useTreeViewOptionalPlugins } from './useTreeViewOptionalPlugins';
2
3
  import { useTreeViewId } from './useTreeViewId';
3
4
  /**
4
5
  * Internal plugins that create the tools used by the other plugins.
5
6
  * These plugins are used by the tree view components.
6
7
  */
7
- export const TREE_VIEW_CORE_PLUGINS = [useTreeViewInstanceEvents, useTreeViewId];
8
+ export const TREE_VIEW_CORE_PLUGINS = [useTreeViewInstanceEvents, useTreeViewOptionalPlugins, useTreeViewId];
@@ -0,0 +1 @@
1
+ export { useTreeViewOptionalPlugins } from './useTreeViewOptionalPlugins';
@@ -0,0 +1,12 @@
1
+ export const useTreeViewOptionalPlugins = ({
2
+ plugins
3
+ }) => {
4
+ const pluginSet = new Set(plugins);
5
+ const getAvailablePlugins = () => pluginSet;
6
+ return {
7
+ instance: {
8
+ getAvailablePlugins
9
+ }
10
+ };
11
+ };
12
+ useTreeViewOptionalPlugins.params = {};
@@ -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
  }
@@ -1,4 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
+ const _excluded = ["children"];
2
4
  import * as React from 'react';
3
5
  import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
4
6
  import { buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from './useTreeViewItems.utils';
@@ -37,7 +39,6 @@ const updateItemsState = ({
37
39
  depth
38
40
  };
39
41
  itemMap[id] = item;
40
- itemOrderedChildrenIds[id] = [];
41
42
  const parentIdWithDefault = parentId ?? TREE_VIEW_ROOT_PARENT_ID;
42
43
  if (!itemOrderedChildrenIds[parentIdWithDefault]) {
43
44
  itemOrderedChildrenIds[parentIdWithDefault] = [];
@@ -66,6 +67,18 @@ export const useTreeViewItems = ({
66
67
  }) => {
67
68
  const getItemMeta = React.useCallback(itemId => state.items.itemMetaMap[itemId], [state.items.itemMetaMap]);
68
69
  const getItem = React.useCallback(itemId => state.items.itemMap[itemId], [state.items.itemMap]);
70
+ const getItemTree = React.useCallback(() => {
71
+ const getItemFromItemId = id => {
72
+ const _state$items$itemMap$ = state.items.itemMap[id],
73
+ item = _objectWithoutPropertiesLoose(_state$items$itemMap$, _excluded);
74
+ const newChildren = state.items.itemOrderedChildrenIds[id];
75
+ if (newChildren) {
76
+ item.children = newChildren.map(getItemFromItemId);
77
+ }
78
+ return item;
79
+ };
80
+ return state.items.itemOrderedChildrenIds[TREE_VIEW_ROOT_PARENT_ID].map(getItemFromItemId);
81
+ }, [state.items.itemMap, state.items.itemOrderedChildrenIds]);
69
82
  const isItemDisabled = React.useCallback(itemId => {
70
83
  if (itemId == null) {
71
84
  return false;
@@ -92,6 +105,13 @@ export const useTreeViewItems = ({
92
105
  return state.items.itemChildrenIndexes[parentId][itemId];
93
106
  }, [instance, state.items.itemChildrenIndexes]);
94
107
  const getItemOrderedChildrenIds = React.useCallback(itemId => state.items.itemOrderedChildrenIds[itemId ?? TREE_VIEW_ROOT_PARENT_ID] ?? [], [state.items.itemOrderedChildrenIds]);
108
+ const getItemDOMElement = itemId => {
109
+ const itemMeta = instance.getItemMeta(itemId);
110
+ if (itemMeta == null) {
111
+ return null;
112
+ }
113
+ return document.getElementById(instance.getTreeItemIdAttribute(itemId, itemMeta.idAttribute));
114
+ };
95
115
  const isItemNavigable = itemId => {
96
116
  if (params.disabledItemsFocusable) {
97
117
  return true;
@@ -133,7 +153,7 @@ export const useTreeViewItems = ({
133
153
  label: item.label,
134
154
  itemId: item.id,
135
155
  id: item.idAttribute,
136
- children: state.items.itemOrderedChildrenIds[id].map(getPropsFromItemId)
156
+ children: state.items.itemOrderedChildrenIds[id]?.map(getPropsFromItemId)
137
157
  };
138
158
  };
139
159
  return state.items.itemOrderedChildrenIds[TREE_VIEW_ROOT_PARENT_ID].map(getPropsFromItemId);
@@ -145,13 +165,18 @@ export const useTreeViewItems = ({
145
165
  }
146
166
  }),
147
167
  publicAPI: {
148
- getItem
168
+ getItem,
169
+ getItemDOMElement,
170
+ getItemTree,
171
+ getItemOrderedChildrenIds
149
172
  },
150
173
  instance: {
151
174
  getItemMeta,
152
175
  getItem,
176
+ getItemTree,
153
177
  getItemsToRender,
154
178
  getItemIndex,
179
+ getItemDOMElement,
155
180
  getItemOrderedChildrenIds,
156
181
  isItemDisabled,
157
182
  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,
@@ -119,7 +119,8 @@ export const useTreeView = ({
119
119
  state,
120
120
  setState,
121
121
  rootRef: innerRootRef,
122
- models
122
+ models,
123
+ plugins
123
124
  });
124
125
  if (pluginResponse.getRootProps) {
125
126
  rootPropsGetters.push(pluginResponse.getRootProps);
@@ -0,0 +1,4 @@
1
+ export const hasPlugin = (instance, plugin) => {
2
+ const plugins = instance.getAvailablePlugins();
3
+ return plugins.has(plugin);
4
+ };