@mui/x-tree-view 7.0.0-beta.4 → 7.0.0-beta.6

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 (69) hide show
  1. package/CHANGELOG.md +271 -61
  2. package/RichTreeView/RichTreeView.js +9 -0
  3. package/RichTreeView/RichTreeView.types.d.ts +7 -1
  4. package/SimpleTreeView/SimpleTreeView.js +9 -0
  5. package/SimpleTreeView/SimpleTreeView.types.d.ts +7 -1
  6. package/TreeItem/TreeItem.js +24 -28
  7. package/TreeItem/TreeItem.types.d.ts +7 -11
  8. package/TreeItem/treeItemClasses.d.ts +1 -1
  9. package/TreeItem/treeItemClasses.js +1 -1
  10. package/TreeView/TreeView.js +9 -0
  11. package/hooks/index.d.ts +1 -0
  12. package/hooks/index.js +1 -0
  13. package/hooks/package.json +6 -0
  14. package/hooks/useTreeViewApiRef.d.ts +6 -0
  15. package/hooks/useTreeViewApiRef.js +5 -0
  16. package/index.d.ts +1 -0
  17. package/index.js +3 -2
  18. package/internals/hooks/useTimeout.d.ts +5 -3
  19. package/internals/hooks/useTimeout.js +13 -5
  20. package/internals/models/helpers.d.ts +2 -0
  21. package/internals/models/plugin.d.ts +12 -0
  22. package/internals/models/treeView.d.ts +1 -0
  23. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +40 -22
  24. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +4 -0
  25. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +20 -6
  26. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +29 -16
  27. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.d.ts +16 -6
  28. package/internals/useTreeView/useTreeView.d.ts +2 -0
  29. package/internals/useTreeView/useTreeView.js +12 -0
  30. package/internals/useTreeView/useTreeView.types.d.ts +2 -1
  31. package/internals/useTreeView/useTreeView.utils.d.ts +2 -1
  32. package/internals/useTreeView/useTreeView.utils.js +3 -0
  33. package/internals/utils/extractPluginParamsFromProps.d.ts +3 -2
  34. package/internals/utils/extractPluginParamsFromProps.js +5 -3
  35. package/internals/utils/utils.d.ts +1 -0
  36. package/internals/utils/utils.js +10 -0
  37. package/modern/RichTreeView/RichTreeView.js +9 -0
  38. package/modern/SimpleTreeView/SimpleTreeView.js +9 -0
  39. package/modern/TreeItem/TreeItem.js +23 -27
  40. package/modern/TreeItem/treeItemClasses.js +1 -1
  41. package/modern/TreeView/TreeView.js +9 -0
  42. package/modern/hooks/index.js +1 -0
  43. package/modern/hooks/useTreeViewApiRef.js +5 -0
  44. package/modern/index.js +3 -2
  45. package/modern/internals/hooks/useTimeout.js +13 -5
  46. package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +40 -22
  47. package/modern/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +20 -6
  48. package/modern/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +29 -16
  49. package/modern/internals/useTreeView/useTreeView.js +12 -0
  50. package/modern/internals/useTreeView/useTreeView.utils.js +3 -0
  51. package/modern/internals/utils/extractPluginParamsFromProps.js +5 -3
  52. package/modern/internals/utils/utils.js +10 -0
  53. package/node/RichTreeView/RichTreeView.js +9 -0
  54. package/node/SimpleTreeView/SimpleTreeView.js +9 -0
  55. package/node/TreeItem/TreeItem.js +23 -27
  56. package/node/TreeItem/treeItemClasses.js +1 -1
  57. package/node/TreeView/TreeView.js +9 -0
  58. package/node/hooks/index.js +12 -0
  59. package/node/hooks/useTreeViewApiRef.js +14 -0
  60. package/node/index.js +13 -1
  61. package/node/internals/hooks/useTimeout.js +13 -4
  62. package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +39 -21
  63. package/node/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +20 -6
  64. package/node/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +28 -15
  65. package/node/internals/useTreeView/useTreeView.js +13 -0
  66. package/node/internals/useTreeView/useTreeView.utils.js +6 -2
  67. package/node/internals/utils/extractPluginParamsFromProps.js +5 -3
  68. package/node/internals/utils/utils.js +17 -0
  69. package/package.json +2 -2
