@mui/x-tree-view 6.17.0 → 7.0.0-alpha.7

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 (203) hide show
  1. package/CHANGELOG.md +1748 -6
  2. package/README.md +0 -1
  3. package/RichTreeView/RichTreeView.d.ts +20 -0
  4. package/RichTreeView/RichTreeView.js +324 -0
  5. package/RichTreeView/RichTreeView.types.d.ts +55 -0
  6. package/RichTreeView/RichTreeView.types.js +1 -0
  7. package/RichTreeView/index.d.ts +3 -0
  8. package/RichTreeView/index.js +3 -0
  9. package/RichTreeView/package.json +6 -0
  10. package/RichTreeView/richTreeViewClasses.d.ts +7 -0
  11. package/RichTreeView/richTreeViewClasses.js +6 -0
  12. package/SimpleTreeView/SimpleTreeView.d.ts +20 -0
  13. package/SimpleTreeView/SimpleTreeView.js +268 -0
  14. package/SimpleTreeView/SimpleTreeView.plugins.d.ts +6 -0
  15. package/SimpleTreeView/SimpleTreeView.plugins.js +5 -0
  16. package/SimpleTreeView/SimpleTreeView.types.d.ts +38 -0
  17. package/SimpleTreeView/SimpleTreeView.types.js +1 -0
  18. package/SimpleTreeView/index.d.ts +3 -0
  19. package/SimpleTreeView/index.js +3 -0
  20. package/SimpleTreeView/package.json +6 -0
  21. package/SimpleTreeView/simpleTreeViewClasses.d.ts +7 -0
  22. package/SimpleTreeView/simpleTreeViewClasses.js +6 -0
  23. package/TreeItem/TreeItem.js +44 -89
  24. package/TreeItem/TreeItem.types.d.ts +2 -1
  25. package/TreeItem/index.d.ts +2 -2
  26. package/TreeItem/index.js +2 -2
  27. package/TreeItem/useTreeItem.js +5 -5
  28. package/TreeView/TreeView.d.ts +4 -0
  29. package/TreeView/TreeView.js +80 -87
  30. package/TreeView/TreeView.types.d.ts +4 -26
  31. package/TreeView/index.d.ts +1 -1
  32. package/index.d.ts +3 -0
  33. package/index.js +5 -2
  34. package/internals/TreeViewProvider/TreeViewContext.d.ts +1 -2
  35. package/internals/TreeViewProvider/TreeViewContext.js +1 -14
  36. package/internals/TreeViewProvider/TreeViewProvider.types.d.ts +3 -3
  37. package/internals/TreeViewProvider/useTreeViewContext.js +7 -1
  38. package/internals/corePlugins/corePlugins.d.ts +1 -1
  39. package/internals/corePlugins/corePlugins.js +1 -1
  40. package/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.d.ts +0 -5
  41. package/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.js +0 -6
  42. package/internals/hooks/useLazyRef.d.ts +2 -0
  43. package/internals/hooks/useLazyRef.js +11 -0
  44. package/internals/hooks/useOnMount.d.ts +2 -0
  45. package/internals/hooks/useOnMount.js +7 -0
  46. package/internals/hooks/useTimeout.d.ts +9 -0
  47. package/internals/hooks/useTimeout.js +28 -0
  48. package/internals/models/plugin.d.ts +23 -0
  49. package/internals/models/treeView.d.ts +5 -1
  50. package/internals/plugins/defaultPlugins.d.ts +3 -2
  51. package/internals/plugins/defaultPlugins.js +2 -1
  52. package/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.js +8 -6
  53. package/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.types.d.ts +1 -6
  54. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +26 -17
  55. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +12 -5
  56. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +13 -6
  57. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +4 -1
  58. package/internals/plugins/useTreeViewId/index.d.ts +2 -0
  59. package/internals/plugins/useTreeViewId/index.js +1 -0
  60. package/internals/plugins/useTreeViewId/useTreeViewId.d.ts +3 -0
  61. package/internals/plugins/useTreeViewId/useTreeViewId.js +18 -0
  62. package/internals/plugins/useTreeViewId/useTreeViewId.types.d.ts +17 -0
  63. package/internals/plugins/useTreeViewId/useTreeViewId.types.js +1 -0
  64. package/internals/plugins/useTreeViewJSXNodes/index.d.ts +2 -0
  65. package/internals/plugins/useTreeViewJSXNodes/index.js +1 -0
  66. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.d.ts +3 -0
  67. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +114 -0
  68. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.d.ts +16 -0
  69. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.js +1 -0
  70. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +20 -9
  71. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +5 -2
  72. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +83 -18
  73. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.d.ts +48 -5
  74. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.d.ts +1 -1
  75. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +41 -28
  76. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +15 -8
  77. package/internals/useTreeView/useTreeView.js +40 -3
  78. package/internals/useTreeView/useTreeView.types.d.ts +2 -1
  79. package/internals/utils/warning.d.ts +1 -0
  80. package/internals/utils/warning.js +14 -0
  81. package/legacy/RichTreeView/RichTreeView.js +317 -0
  82. package/legacy/RichTreeView/RichTreeView.types.js +1 -0
  83. package/legacy/RichTreeView/index.js +3 -0
  84. package/legacy/RichTreeView/richTreeViewClasses.js +6 -0
  85. package/legacy/SimpleTreeView/SimpleTreeView.js +264 -0
  86. package/legacy/SimpleTreeView/SimpleTreeView.plugins.js +6 -0
  87. package/legacy/SimpleTreeView/SimpleTreeView.types.js +1 -0
  88. package/legacy/SimpleTreeView/index.js +3 -0
  89. package/legacy/SimpleTreeView/simpleTreeViewClasses.js +6 -0
  90. package/legacy/TreeItem/TreeItem.js +49 -103
  91. package/legacy/TreeItem/index.js +2 -2
  92. package/legacy/TreeItem/useTreeItem.js +5 -5
  93. package/legacy/TreeView/TreeView.js +80 -82
  94. package/legacy/index.js +5 -2
  95. package/legacy/internals/TreeViewProvider/TreeViewContext.js +1 -14
  96. package/legacy/internals/TreeViewProvider/useTreeViewContext.js +5 -1
  97. package/legacy/internals/corePlugins/corePlugins.js +1 -1
  98. package/legacy/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.js +0 -6
  99. package/legacy/internals/hooks/useLazyRef.js +11 -0
  100. package/legacy/internals/hooks/useOnMount.js +7 -0
  101. package/legacy/internals/hooks/useTimeout.js +38 -0
  102. package/legacy/internals/plugins/defaultPlugins.js +2 -1
  103. package/legacy/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.js +11 -8
  104. package/legacy/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +26 -17
  105. package/legacy/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +13 -6
  106. package/legacy/internals/plugins/useTreeViewId/index.js +1 -0
  107. package/legacy/internals/plugins/useTreeViewId/useTreeViewId.js +21 -0
  108. package/legacy/internals/plugins/useTreeViewId/useTreeViewId.types.js +1 -0
  109. package/legacy/internals/plugins/useTreeViewJSXNodes/index.js +1 -0
  110. package/legacy/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +120 -0
  111. package/legacy/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.js +1 -0
  112. package/legacy/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +20 -9
  113. package/legacy/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +89 -20
  114. package/legacy/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +45 -28
  115. package/legacy/internals/useTreeView/useTreeView.js +39 -3
  116. package/legacy/internals/utils/warning.js +15 -0
  117. package/legacy/models/index.js +1 -0
  118. package/legacy/models/items.js +1 -0
  119. package/models/index.d.ts +1 -0
  120. package/models/index.js +1 -0
  121. package/models/items.d.ts +7 -0
  122. package/models/items.js +1 -0
  123. package/models/package.json +6 -0
  124. package/modern/RichTreeView/RichTreeView.js +322 -0
  125. package/modern/RichTreeView/RichTreeView.types.js +1 -0
  126. package/modern/RichTreeView/index.js +3 -0
  127. package/modern/RichTreeView/richTreeViewClasses.js +6 -0
  128. package/modern/SimpleTreeView/SimpleTreeView.js +267 -0
  129. package/modern/SimpleTreeView/SimpleTreeView.plugins.js +5 -0
  130. package/modern/SimpleTreeView/SimpleTreeView.types.js +1 -0
  131. package/modern/SimpleTreeView/index.js +3 -0
  132. package/modern/SimpleTreeView/simpleTreeViewClasses.js +6 -0
  133. package/modern/TreeItem/TreeItem.js +44 -88
  134. package/modern/TreeItem/index.js +2 -2
  135. package/modern/TreeItem/useTreeItem.js +5 -5
  136. package/modern/TreeView/TreeView.js +80 -87
  137. package/modern/index.js +5 -2
  138. package/modern/internals/TreeViewProvider/TreeViewContext.js +1 -14
  139. package/modern/internals/TreeViewProvider/useTreeViewContext.js +7 -1
  140. package/modern/internals/corePlugins/corePlugins.js +1 -1
  141. package/modern/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.js +0 -6
  142. package/modern/internals/hooks/useLazyRef.js +11 -0
  143. package/modern/internals/hooks/useOnMount.js +7 -0
  144. package/modern/internals/hooks/useTimeout.js +28 -0
  145. package/modern/internals/plugins/defaultPlugins.js +2 -1
  146. package/modern/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.js +8 -6
  147. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +26 -17
  148. package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +12 -6
  149. package/modern/internals/plugins/useTreeViewId/index.js +1 -0
  150. package/modern/internals/plugins/useTreeViewId/useTreeViewId.js +18 -0
  151. package/modern/internals/plugins/useTreeViewId/useTreeViewId.types.js +1 -0
  152. package/modern/internals/plugins/useTreeViewJSXNodes/index.js +1 -0
  153. package/modern/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +113 -0
  154. package/modern/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.js +1 -0
  155. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +19 -9
  156. package/modern/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +82 -18
  157. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +41 -28
  158. package/modern/internals/useTreeView/useTreeView.js +40 -3
  159. package/modern/internals/utils/warning.js +14 -0
  160. package/modern/models/index.js +1 -0
  161. package/modern/models/items.js +1 -0
  162. package/node/RichTreeView/RichTreeView.js +330 -0
  163. package/node/RichTreeView/RichTreeView.types.js +5 -0
  164. package/node/RichTreeView/index.js +27 -0
  165. package/node/RichTreeView/richTreeViewClasses.js +14 -0
  166. package/node/SimpleTreeView/SimpleTreeView.js +275 -0
  167. package/node/SimpleTreeView/SimpleTreeView.plugins.js +11 -0
  168. package/node/SimpleTreeView/SimpleTreeView.types.js +5 -0
  169. package/node/SimpleTreeView/index.js +27 -0
  170. package/node/SimpleTreeView/simpleTreeViewClasses.js +14 -0
  171. package/node/TreeItem/TreeItem.js +44 -88
  172. package/node/TreeItem/index.js +11 -15
  173. package/node/TreeItem/useTreeItem.js +5 -5
  174. package/node/TreeView/TreeView.js +80 -87
  175. package/node/index.js +38 -2
  176. package/node/internals/TreeViewProvider/TreeViewContext.js +2 -15
  177. package/node/internals/TreeViewProvider/useTreeViewContext.js +7 -1
  178. package/node/internals/corePlugins/corePlugins.js +1 -1
  179. package/node/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.js +0 -6
  180. package/node/internals/hooks/useLazyRef.js +19 -0
  181. package/node/internals/hooks/useOnMount.js +15 -0
  182. package/node/internals/hooks/useTimeout.js +34 -0
  183. package/node/internals/plugins/defaultPlugins.js +2 -1
  184. package/node/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.js +8 -7
  185. package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +26 -17
  186. package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +12 -6
  187. package/node/internals/plugins/useTreeViewId/index.js +12 -0
  188. package/node/internals/plugins/useTreeViewId/useTreeViewId.js +28 -0
  189. package/node/internals/plugins/useTreeViewId/useTreeViewId.types.js +5 -0
  190. package/node/internals/plugins/useTreeViewJSXNodes/index.js +12 -0
  191. package/node/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +123 -0
  192. package/node/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.js +5 -0
  193. package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +19 -9
  194. package/node/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +82 -18
  195. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +41 -28
  196. package/node/internals/useTreeView/useTreeView.js +40 -3
  197. package/node/internals/utils/warning.js +21 -0
  198. package/node/models/index.js +16 -0
  199. package/node/models/items.js +5 -0
  200. package/package.json +8 -7
  201. package/themeAugmentation/components.d.ts +14 -4
  202. package/themeAugmentation/overrides.d.ts +8 -4
  203. package/themeAugmentation/props.d.ts +7 -3
@@ -8,8 +8,8 @@ export const useTreeViewExpansion = ({
8
8
  models
9
9
  }) => {
10
10
  const isNodeExpanded = React.useCallback(nodeId => {
11
- return Array.isArray(models.expanded.value) ? models.expanded.value.indexOf(nodeId) !== -1 : false;
12
- }, [models.expanded.value]);
11
+ return Array.isArray(models.expandedNodes.value) ? models.expandedNodes.value.indexOf(nodeId) !== -1 : false;
12
+ }, [models.expandedNodes.value]);
13
13
  const isNodeExpandable = React.useCallback(nodeId => {
14
14
  var _instance$getNode;
15
15
  return !!((_instance$getNode = instance.getNode(nodeId)) != null && _instance$getNode.expandable);
@@ -18,27 +18,36 @@ export const useTreeViewExpansion = ({
18
18
  if (nodeId == null) {
19
19
  return;
20
20
  }
21
+ const isExpandedBefore = models.expandedNodes.value.indexOf(nodeId) !== -1;
21
22
  let newExpanded;
22
- if (models.expanded.value.indexOf(nodeId) !== -1) {
23
- newExpanded = models.expanded.value.filter(id => id !== nodeId);
23
+ if (isExpandedBefore) {
24
+ newExpanded = models.expandedNodes.value.filter(id => id !== nodeId);
24
25
  } else {
25
- newExpanded = [nodeId].concat(models.expanded.value);
26
+ newExpanded = [nodeId].concat(models.expandedNodes.value);
26
27
  }
27
- if (params.onNodeToggle) {
28
- params.onNodeToggle(event, newExpanded);
28
+ if (params.onNodeExpansionToggle) {
29
+ params.onNodeExpansionToggle(event, nodeId, !isExpandedBefore);
29
30
  }
30
- models.expanded.setValue(newExpanded);
31
+ if (params.onExpandedNodesChange) {
32
+ params.onExpandedNodesChange(event, newExpanded);
33
+ }
34
+ models.expandedNodes.setValue(newExpanded);
31
35
  });
32
36
  const expandAllSiblings = (event, nodeId) => {
33
37
  const node = instance.getNode(nodeId);
34
38
  const siblings = instance.getChildrenIds(node.parentId);
35
39
  const diff = siblings.filter(child => instance.isNodeExpandable(child) && !instance.isNodeExpanded(child));
36
- const newExpanded = models.expanded.value.concat(diff);
40
+ const newExpanded = models.expandedNodes.value.concat(diff);
37
41
  if (diff.length > 0) {
38
- models.expanded.setValue(newExpanded);
39
- if (params.onNodeToggle) {
40
- params.onNodeToggle(event, newExpanded);
42
+ if (params.onNodeExpansionToggle) {
43
+ diff.forEach(newlyExpandedNodeId => {
44
+ params.onNodeExpansionToggle(event, newlyExpandedNodeId, true);
45
+ });
46
+ }
47
+ if (params.onExpandedNodesChange) {
48
+ params.onExpandedNodesChange(event, newExpanded);
41
49
  }
50
+ models.expandedNodes.setValue(newExpanded);
42
51
  }
43
52
  };
44
53
  populateInstance(instance, {
@@ -49,15 +58,15 @@ export const useTreeViewExpansion = ({
49
58
  });
50
59
  };
51
60
  useTreeViewExpansion.models = {
52
- expanded: {
53
- controlledProp: 'expanded',
54
- defaultProp: 'defaultExpanded'
61
+ expandedNodes: {
62
+ controlledProp: 'expandedNodes',
63
+ defaultProp: 'defaultExpandedNodes'
55
64
  }
56
65
  };
57
- const DEFAULT_EXPANDED = [];
66
+ const DEFAULT_EXPANDED_NODES = [];
58
67
  useTreeViewExpansion.getDefaultizedParams = params => {
59
68
  var _params$defaultExpand;
60
69
  return _extends({}, params, {
61
- defaultExpanded: (_params$defaultExpand = params.defaultExpanded) != null ? _params$defaultExpand : DEFAULT_EXPANDED
70
+ defaultExpandedNodes: (_params$defaultExpand = params.defaultExpandedNodes) != null ? _params$defaultExpand : DEFAULT_EXPANDED_NODES
62
71
  });
63
72
  };
@@ -12,21 +12,28 @@ export interface UseTreeViewExpansionParameters {
12
12
  * Expanded node ids.
13
13
  * Used when the item's expansion is controlled.
14
14
  */
15
- expanded?: string[];
15
+ expandedNodes?: string[];
16
16
  /**
17
17
  * Expanded node ids.
18
18
  * Used when the item's expansion is not controlled.
19
19
  * @default []
20
20
  */
21
- defaultExpanded?: string[];
21
+ defaultExpandedNodes?: string[];
22
22
  /**
23
23
  * Callback fired when tree items are expanded/collapsed.
24
24
  * @param {React.SyntheticEvent} event The event source of the callback.
25
25
  * @param {array} nodeIds The ids of the expanded nodes.
26
26
  */
27
- onNodeToggle?: (event: React.SyntheticEvent, nodeIds: string[]) => void;
27
+ onExpandedNodesChange?: (event: React.SyntheticEvent, nodeIds: string[]) => void;
28
+ /**
29
+ * Callback fired when a tree item is expanded or collapsed.
30
+ * @param {React.SyntheticEvent} event The event source of the callback.
31
+ * @param {array} nodeId The nodeId of the modified node.
32
+ * @param {array} isExpanded `true` if the node has just been expanded, `false` if it has just been collapsed.
33
+ */
34
+ onNodeExpansionToggle?: (event: React.SyntheticEvent, nodeId: string, isExpanded: boolean) => void;
28
35
  }
29
- export type UseTreeViewExpansionDefaultizedParameters = DefaultizedProps<UseTreeViewExpansionParameters, 'defaultExpanded'>;
30
- export type UseTreeViewExpansionSignature = TreeViewPluginSignature<UseTreeViewExpansionParameters, UseTreeViewExpansionDefaultizedParameters, UseTreeViewExpansionInstance, {}, {}, 'expanded', [
36
+ export type UseTreeViewExpansionDefaultizedParameters = DefaultizedProps<UseTreeViewExpansionParameters, 'defaultExpandedNodes'>;
37
+ export type UseTreeViewExpansionSignature = TreeViewPluginSignature<UseTreeViewExpansionParameters, UseTreeViewExpansionDefaultizedParameters, UseTreeViewExpansionInstance, {}, {}, 'expandedNodes', [
31
38
  UseTreeViewNodesSignature
32
39
  ]>;
@@ -27,9 +27,16 @@ export const useTreeViewFocus = ({
27
27
  }
28
28
  }
29
29
  });
30
+ const focusRoot = useEventCallback(() => {
31
+ var _rootRef$current;
32
+ (_rootRef$current = rootRef.current) == null || _rootRef$current.focus({
33
+ preventScroll: true
34
+ });
35
+ });
30
36
  populateInstance(instance, {
31
37
  isNodeFocused,
32
- focusNode
38
+ focusNode,
39
+ focusRoot
33
40
  });
34
41
  useInstanceEventHandler(instance, 'removeNode', ({
35
42
  id
@@ -52,10 +59,10 @@ export const useTreeViewFocus = ({
52
59
  return node && (node.parentId == null || instance.isNodeExpanded(node.parentId));
53
60
  };
54
61
  let nodeToFocusId;
55
- if (Array.isArray(models.selected.value)) {
56
- nodeToFocusId = models.selected.value.find(isNodeVisible);
57
- } else if (models.selected.value != null && isNodeVisible(models.selected.value)) {
58
- nodeToFocusId = models.selected.value;
62
+ if (Array.isArray(models.selectedNodes.value)) {
63
+ nodeToFocusId = models.selectedNodes.value.find(isNodeVisible);
64
+ } else if (models.selectedNodes.value != null && isNodeVisible(models.selectedNodes.value)) {
65
+ nodeToFocusId = models.selectedNodes.value;
59
66
  }
60
67
  if (nodeToFocusId == null) {
61
68
  nodeToFocusId = instance.getNavigableChildrenIds(null)[0];
@@ -69,7 +76,7 @@ export const useTreeViewFocus = ({
69
76
  setFocusedNodeId(null);
70
77
  };
71
78
  const focusedNode = instance.getNode(state.focusedNodeId);
72
- const activeDescendant = focusedNode ? focusedNode.idAttribute : null;
79
+ const activeDescendant = focusedNode ? instance.getTreeItemId(focusedNode.id, focusedNode.idAttribute) : null;
73
80
  return {
74
81
  getRootProps: otherHandlers => ({
75
82
  onFocus: createHandleFocus(otherHandlers),
@@ -1,11 +1,13 @@
1
1
  import * as React from 'react';
2
2
  import { TreeViewPluginSignature } from '../../models';
3
+ import { UseTreeViewIdSignature } from '../useTreeViewId/useTreeViewId.types';
3
4
  import type { UseTreeViewNodesSignature } from '../useTreeViewNodes';
4
5
  import type { UseTreeViewSelectionSignature } from '../useTreeViewSelection';
5
6
  import { UseTreeViewExpansionSignature } from '../useTreeViewExpansion';
6
7
  export interface UseTreeViewFocusInstance {
7
8
  isNodeFocused: (nodeId: string) => boolean;
8
9
  focusNode: (event: React.SyntheticEvent, nodeId: string | null) => void;
10
+ focusRoot: () => void;
9
11
  }
10
12
  export interface UseTreeViewFocusParameters {
11
13
  /**
@@ -21,7 +23,8 @@ export interface UseTreeViewFocusState {
21
23
  focusedNodeId: string | null;
22
24
  }
23
25
  export type UseTreeViewFocusSignature = TreeViewPluginSignature<UseTreeViewFocusParameters, UseTreeViewFocusParameters, UseTreeViewFocusInstance, {}, UseTreeViewFocusState, never, [
26
+ UseTreeViewIdSignature,
24
27
  UseTreeViewNodesSignature,
25
- UseTreeViewSelectionSignature<any>,
28
+ UseTreeViewSelectionSignature,
26
29
  UseTreeViewExpansionSignature
27
30
  ]>;
@@ -0,0 +1,2 @@
1
+ export { useTreeViewId } from './useTreeViewId';
2
+ export type { UseTreeViewIdSignature, UseTreeViewIdParameters, UseTreeViewIdDefaultizedParameters, } from './useTreeViewId.types';
@@ -0,0 +1 @@
1
+ export { useTreeViewId } from './useTreeViewId';
@@ -0,0 +1,3 @@
1
+ import { TreeViewPlugin } from '../../models';
2
+ import { UseTreeViewIdSignature } from './useTreeViewId.types';
3
+ export declare const useTreeViewId: TreeViewPlugin<UseTreeViewIdSignature>;
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+ import useId from '@mui/utils/useId';
3
+ import { populateInstance } from '../../useTreeView/useTreeView.utils';
4
+ export const useTreeViewId = ({
5
+ instance,
6
+ params
7
+ }) => {
8
+ const treeId = useId(params.id);
9
+ const getTreeItemId = React.useCallback((nodeId, idAttribute) => idAttribute != null ? idAttribute : `${treeId}-${nodeId}`, [treeId]);
10
+ populateInstance(instance, {
11
+ getTreeItemId
12
+ });
13
+ return {
14
+ getRootProps: () => ({
15
+ id: treeId
16
+ })
17
+ };
18
+ };
@@ -0,0 +1,17 @@
1
+ import { TreeViewPluginSignature } from '../../models';
2
+ export interface UseTreeViewIdInstance {
3
+ getTreeItemId: (nodeId: string, idAttribute: string | undefined) => string;
4
+ }
5
+ export interface UseTreeViewIdParameters {
6
+ /**
7
+ * This prop is used to help implement the accessibility logic.
8
+ * If you don't provide this prop. It falls back to a randomly generated id.
9
+ */
10
+ id?: string;
11
+ }
12
+ export type UseTreeViewIdDefaultizedParameters = UseTreeViewIdParameters;
13
+ export interface UseTreeViewIdState {
14
+ focusedNodeId: string | null;
15
+ }
16
+ export type UseTreeViewIdSignature = TreeViewPluginSignature<UseTreeViewIdParameters, UseTreeViewIdDefaultizedParameters, UseTreeViewIdInstance, {}, UseTreeViewIdState, never, [
17
+ ]>;
@@ -0,0 +1,2 @@
1
+ export { useTreeViewJSXNodes } from './useTreeViewJSXNodes';
2
+ export type { UseTreeViewJSXNodesSignature, UseTreeViewNodesParameters, UseTreeViewNodesDefaultizedParameters, } from './useTreeViewJSXNodes.types';
@@ -0,0 +1 @@
1
+ export { useTreeViewJSXNodes } from './useTreeViewJSXNodes';
@@ -0,0 +1,3 @@
1
+ import { TreeViewPlugin } from '../../models';
2
+ import { UseTreeViewJSXNodesSignature } from './useTreeViewJSXNodes.types';
3
+ export declare const useTreeViewJSXNodes: TreeViewPlugin<UseTreeViewJSXNodesSignature>;
@@ -0,0 +1,114 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import * as React from 'react';
3
+ import useEventCallback from '@mui/utils/useEventCallback';
4
+ import useForkRef from '@mui/utils/useForkRef';
5
+ import { populateInstance } from '../../useTreeView/useTreeView.utils';
6
+ import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
7
+ import { useTreeViewContext } from '../../TreeViewProvider/useTreeViewContext';
8
+ import { DescendantProvider, useDescendant } from '../../TreeViewProvider/DescendantProvider';
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ export const useTreeViewJSXNodes = ({
11
+ instance,
12
+ setState
13
+ }) => {
14
+ const insertJSXNode = useEventCallback(node => {
15
+ setState(prevState => _extends({}, prevState, {
16
+ nodeMap: _extends({}, prevState.nodeMap, {
17
+ [node.id]: node
18
+ })
19
+ }));
20
+ });
21
+ const removeJSXNode = useEventCallback(nodeId => {
22
+ setState(prevState => {
23
+ const newMap = _extends({}, prevState.nodeMap);
24
+ delete newMap[nodeId];
25
+ return _extends({}, prevState, {
26
+ nodeMap: newMap
27
+ });
28
+ });
29
+ publishTreeViewEvent(instance, 'removeNode', {
30
+ id: nodeId
31
+ });
32
+ });
33
+ const mapFirstCharFromJSX = useEventCallback((nodeId, firstChar) => {
34
+ instance.updateFirstCharMap(firstCharMap => {
35
+ firstCharMap[nodeId] = firstChar;
36
+ return firstCharMap;
37
+ });
38
+ return () => {
39
+ instance.updateFirstCharMap(firstCharMap => {
40
+ const newMap = _extends({}, firstCharMap);
41
+ delete newMap[nodeId];
42
+ return newMap;
43
+ });
44
+ };
45
+ });
46
+ populateInstance(instance, {
47
+ insertJSXNode,
48
+ removeJSXNode,
49
+ mapFirstCharFromJSX
50
+ });
51
+ };
52
+ const useTreeViewJSXNodesItemPlugin = ({
53
+ props,
54
+ ref
55
+ }) => {
56
+ const {
57
+ children,
58
+ disabled = false,
59
+ label,
60
+ nodeId,
61
+ id,
62
+ ContentProps: inContentProps
63
+ } = props;
64
+ const {
65
+ instance
66
+ } = useTreeViewContext();
67
+ const expandable = Boolean(Array.isArray(children) ? children.length : children);
68
+ const [treeItemElement, setTreeItemElement] = React.useState(null);
69
+ const contentRef = React.useRef(null);
70
+ const handleRef = useForkRef(setTreeItemElement, ref);
71
+ const descendant = React.useMemo(() => ({
72
+ element: treeItemElement,
73
+ id: nodeId
74
+ }), [nodeId, treeItemElement]);
75
+ const {
76
+ index,
77
+ parentId
78
+ } = useDescendant(descendant);
79
+ React.useEffect(() => {
80
+ // On the first render a node's index will be -1. We want to wait for the real index.
81
+ if (instance && index !== -1) {
82
+ instance.insertJSXNode({
83
+ id: nodeId,
84
+ idAttribute: id,
85
+ index,
86
+ parentId,
87
+ expandable,
88
+ disabled
89
+ });
90
+ return () => instance.removeJSXNode(nodeId);
91
+ }
92
+ return undefined;
93
+ }, [instance, parentId, index, nodeId, expandable, disabled, id]);
94
+ React.useEffect(() => {
95
+ if (instance && label) {
96
+ var _contentRef$current$t, _contentRef$current;
97
+ return instance.mapFirstCharFromJSX(nodeId, ((_contentRef$current$t = (_contentRef$current = contentRef.current) == null ? void 0 : _contentRef$current.textContent) != null ? _contentRef$current$t : '').substring(0, 1).toLowerCase());
98
+ }
99
+ return undefined;
100
+ }, [instance, nodeId, label]);
101
+ return {
102
+ props: _extends({}, props, {
103
+ ContentProps: _extends({}, inContentProps, {
104
+ ref: contentRef
105
+ })
106
+ }),
107
+ ref: handleRef,
108
+ wrapItem: item => /*#__PURE__*/_jsx(DescendantProvider, {
109
+ id: nodeId,
110
+ children: item
111
+ })
112
+ };
113
+ };
114
+ useTreeViewJSXNodes.itemPlugin = useTreeViewJSXNodesItemPlugin;
@@ -0,0 +1,16 @@
1
+ import { TreeViewNode, TreeViewPluginSignature } from '../../models';
2
+ import { UseTreeViewNodesSignature } from '../useTreeViewNodes';
3
+ import { UseTreeViewKeyboardNavigationSignature } from '../useTreeViewKeyboardNavigation';
4
+ export interface UseTreeViewNodesInstance {
5
+ insertJSXNode: (node: TreeViewNode) => void;
6
+ removeJSXNode: (nodeId: string) => void;
7
+ mapFirstCharFromJSX: (nodeId: string, firstChar: string) => () => void;
8
+ }
9
+ export interface UseTreeViewNodesParameters {
10
+ }
11
+ export interface UseTreeViewNodesDefaultizedParameters {
12
+ }
13
+ export type UseTreeViewJSXNodesSignature = TreeViewPluginSignature<UseTreeViewNodesParameters, UseTreeViewNodesDefaultizedParameters, UseTreeViewNodesInstance, {}, {}, never, [
14
+ UseTreeViewNodesSignature,
15
+ UseTreeViewKeyboardNavigationSignature
16
+ ]>;
@@ -1,4 +1,3 @@
1
- import _extends from "@babel/runtime/helpers/esm/extends";
2
1
  import * as React from 'react';
3
2
  import { useTheme } from '@mui/material/styles';
4
3
  import useEventCallback from '@mui/utils/useEventCallback';
@@ -22,16 +21,28 @@ export const useTreeViewKeyboardNavigation = ({
22
21
  const theme = useTheme();
23
22
  const isRtl = theme.direction === 'rtl';
24
23
  const firstCharMap = React.useRef({});
25
- const mapFirstChar = useEventCallback((nodeId, firstChar) => {
26
- firstCharMap.current[nodeId] = firstChar;
27
- return () => {
28
- const newMap = _extends({}, firstCharMap.current);
29
- delete newMap[nodeId];
30
- firstCharMap.current = newMap;
31
- };
24
+ const hasFirstCharMapBeenUpdatedImperatively = React.useRef(false);
25
+ const updateFirstCharMap = useEventCallback(callback => {
26
+ hasFirstCharMapBeenUpdatedImperatively.current = true;
27
+ firstCharMap.current = callback(firstCharMap.current);
32
28
  });
29
+ React.useEffect(() => {
30
+ if (hasFirstCharMapBeenUpdatedImperatively.current) {
31
+ return;
32
+ }
33
+ const newFirstCharMap = {};
34
+ const processItem = item => {
35
+ var _item$children;
36
+ const getItemId = params.getItemId;
37
+ const nodeId = getItemId ? getItemId(item) : item.id;
38
+ newFirstCharMap[nodeId] = instance.getNode(nodeId).label.substring(0, 1).toLowerCase();
39
+ (_item$children = item.children) == null || _item$children.forEach(processItem);
40
+ };
41
+ params.items.forEach(processItem);
42
+ firstCharMap.current = newFirstCharMap;
43
+ }, [params.items, params.getItemId, instance]);
33
44
  populateInstance(instance, {
34
- mapFirstChar
45
+ updateFirstCharMap
35
46
  });
36
47
  const handleNextArrow = event => {
37
48
  if (state.focusedNodeId != null && instance.isNodeExpandable(state.focusedNodeId)) {
@@ -4,11 +4,14 @@ import { UseTreeViewSelectionSignature } from '../useTreeViewSelection';
4
4
  import { UseTreeViewFocusSignature } from '../useTreeViewFocus';
5
5
  import { UseTreeViewExpansionSignature } from '../useTreeViewExpansion';
6
6
  export interface UseTreeViewKeyboardNavigationInstance {
7
- mapFirstChar: (nodeId: string, firstChar: string) => () => void;
7
+ updateFirstCharMap: (updater: (map: TreeViewFirstCharMap) => TreeViewFirstCharMap) => void;
8
8
  }
9
9
  export type UseTreeViewKeyboardNavigationSignature = TreeViewPluginSignature<{}, {}, UseTreeViewKeyboardNavigationInstance, {}, {}, never, [
10
10
  UseTreeViewNodesSignature,
11
- UseTreeViewSelectionSignature<any>,
11
+ UseTreeViewSelectionSignature,
12
12
  UseTreeViewFocusSignature,
13
13
  UseTreeViewExpansionSignature
14
14
  ]>;
15
+ export type TreeViewFirstCharMap = {
16
+ [nodeId: string]: string;
17
+ };
@@ -3,23 +3,50 @@ import * as React from 'react';
3
3
  import useEventCallback from '@mui/utils/useEventCallback';
4
4
  import { populateInstance } from '../../useTreeView/useTreeView.utils';
5
5
  import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
6
+ const updateState = ({
7
+ items,
8
+ isItemDisabled,
9
+ getItemLabel,
10
+ getItemId
11
+ }) => {
12
+ const nodeMap = {};
13
+ const processItem = (item, index, parentId) => {
14
+ var _item$children, _item$children2;
15
+ const id = getItemId ? getItemId(item) : item.id;
16
+ if (id == null) {
17
+ throw new Error(['MUI: The Tree View component requires all items to have a unique `id` property.', 'Alternatively, you can use the `getItemId` prop to specify a custom id for each item.', 'An item was provided without id in the `items` prop:', JSON.stringify(item)].join('\n'));
18
+ }
19
+ const label = getItemLabel ? getItemLabel(item) : item.label;
20
+ if (label == null) {
21
+ throw new Error(['MUI: The Tree View component requires all items to have a `label` property.', 'Alternatively, you can use the `getItemLabel` prop to specify a custom label for each item.', 'An item was provided without label in the `items` prop:', JSON.stringify(item)].join('\n'));
22
+ }
23
+ nodeMap[id] = {
24
+ id,
25
+ label,
26
+ index,
27
+ parentId,
28
+ idAttribute: id,
29
+ expandable: !!((_item$children = item.children) != null && _item$children.length),
30
+ disabled: isItemDisabled ? isItemDisabled(item) : false
31
+ };
32
+ return {
33
+ id,
34
+ children: (_item$children2 = item.children) == null ? void 0 : _item$children2.map((child, childIndex) => processItem(child, childIndex, id))
35
+ };
36
+ };
37
+ const nodeTree = items.map((item, itemIndex) => processItem(item, itemIndex, null));
38
+ return {
39
+ nodeMap,
40
+ nodeTree
41
+ };
42
+ };
6
43
  export const useTreeViewNodes = ({
7
44
  instance,
8
- params
45
+ params,
46
+ state,
47
+ setState
9
48
  }) => {
10
- const nodeMap = React.useRef({});
11
- const getNode = React.useCallback(nodeId => nodeMap.current[nodeId], []);
12
- const insertNode = React.useCallback(node => {
13
- nodeMap.current[node.id] = node;
14
- }, []);
15
- const removeNode = React.useCallback(nodeId => {
16
- const newMap = _extends({}, nodeMap.current);
17
- delete newMap[nodeId];
18
- nodeMap.current = newMap;
19
- publishTreeViewEvent(instance, 'removeNode', {
20
- id: nodeId
21
- });
22
- }, [instance]);
49
+ const getNode = React.useCallback(nodeId => state.nodeMap[nodeId], [state.nodeMap]);
23
50
  const isNodeDisabled = React.useCallback(nodeId => {
24
51
  if (nodeId == null) {
25
52
  return false;
@@ -41,7 +68,7 @@ export const useTreeViewNodes = ({
41
68
  }
42
69
  return false;
43
70
  }, [instance]);
44
- const getChildrenIds = useEventCallback(nodeId => Object.values(nodeMap.current).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
71
+ const getChildrenIds = useEventCallback(nodeId => Object.values(state.nodeMap).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
45
72
  const getNavigableChildrenIds = nodeId => {
46
73
  let childrenIds = instance.getChildrenIds(nodeId);
47
74
  if (!params.disabledItemsFocusable) {
@@ -49,12 +76,50 @@ export const useTreeViewNodes = ({
49
76
  }
50
77
  return childrenIds;
51
78
  };
79
+ React.useEffect(() => {
80
+ setState(prevState => {
81
+ const newState = updateState({
82
+ items: params.items,
83
+ isItemDisabled: params.isItemDisabled,
84
+ getItemId: params.getItemId,
85
+ getItemLabel: params.getItemLabel
86
+ });
87
+ Object.values(prevState.nodeMap).forEach(node => {
88
+ if (!newState.nodeMap[node.id]) {
89
+ publishTreeViewEvent(instance, 'removeNode', {
90
+ id: node.id
91
+ });
92
+ }
93
+ });
94
+ return _extends({}, prevState, newState);
95
+ });
96
+ }, [instance, setState, params.items, params.isItemDisabled, params.getItemId, params.getItemLabel]);
97
+ const getNodesToRender = useEventCallback(() => {
98
+ const getPropsFromNodeId = ({
99
+ id,
100
+ children
101
+ }) => {
102
+ const node = state.nodeMap[id];
103
+ return {
104
+ label: node.label,
105
+ nodeId: node.id,
106
+ id: node.idAttribute,
107
+ children: children == null ? void 0 : children.map(getPropsFromNodeId)
108
+ };
109
+ };
110
+ return state.nodeTree.map(getPropsFromNodeId);
111
+ });
52
112
  populateInstance(instance, {
53
113
  getNode,
54
- updateNode: insertNode,
55
- removeNode,
114
+ getNodesToRender,
56
115
  getChildrenIds,
57
116
  getNavigableChildrenIds,
58
117
  isNodeDisabled
59
118
  });
60
- };
119
+ };
120
+ useTreeViewNodes.getInitialState = params => updateState({
121
+ items: params.items,
122
+ isItemDisabled: params.isItemDisabled,
123
+ getItemId: params.getItemId,
124
+ getItemLabel: params.getItemLabel
125
+ });
@@ -1,20 +1,52 @@
1
1
  import { TreeViewNode, DefaultizedProps, TreeViewPluginSignature } from '../../models';
2
+ import { TreeViewItemId } from '../../../models';
3
+ interface TreeViewNodeProps {
4
+ label: string;
5
+ nodeId: string;
6
+ id: string | undefined;
7
+ children?: TreeViewNodeProps[];
8
+ }
2
9
  export interface UseTreeViewNodesInstance {
3
10
  getNode: (nodeId: string) => TreeViewNode;
4
- updateNode: (node: TreeViewNode) => void;
5
- removeNode: (nodeId: string) => void;
11
+ getNodesToRender: () => TreeViewNodeProps[];
6
12
  getChildrenIds: (nodeId: string | null) => string[];
7
13
  getNavigableChildrenIds: (nodeId: string | null) => string[];
8
14
  isNodeDisabled: (nodeId: string | null) => nodeId is string;
9
15
  }
10
- export interface UseTreeViewNodesParameters {
16
+ export interface UseTreeViewNodesParameters<R extends {}> {
11
17
  /**
12
18
  * If `true`, will allow focus on disabled items.
13
19
  * @default false
14
20
  */
15
21
  disabledItemsFocusable?: boolean;
22
+ items: readonly R[];
23
+ /**
24
+ * Used to determine if a given item should be disabled.
25
+ * @template R
26
+ * @param {R} item The item to check.
27
+ * @returns {boolean} `true` if the item should be disabled.
28
+ */
29
+ isItemDisabled?: (item: R) => boolean;
30
+ /**
31
+ * Used to determine the string label for a given item.
32
+ *
33
+ * @template R
34
+ * @param {R} item The item to check.
35
+ * @returns {string} The label of the item.
36
+ * @default `(item) => item.label`
37
+ */
38
+ getItemLabel?: (item: R) => string;
39
+ /**
40
+ * Used to determine the string label for a given item.
41
+ *
42
+ * @template R
43
+ * @param {R} item The item to check.
44
+ * @returns {string} The id of the item.
45
+ * @default `(item) => item.id`
46
+ */
47
+ getItemId?: (item: R) => TreeViewItemId;
16
48
  }
17
- export type UseTreeViewNodesDefaultizedParameters = DefaultizedProps<UseTreeViewNodesParameters, 'disabledItemsFocusable'>;
49
+ export type UseTreeViewNodesDefaultizedParameters<R extends {}> = DefaultizedProps<UseTreeViewNodesParameters<R>, 'disabledItemsFocusable'>;
18
50
  interface UseTreeViewNodesEventLookup {
19
51
  removeNode: {
20
52
  params: {
@@ -22,6 +54,17 @@ interface UseTreeViewNodesEventLookup {
22
54
  };
23
55
  };
24
56
  }
25
- export type UseTreeViewNodesSignature = TreeViewPluginSignature<UseTreeViewNodesParameters, UseTreeViewNodesDefaultizedParameters, UseTreeViewNodesInstance, UseTreeViewNodesEventLookup, {}, never, [
57
+ export interface TreeViewNodeIdAndChildren {
58
+ id: TreeViewItemId;
59
+ children?: TreeViewNodeIdAndChildren[];
60
+ }
61
+ export interface UseTreeViewNodesState {
62
+ nodeTree: TreeViewNodeIdAndChildren[];
63
+ nodeMap: TreeViewNodeMap;
64
+ }
65
+ export type UseTreeViewNodesSignature = TreeViewPluginSignature<UseTreeViewNodesParameters<any>, UseTreeViewNodesDefaultizedParameters<any>, UseTreeViewNodesInstance, UseTreeViewNodesEventLookup, UseTreeViewNodesState, never, [
26
66
  ]>;
67
+ export type TreeViewNodeMap = {
68
+ [nodeId: string]: TreeViewNode;
69
+ };
27
70
  export {};
@@ -1,3 +1,3 @@
1
1
  import { TreeViewPlugin } from '../../models';
2
2
  import { UseTreeViewSelectionSignature } from './useTreeViewSelection.types';
3
- export declare const useTreeViewSelection: TreeViewPlugin<UseTreeViewSelectionSignature<any>>;
3
+ export declare const useTreeViewSelection: TreeViewPlugin<UseTreeViewSelectionSignature>;