@@ -13,22 +13,36 @@ export const useTreeViewJSXNodes = ({
13
13
  }) => {
14
14
  const insertJSXNode = useEventCallback(node => {
15
15
  setState(prevState => {
16
- if (prevState.nodeMap[node.id] != null) {
16
+ if (prevState.nodes.nodeMap[node.id] != null) {
17
17
  throw new Error(['MUI X: 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.', `Tow items were provided with the same id in the \`items\` prop: "${node.id}"`].join('\n'));
18
18
  }
19
19
  return _extends({}, prevState, {
20
- nodeMap: _extends({}, prevState.nodeMap, {
21
- [node.id]: node
20
+ nodes: _extends({}, prevState.nodes, {
21
+ nodeMap: _extends({}, prevState.nodes.nodeMap, {
22
+ [node.id]: node
23
+ }),
24
+ // For `SimpleTreeView`, we don't have a proper `item` object, so we create a very basic one.
25
+ itemMap: _extends({}, prevState.nodes.itemMap, {
26
+ [node.id]: {
27
+ id: node.id,
28
+ label: node.label
29
+ }
30
+ })
22
31
  })
23
32
  });
24
33
  });
25
34
  });
26
35
  const removeJSXNode = useEventCallback(nodeId => {
27
36
  setState(prevState => {
28
- const newMap = _extends({}, prevState.nodeMap);
29
- delete newMap[nodeId];
37
+ const newNodeMap = _extends({}, prevState.nodes.nodeMap);
38
+ const newItemMap = _extends({}, prevState.nodes.itemMap);
39
+ delete newNodeMap[nodeId];
40
+ delete newItemMap[nodeId];
30
41
  return _extends({}, prevState, {
31
- nodeMap: newMap
42
+ nodes: _extends({}, prevState.nodes, {
43
+ nodeMap: newNodeMap,
44
+ itemMap: newItemMap
45
+ })
32
46
  });
33
47
  });
34
48
  publishTreeViewEvent(instance, 'removeNode', {
@@ -1,15 +1,16 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import useEventCallback from '@mui/utils/useEventCallback';
4
- import { populateInstance } from '../../useTreeView/useTreeView.utils';
4
+ import { populateInstance, populatePublicAPI } from '../../useTreeView/useTreeView.utils';
5
5
  import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
6
- const updateState = ({
6
+ const updateNodesState = ({
7
7
  items,
8
8
  isItemDisabled,
9
9
  getItemLabel,
10
10
  getItemId
11
11
  }) => {
12
12
  const nodeMap = {};
13
+ const itemMap = {};
13
14
  const processItem = (item, index, parentId) => {
14
15
  const id = getItemId ? getItemId(item) : item.id;
15
16
  if (id == null) {
@@ -27,10 +28,11 @@ const updateState = ({
27
28
  label,
28
29
  index,
29
30
  parentId,
30
- idAttribute: id,
31
+ idAttribute: undefined,
31
32
  expandable: !!item.children?.length,
32
33
  disabled: isItemDisabled ? isItemDisabled(item) : false
33
34
  };
35
+ itemMap[id] = item;
34
36
  return {
35
37
  id,
36
38
  children: item.children?.map((child, childIndex) => processItem(child, childIndex, id))
@@ -39,16 +41,19 @@ const updateState = ({
39
41
  const nodeTree = items.map((item, itemIndex) => processItem(item, itemIndex, null));
40
42
  return {
41
43
  nodeMap,
42
- nodeTree
44
+ nodeTree,
45
+ itemMap
43
46
  };
44
47
  };
45
48
  export const useTreeViewNodes = ({
46
49
  instance,
50
+ publicAPI,
47
51
  params,
48
52
  state,
49
53
  setState
50
54
  }) => {
51
- const getNode = React.useCallback(nodeId => state.nodeMap[nodeId], [state.nodeMap]);
55
+ const getNode = React.useCallback(nodeId => state.nodes.nodeMap[nodeId], [state.nodes.nodeMap]);
56
+ const getItem = React.useCallback(nodeId => state.nodes.itemMap[nodeId], [state.nodes.itemMap]);
52
57
  const isNodeDisabled = React.useCallback(nodeId => {
53
58
  if (nodeId == null) {
54
59
  return false;
@@ -70,7 +75,7 @@ export const useTreeViewNodes = ({
70
75
  }
71
76
  return false;
72
77
  }, [instance]);
73
- const getChildrenIds = useEventCallback(nodeId => Object.values(state.nodeMap).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
78
+ const getChildrenIds = useEventCallback(nodeId => Object.values(state.nodes.nodeMap).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
74
79
  const getNavigableChildrenIds = nodeId => {
75
80
  let childrenIds = instance.getChildrenIds(nodeId);
76
81
  if (!params.disabledItemsFocusable) {
@@ -80,20 +85,22 @@ export const useTreeViewNodes = ({
80
85
  };
81
86
  React.useEffect(() => {
82
87
  setState(prevState => {
83
- const newState = updateState({
88
+ const newState = updateNodesState({
84
89
  items: params.items,
85
90
  isItemDisabled: params.isItemDisabled,
86
91
  getItemId: params.getItemId,
87
92
  getItemLabel: params.getItemLabel
88
93
  });
89
- Object.values(prevState.nodeMap).forEach(node => {
94
+ Object.values(prevState.nodes.nodeMap).forEach(node => {
90
95
  if (!newState.nodeMap[node.id]) {
91
96
  publishTreeViewEvent(instance, 'removeNode', {
92
97
  id: node.id
93
98
  });
94
99
  }
95
100
  });
96
- return _extends({}, prevState, newState);
101
+ return _extends({}, prevState, {
102
+ nodes: newState
103
+ });
97
104
  });
98
105
  }, [instance, setState, params.items, params.isItemDisabled, params.getItemId, params.getItemLabel]);
99
106
  const getNodesToRender = useEventCallback(() => {
@@ -101,7 +108,7 @@ export const useTreeViewNodes = ({
101
108
  id,
102
109
  children
103
110
  }) => {
104
- const node = state.nodeMap[id];
111
+ const node = state.nodes.nodeMap[id];
105
112
  return {
106
113
  label: node.label,
107
114
  nodeId: node.id,
@@ -109,26 +116,32 @@ export const useTreeViewNodes = ({
109
116
  children: children?.map(getPropsFromNodeId)
110
117
  };
111
118
  };
112
- return state.nodeTree.map(getPropsFromNodeId);
119
+ return state.nodes.nodeTree.map(getPropsFromNodeId);
113
120
  });
114
121
  populateInstance(instance, {
115
122
  getNode,
123
+ getItem,
116
124
  getNodesToRender,
117
125
  getChildrenIds,
118
126
  getNavigableChildrenIds,
119
127
  isNodeDisabled
120
128
  });
129
+ populatePublicAPI(publicAPI, {
130
+ getItem
131
+ });
121
132
  return {
122
133
  contextValue: {
123
134
  disabledItemsFocusable: params.disabledItemsFocusable
124
135
  }
125
136
  };
126
137
  };
127
- useTreeViewNodes.getInitialState = params => updateState({
128
- items: params.items,
129
- isItemDisabled: params.isItemDisabled,
130
- getItemId: params.getItemId,
131
- getItemLabel: params.getItemLabel
138
+ useTreeViewNodes.getInitialState = params => ({
139
+ nodes: updateNodesState({
140
+ items: params.items,
141
+ isItemDisabled: params.isItemDisabled,
142
+ getItemId: params.getItemId,
143
+ getItemLabel: params.getItemLabel
144
+ })
132
145
  });
133
146
  useTreeViewNodes.getDefaultizedParams = params => _extends({}, params, {
134
147
  disabledItemsFocusable: params.disabledItemsFocusable ?? false
@@ -3,6 +3,16 @@ import * as React from 'react';
3
3
  import useForkRef from '@mui/utils/useForkRef';
4
4
  import { useTreeViewModels } from './useTreeViewModels';
5
5
  import { TREE_VIEW_CORE_PLUGINS } from '../corePlugins';
6
+ export function useTreeViewApiInitialization(inputApiRef) {
7
+ const fallbackPublicApiRef = React.useRef({});
8
+ if (inputApiRef) {
9
+ if (inputApiRef.current == null) {
10
+ inputApiRef.current = {};
11
+ }
12
+ return inputApiRef.current;
13
+ }
14
+ return fallbackPublicApiRef.current;
15
+ }
6
16
  export const useTreeView = inParams => {
7
17
  const plugins = [...TREE_VIEW_CORE_PLUGINS, ...inParams.plugins];
8
18
  const params = plugins.reduce((acc, plugin) => {
@@ -14,6 +24,7 @@ export const useTreeView = inParams => {
14
24
  const models = useTreeViewModels(plugins, params);
15
25
  const instanceRef = React.useRef({});
16
26
  const instance = instanceRef.current;
27
+ const publicAPI = useTreeViewApiInitialization(inParams.apiRef);
17
28
  const innerRootRef = React.useRef(null);
18
29
  const handleRootRef = useForkRef(innerRootRef, inParams.rootRef);
19
30
  const [state, setState] = React.useState(() => {
@@ -32,6 +43,7 @@ export const useTreeView = inParams => {
32
43
  const runPlugin = plugin => {
33
44
  const pluginResponse = plugin({
34
45
  instance,
46
+ publicAPI,
35
47
  params,
36
48
  slots: params.slots,
37
49
  slotProps: params.slotProps,
@@ -40,4 +40,7 @@ export const getLastNode = instance => {
40
40
  export const getFirstNode = instance => instance.getNavigableChildrenIds(null)[0];
41
41
  export const populateInstance = (instance, methods) => {
42
42
  Object.assign(instance, methods);
43
+ };
44
+ export const populatePublicAPI = (publicAPI, methods) => {
45
+ Object.assign(publicAPI, methods);
43
46
  };
@@ -1,10 +1,11 @@
1
1
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
2
- const _excluded = ["slots", "slotProps"];
2
+ const _excluded = ["slots", "slotProps", "apiRef"];
3
3
  export const extractPluginParamsFromProps = _ref => {
4
4
  let {
5
5
  props: {
6
6
  slots,
7
- slotProps
7
+ slotProps,
8
+ apiRef
8
9
  },
9
10
  plugins,
10
11
  rootRef
@@ -18,7 +19,8 @@ export const extractPluginParamsFromProps = _ref => {
18
19
  plugins,
19
20
  rootRef,
20
21
  slots: slots ?? {},
21
- slotProps: slotProps ?? {}
22
+ slotProps: slotProps ?? {},
23
+ apiRef
22
24
  };
23
25
  const otherProps = {};
24
26
  Object.keys(props).forEach(propName => {
@@ -0,0 +1,10 @@
1
+ export const getActiveElement = (root = document) => {
2
+ const activeEl = root.activeElement;
3
+ if (!activeEl) {
4
+ return null;
5
+ }
6
+ if (activeEl.shadowRoot) {
7
+ return getActiveElement(activeEl.shadowRoot);
8
+ }
9
+ return activeEl;
10
+ };
@@ -141,6 +141,15 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
141
141
  // | These PropTypes are generated from the TypeScript type definitions |
142
142
  // | To update them edit the TypeScript types and run "yarn proptypes" |
143
143
  // ----------------------------------------------------------------------
144
+ /**
145
+ * The ref object that allows Tree View manipulation. Can be instantiated with `useTreeViewApiRef()`.
146
+ */
147
+ apiRef: _propTypes.default.shape({
148
+ current: _propTypes.default.shape({
149
+ focusNode: _propTypes.default.func.isRequired,
150
+ getItem: _propTypes.default.func.isRequired
151
+ })
152
+ }),
144
153
  /**
145
154
  * Override or extend the styles applied to the component.
146
155
  */
@@ -99,6 +99,15 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
99
99
  // | These PropTypes are generated from the TypeScript type definitions |
100
100
  // | To update them edit the TypeScript types and run "yarn proptypes" |
101
101
  // ----------------------------------------------------------------------
102
+ /**
103
+ * The ref object that allows Tree View manipulation. Can be instantiated with `useTreeViewApiRef()`.
104
+ */
105
+ apiRef: _propTypes.default.shape({
106
+ current: _propTypes.default.shape({
107
+ focusNode: _propTypes.default.func.isRequired,
108
+ getItem: _propTypes.default.func.isRequired
109
+ })
110
+ }),
102
111
  /**
103
112
  * The content of the component.
104
113
  */
@@ -21,7 +21,7 @@ var _treeItemClasses = require("./treeItemClasses");
21
21
  var _useTreeViewContext = require("../internals/TreeViewProvider/useTreeViewContext");
22
22
  var _icons = require("../icons");
23
23
  var _jsxRuntime = require("react/jsx-runtime");
24
- const _excluded = ["children", "className", "slots", "slotProps", "ContentComponent", "ContentProps", "nodeId", "id", "label", "onClick", "onMouseDown", "TransitionComponent", "TransitionProps"],
24
+ const _excluded = ["children", "className", "slots", "slotProps", "ContentComponent", "ContentProps", "nodeId", "id", "label", "onClick", "onMouseDown"],
25
25
  _excluded2 = ["ownerState"],
26
26
  _excluded3 = ["ownerState"],
27
27
  _excluded4 = ["ownerState"];
@@ -40,7 +40,7 @@ const useUtilityClasses = ownerState => {
40
40
  disabled: ['disabled'],
41
41
  iconContainer: ['iconContainer'],
42
42
  label: ['label'],
43
- group: ['group']
43
+ groupTransition: ['groupTransition']
44
44
  };
45
45
  return (0, _base.unstable_composeClasses)(slots, _treeItemClasses.getTreeItemUtilityClass, classes);
46
46
  };
@@ -124,8 +124,8 @@ const StyledTreeItemContent = (0, _styles.styled)(_TreeItemContent.TreeItemConte
124
124
  }));
125
125
  const TreeItemGroup = (0, _styles.styled)(_Collapse.default, {
126
126
  name: 'MuiTreeItem',
127
- slot: 'Group',
128
- overridesResolver: (props, styles) => styles.group
127
+ slot: 'GroupTransition',
128
+ overridesResolver: (props, styles) => styles.groupTransition
129
129
  })({
130
130
  margin: 0,
131
131
  padding: 0,
@@ -175,16 +175,15 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
175
175
  id,
176
176
  label,
177
177
  onClick,
178
- onMouseDown,
179
- TransitionComponent = _Collapse.default,
180
- TransitionProps
178
+ onMouseDown
181
179
  } = props,
182
180
  other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
183
181
  const slots = {
184
182
  expandIcon: inSlots?.expandIcon ?? contextIcons.slots.expandIcon ?? _icons.TreeViewExpandIcon,
185
183
  collapseIcon: inSlots?.collapseIcon ?? contextIcons.slots.collapseIcon ?? _icons.TreeViewCollapseIcon,
186
184
  endIcon: inSlots?.endIcon ?? contextIcons.slots.endIcon,
187
- icon: inSlots?.icon
185
+ icon: inSlots?.icon,
186
+ groupTransition: inSlots?.groupTransition
188
187
  };
189
188
  const isExpandable = reactChildren => {
190
189
  if (Array.isArray(reactChildren)) {
@@ -204,6 +203,19 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
204
203
  disabled
205
204
  });
206
205
  const classes = useUtilityClasses(ownerState);
206
+ const GroupTransition = slots.groupTransition ?? undefined;
207
+ const groupTransitionProps = (0, _utils.useSlotProps)({
208
+ elementType: GroupTransition,
209
+ ownerState: {},
210
+ externalSlotProps: inSlotProps?.groupTransition,
211
+ additionalProps: {
212
+ unmountOnExit: true,
213
+ in: expanded,
214
+ component: 'ul',
215
+ role: 'group'
216
+ },
217
+ className: classes.groupTransition
218
+ });
207
219
  const ExpansionIcon = expanded ? slots.collapseIcon : slots.expandIcon;
208
220
  const _useSlotProps = (0, _utils.useSlotProps)({
209
221
  elementType: ExpansionIcon,
@@ -293,13 +305,8 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
293
305
  displayIcon: displayIcon,
294
306
  ownerState: ownerState
295
307
  }, ContentProps)), children && /*#__PURE__*/(0, _jsxRuntime.jsx)(TreeItemGroup, (0, _extends2.default)({
296
- as: TransitionComponent,
297
- unmountOnExit: true,
298
- className: classes.group,
299
- in: expanded,
300
- component: "ul",
301
- role: "group"
302
- }, TransitionProps, {
308
+ as: GroupTransition
309
+ }, groupTransitionProps, {
303
310
  children: children
304
311
  }))]
305
312
  }));
@@ -359,16 +366,5 @@ TreeItem.propTypes = {
359
366
  /**
360
367
  * The system prop that allows defining system overrides as well as additional CSS styles.
361
368
  */
362
- sx: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object, _propTypes.default.bool])), _propTypes.default.func, _propTypes.default.object]),
363
- /**
364
- * The component used for the transition.
365
- * [Follow this guide](/material-ui/transitions/#transitioncomponent-prop) to learn more about the requirements for this component.
366
- * @default Collapse
367
- */
368
- TransitionComponent: _propTypes.default.elementType,
369
- /**
370
- * Props applied to the transition element.
371
- * By default, the element is based on this [`Transition`](https://reactcommunity.org/react-transition-group/transition/) component.
372
- */
373
- TransitionProps: _propTypes.default.object
369
+ sx: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object, _propTypes.default.bool])), _propTypes.default.func, _propTypes.default.object])
374
370
  };
@@ -11,4 +11,4 @@ var _generateUtilityClasses = _interopRequireDefault(require("@mui/utils/generat
11
11
  function getTreeItemUtilityClass(slot) {
12
12
  return (0, _generateUtilityClass.default)('MuiTreeItem', slot);
13
13
  }
14
- const treeItemClasses = exports.treeItemClasses = (0, _generateUtilityClasses.default)('MuiTreeItem', ['root', 'group', 'content', 'expanded', 'selected', 'focused', 'disabled', 'iconContainer', 'label']);
14
+ const treeItemClasses = exports.treeItemClasses = (0, _generateUtilityClasses.default)('MuiTreeItem', ['root', 'groupTransition', 'content', 'expanded', 'selected', 'focused', 'disabled', 'iconContainer', 'label']);
@@ -73,6 +73,15 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
73
73
  // | These PropTypes are generated from the TypeScript type definitions |
74
74
  // | To update them edit the TypeScript types and run "yarn proptypes" |
75
75
  // ----------------------------------------------------------------------
76
+ /**
77
+ * The ref object that allows Tree View manipulation. Can be instantiated with `useTreeViewApiRef()`.
78
+ */
79
+ apiRef: _propTypes.default.shape({
80
+ current: _propTypes.default.shape({
81
+ focusNode: _propTypes.default.func.isRequired,
82
+ getItem: _propTypes.default.func.isRequired
83
+ })
84
+ }),
76
85
  /**
77
86
  * The content of the component.
78
87
  */
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "useTreeViewApiRef", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _useTreeViewApiRef.useTreeViewApiRef;
10
+ }
11
+ });
12
+ var _useTreeViewApiRef = require("./useTreeViewApiRef");
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useTreeViewApiRef = void 0;
7
+ var React = _interopRequireWildcard(require("react"));
8
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
9
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
10
+ /**
11
+ * Hook that instantiates a [[TreeViewApiRef]].
12
+ */
13
+ const useTreeViewApiRef = () => React.useRef(undefined);
14
+ exports.useTreeViewApiRef = useTreeViewApiRef;
package/node/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view v7.0.0-beta.4
2
+ * @mui/x-tree-view v7.0.0-beta.6
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -91,4 +91,16 @@ Object.keys(_icons).forEach(function (key) {
91
91
  return _icons[key];
92
92
  }
93
93
  });
94
+ });
95
+ var _hooks = require("./hooks");
96
+ Object.keys(_hooks).forEach(function (key) {
97
+ if (key === "default" || key === "__esModule") return;
98
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
99
+ if (key in exports && exports[key] === _hooks[key]) return;
100
+ Object.defineProperty(exports, key, {
101
+ enumerable: true,
102
+ get: function () {
103
+ return _hooks[key];
104
+ }
105
+ });
94
106
  });
@@ -1,18 +1,20 @@
1
1
  "use strict";
2
+ 'use client';
2
3
 
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
7
+ exports.Timeout = void 0;
6
8
  exports.useTimeout = useTimeout;
7
9
  var _useLazyRef = require("./useLazyRef");
8
10
  var _useOnMount = require("./useOnMount");
9
11
  class Timeout {
10
12
  constructor() {
11
- this.currentId = 0;
13
+ this.currentId = null;
12
14
  this.clear = () => {
13
- if (this.currentId !== 0) {
15
+ if (this.currentId !== null) {
14
16
  clearTimeout(this.currentId);
15
- this.currentId = 0;
17
+ this.currentId = null;
16
18
  }
17
19
  };
18
20
  this.disposeEffect = () => {
@@ -22,11 +24,18 @@ class Timeout {
22
24
  static create() {
23
25
  return new Timeout();
24
26
  }
27
+ /**
28
+ * Executes `fn` after `delay`, clearing any previously scheduled call.
29
+ */
25
30
  start(delay, fn) {
26
31
  this.clear();
27
- this.currentId = setTimeout(fn, delay);
32
+ this.currentId = setTimeout(() => {
33
+ this.currentId = null;
34
+ fn();
35
+ }, delay);
28
36
  }
29
37
  }
38
+ exports.Timeout = Timeout;
30
39
  function useTimeout() {
31
40
  const timeout = (0, _useLazyRef.useLazyRef)(Timeout.create).current;
32
41
  (0, _useOnMount.useOnMount)(timeout.disposeEffect);
@@ -11,10 +11,12 @@ var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallb
11
11
  var _ownerDocument = _interopRequireDefault(require("@mui/utils/ownerDocument"));
12
12
  var _useTreeView = require("../../useTreeView/useTreeView.utils");
13
13
  var _useInstanceEventHandler = require("../../hooks/useInstanceEventHandler");
14
+ var _utils = require("../../utils/utils");
14
15
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
15
16
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
16
17
  const useTreeViewFocus = ({
17
18
  instance,
19
+ publicAPI,
18
20
  params,
19
21
  state,
20
22
  setState,
@@ -23,19 +25,45 @@ const useTreeViewFocus = ({
23
25
  }) => {
24
26
  const setFocusedNodeId = (0, _useEventCallback.default)(nodeId => {
25
27
  const cleanNodeId = typeof nodeId === 'function' ? nodeId(state.focusedNodeId) : nodeId;
26
- setState(prevState => (0, _extends2.default)({}, prevState, {
27
- focusedNodeId: cleanNodeId
28
- }));
28
+ if (state.focusedNodeId !== cleanNodeId) {
29
+ setState(prevState => (0, _extends2.default)({}, prevState, {
30
+ focusedNodeId: cleanNodeId
31
+ }));
32
+ }
29
33
  });
30
- const isNodeFocused = React.useCallback(nodeId => state.focusedNodeId === nodeId, [state.focusedNodeId]);
34
+ const isTreeViewFocused = React.useCallback(() => !!rootRef.current && rootRef.current === (0, _utils.getActiveElement)((0, _ownerDocument.default)(rootRef.current)), [rootRef]);
35
+ const isNodeFocused = React.useCallback(nodeId => state.focusedNodeId === nodeId && isTreeViewFocused(), [state.focusedNodeId, isTreeViewFocused]);
36
+ const isNodeVisible = nodeId => {
37
+ const node = instance.getNode(nodeId);
38
+ return node && (node.parentId == null || instance.isNodeExpanded(node.parentId));
39
+ };
31
40
  const focusNode = (0, _useEventCallback.default)((event, nodeId) => {
32
- if (nodeId) {
41
+ // if we receive a nodeId, and it is visible, the focus will be set to it
42
+ if (nodeId && isNodeVisible(nodeId)) {
43
+ if (!isTreeViewFocused()) {
44
+ instance.focusRoot();
45
+ }
33
46
  setFocusedNodeId(nodeId);
34
47
  if (params.onNodeFocus) {
35
48
  params.onNodeFocus(event, nodeId);
36
49
  }
37
50
  }
38
51
  });
52
+ const focusDefaultNode = (0, _useEventCallback.default)(event => {
53
+ let nodeToFocusId;
54
+ if (Array.isArray(models.selectedNodes.value)) {
55
+ nodeToFocusId = models.selectedNodes.value.find(isNodeVisible);
56
+ } else if (models.selectedNodes.value != null && isNodeVisible(models.selectedNodes.value)) {
57
+ nodeToFocusId = models.selectedNodes.value;
58
+ }
59
+ if (nodeToFocusId == null) {
60
+ nodeToFocusId = instance.getNavigableChildrenIds(null)[0];
61
+ }
62
+ setFocusedNodeId(nodeToFocusId);
63
+ if (params.onNodeFocus) {
64
+ params.onNodeFocus(event, nodeToFocusId);
65
+ }
66
+ });
39
67
  const focusRoot = (0, _useEventCallback.default)(() => {
40
68
  rootRef.current?.focus({
41
69
  preventScroll: true
@@ -44,7 +72,11 @@ const useTreeViewFocus = ({
44
72
  (0, _useTreeView.populateInstance)(instance, {
45
73
  isNodeFocused,
46
74
  focusNode,
47
- focusRoot
75
+ focusRoot,
76
+ focusDefaultNode
77
+ });
78
+ (0, _useTreeView.populatePublicAPI)(publicAPI, {
79
+ focusNode
48
80
  });
49
81
  (0, _useInstanceEventHandler.useInstanceEventHandler)(instance, 'removeNode', ({
50
82
  id
@@ -58,23 +90,9 @@ const useTreeViewFocus = ({
58
90
  });
59
91
  const createHandleFocus = otherHandlers => event => {
60
92
  otherHandlers.onFocus?.(event);
61
-
62
93
  // if the event bubbled (which is React specific) we don't want to steal focus
63
94
  if (event.target === event.currentTarget) {
64
- const isNodeVisible = nodeId => {
65
- const node = instance.getNode(nodeId);
66
- return node && (node.parentId == null || instance.isNodeExpanded(node.parentId));
67
- };
68
- let nodeToFocusId;
69
- if (Array.isArray(models.selectedNodes.value)) {
70
- nodeToFocusId = models.selectedNodes.value.find(isNodeVisible);
71
- } else if (models.selectedNodes.value != null && isNodeVisible(models.selectedNodes.value)) {
72
- nodeToFocusId = models.selectedNodes.value;
73
- }
74
- if (nodeToFocusId == null) {
75
- nodeToFocusId = instance.getNavigableChildrenIds(null)[0];
76
- }
77
- instance.focusNode(event, nodeToFocusId);
95
+ instance.focusDefaultNode(event);
78
96
  }
79
97
  };
80
98
  const createHandleBlur = otherHandlers => event => {
@@ -22,22 +22,36 @@ const useTreeViewJSXNodes = ({
22
22
  }) => {
23
23
  const insertJSXNode = (0, _useEventCallback.default)(node => {
24
24
  setState(prevState => {
25
- if (prevState.nodeMap[node.id] != null) {
25
+ if (prevState.nodes.nodeMap[node.id] != null) {
26
26
  throw new Error(['MUI X: 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.', `Tow items were provided with the same id in the \`items\` prop: "${node.id}"`].join('\n'));
27
27
  }
28
28
  return (0, _extends2.default)({}, prevState, {
29
- nodeMap: (0, _extends2.default)({}, prevState.nodeMap, {
30
- [node.id]: node
29
+ nodes: (0, _extends2.default)({}, prevState.nodes, {
30
+ nodeMap: (0, _extends2.default)({}, prevState.nodes.nodeMap, {
31
+ [node.id]: node
32
+ }),
33
+ // For `SimpleTreeView`, we don't have a proper `item` object, so we create a very basic one.
34
+ itemMap: (0, _extends2.default)({}, prevState.nodes.itemMap, {
35
+ [node.id]: {
36
+ id: node.id,
37
+ label: node.label
38
+ }
39
+ })
31
40
  })
32
41
  });
33
42
  });
34
43
  });
35
44
  const removeJSXNode = (0, _useEventCallback.default)(nodeId => {
36
45
  setState(prevState => {
37
- const newMap = (0, _extends2.default)({}, prevState.nodeMap);
38
- delete newMap[nodeId];
46
+ const newNodeMap = (0, _extends2.default)({}, prevState.nodes.nodeMap);
47
+ const newItemMap = (0, _extends2.default)({}, prevState.nodes.itemMap);
48
+ delete newNodeMap[nodeId];
49
+ delete newItemMap[nodeId];
39
50
  return (0, _extends2.default)({}, prevState, {
40
- nodeMap: newMap
51
+ nodes: (0, _extends2.default)({}, prevState.nodes, {
52
+ nodeMap: newNodeMap,
53
+ itemMap: newItemMap
54
+ })
41
55
  });
42
56
  });
43
57
  (0, _publishTreeViewEvent.publishTreeViewEvent)(instance, 'removeNode', {