@mui/x-tree-view 8.0.0-alpha.13 → 8.0.0-alpha.14

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 (120) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/RichTreeView/RichTreeView.js +24 -5
  3. package/SimpleTreeView/SimpleTreeView.js +8 -6
  4. package/TreeItem/TreeItem.d.ts +2 -0
  5. package/TreeItem/TreeItem.js +46 -5
  6. package/TreeItem/TreeItem.types.d.ts +14 -0
  7. package/TreeItemIcon/TreeItemIcon.js +2 -0
  8. package/esm/RichTreeView/RichTreeView.js +24 -5
  9. package/esm/SimpleTreeView/SimpleTreeView.js +8 -6
  10. package/esm/TreeItem/TreeItem.d.ts +2 -0
  11. package/esm/TreeItem/TreeItem.js +45 -4
  12. package/esm/TreeItem/TreeItem.types.d.ts +14 -0
  13. package/esm/TreeItemIcon/TreeItemIcon.js +2 -0
  14. package/esm/hooks/useTreeItemUtils/useTreeItemUtils.d.ts +3 -2
  15. package/esm/hooks/useTreeItemUtils/useTreeItemUtils.js +21 -9
  16. package/esm/hooks/useTreeViewApiRef.d.ts +1 -1
  17. package/esm/index.js +1 -1
  18. package/esm/internals/index.d.ts +6 -1
  19. package/esm/internals/index.js +4 -1
  20. package/esm/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +35 -12
  21. package/esm/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.d.ts +4 -0
  22. package/esm/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +40 -16
  23. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.js +157 -16
  24. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.d.ts +172 -0
  25. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +13 -0
  26. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +49 -0
  27. package/esm/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +2 -2
  28. package/esm/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +16 -7
  29. package/esm/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +2 -1
  30. package/esm/internals/plugins/useTreeViewLazyLoading/index.d.ts +1 -0
  31. package/esm/internals/plugins/useTreeViewLazyLoading/index.js +1 -0
  32. package/esm/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.d.ts +249 -0
  33. package/esm/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.js +27 -0
  34. package/esm/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.types.d.ts +83 -0
  35. package/esm/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.types.js +1 -0
  36. package/esm/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +4 -4
  37. package/esm/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +12 -12
  38. package/esm/internals/utils/selectors.d.ts +7 -0
  39. package/esm/internals/utils/selectors.js +9 -0
  40. package/esm/useTreeItem/useTreeItem.d.ts +1 -1
  41. package/esm/useTreeItem/useTreeItem.js +13 -0
  42. package/esm/useTreeItem/useTreeItem.types.d.ts +21 -0
  43. package/esm/utils/cache.d.ts +38 -0
  44. package/esm/utils/cache.js +31 -0
  45. package/esm/utils/index.d.ts +1 -0
  46. package/esm/utils/index.js +1 -0
  47. package/hooks/useTreeItemUtils/useTreeItemUtils.d.ts +3 -2
  48. package/hooks/useTreeItemUtils/useTreeItemUtils.js +22 -10
  49. package/hooks/useTreeViewApiRef.d.ts +1 -1
  50. package/index.js +1 -1
  51. package/internals/index.d.ts +6 -1
  52. package/internals/index.js +33 -0
  53. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +35 -12
  54. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.d.ts +4 -0
  55. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +40 -16
  56. package/internals/plugins/useTreeViewItems/useTreeViewItems.js +157 -16
  57. package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.d.ts +172 -0
  58. package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +14 -1
  59. package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +49 -0
  60. package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +1 -1
  61. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +16 -7
  62. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +2 -1
  63. package/internals/plugins/useTreeViewLazyLoading/index.d.ts +1 -0
  64. package/internals/plugins/useTreeViewLazyLoading/index.js +5 -0
  65. package/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.d.ts +249 -0
  66. package/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.js +33 -0
  67. package/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.types.d.ts +83 -0
  68. package/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.types.js +5 -0
  69. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +4 -4
  70. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +12 -12
  71. package/internals/utils/selectors.d.ts +7 -0
  72. package/internals/utils/selectors.js +9 -0
  73. package/modern/RichTreeView/RichTreeView.js +24 -5
  74. package/modern/SimpleTreeView/SimpleTreeView.js +8 -6
  75. package/modern/TreeItem/TreeItem.d.ts +2 -0
  76. package/modern/TreeItem/TreeItem.js +45 -4
  77. package/modern/TreeItem/TreeItem.types.d.ts +14 -0
  78. package/modern/TreeItemIcon/TreeItemIcon.js +2 -0
  79. package/modern/hooks/useTreeItemUtils/useTreeItemUtils.d.ts +3 -2
  80. package/modern/hooks/useTreeItemUtils/useTreeItemUtils.js +21 -9
  81. package/modern/hooks/useTreeViewApiRef.d.ts +1 -1
  82. package/modern/index.js +1 -1
  83. package/modern/internals/index.d.ts +6 -1
  84. package/modern/internals/index.js +4 -1
  85. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +35 -12
  86. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.d.ts +4 -0
  87. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +40 -16
  88. package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.js +157 -16
  89. package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.d.ts +172 -0
  90. package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +13 -0
  91. package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +49 -0
  92. package/modern/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +2 -2
  93. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +16 -7
  94. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +2 -1
  95. package/modern/internals/plugins/useTreeViewLazyLoading/index.d.ts +1 -0
  96. package/modern/internals/plugins/useTreeViewLazyLoading/index.js +1 -0
  97. package/modern/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.d.ts +249 -0
  98. package/modern/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.js +27 -0
  99. package/modern/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.types.d.ts +83 -0
  100. package/modern/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.types.js +1 -0
  101. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +4 -4
  102. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +12 -12
  103. package/modern/internals/utils/selectors.d.ts +7 -0
  104. package/modern/internals/utils/selectors.js +9 -0
  105. package/modern/useTreeItem/useTreeItem.d.ts +1 -1
  106. package/modern/useTreeItem/useTreeItem.js +13 -0
  107. package/modern/useTreeItem/useTreeItem.types.d.ts +21 -0
  108. package/modern/utils/cache.d.ts +38 -0
  109. package/modern/utils/cache.js +31 -0
  110. package/modern/utils/index.d.ts +1 -0
  111. package/modern/utils/index.js +1 -0
  112. package/package.json +1 -1
  113. package/tsconfig.build.tsbuildinfo +1 -1
  114. package/useTreeItem/useTreeItem.d.ts +1 -1
  115. package/useTreeItem/useTreeItem.js +13 -0
  116. package/useTreeItem/useTreeItem.types.d.ts +21 -0
  117. package/utils/cache.d.ts +38 -0
  118. package/utils/cache.js +38 -0
  119. package/utils/index.d.ts +1 -0
  120. package/utils/index.js +16 -0
@@ -7,6 +7,7 @@ const _excluded = ["visible"],
7
7
  import * as React from 'react';
8
8
  import PropTypes from 'prop-types';
9
9
  import clsx from 'clsx';
10
+ import CircularProgress from '@mui/material/CircularProgress';
10
11
  import unsupportedProp from '@mui/utils/unsupportedProp';
11
12
  import { alpha } from '@mui/material/styles';
12
13
  import Collapse from '@mui/material/Collapse';
@@ -132,6 +133,7 @@ export const TreeItemIconContainer = styled('div', {
132
133
  display: 'flex',
133
134
  flexShrink: 0,
134
135
  justifyContent: 'center',
136
+ position: 'relative',
135
137
  '& svg': {
136
138
  fontSize: 18
137
139
  }
@@ -144,6 +146,25 @@ export const TreeItemGroupTransition = styled(Collapse, {
144
146
  margin: 0,
145
147
  padding: 0
146
148
  });
149
+ export const TreeItemErrorContainer = styled('div', {
150
+ name: 'MuiTreeItem',
151
+ slot: 'ErrorIcon',
152
+ overridesResolver: (props, styles) => styles.errorIcon
153
+ })({
154
+ position: 'absolute',
155
+ right: -3,
156
+ width: 7,
157
+ height: 7,
158
+ borderRadius: '50%',
159
+ backgroundColor: 'red'
160
+ });
161
+ export const TreeItemLoadingContainer = styled(CircularProgress, {
162
+ name: 'MuiTreeItem',
163
+ slot: 'LoadingIcon',
164
+ overridesResolver: (props, styles) => styles.loadingIcon
165
+ })({
166
+ color: 'text.primary'
167
+ });
147
168
  export const TreeItemCheckbox = styled(/*#__PURE__*/React.forwardRef((props, ref) => {
148
169
  const {
149
170
  visible
@@ -180,7 +201,9 @@ const useUtilityClasses = ownerState => {
180
201
  label: ['label'],
181
202
  groupTransition: ['groupTransition'],
182
203
  labelInput: ['labelInput'],
183
- dragAndDropOverlay: ['dragAndDropOverlay']
204
+ dragAndDropOverlay: ['dragAndDropOverlay'],
205
+ errorIcon: ['errorIcon'],
206
+ loadingIcon: ['loadingIcon']
184
207
  };
185
208
  return composeClasses(slots, getTreeItemUtilityClass, classes);
186
209
  };
@@ -219,6 +242,8 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
219
242
  getGroupTransitionProps,
220
243
  getLabelInputProps,
221
244
  getDragAndDropOverlayProps,
245
+ getErrorContainerProps,
246
+ getLoadingContainerProps,
222
247
  status
223
248
  } = useTreeItem({
224
249
  id,
@@ -297,15 +322,31 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
297
322
  ownerState: {},
298
323
  className: classes.dragAndDropOverlay
299
324
  });
325
+ const ErrorIcon = slots.errorIcon ?? TreeItemErrorContainer;
326
+ const errorContainerProps = useSlotProps({
327
+ elementType: ErrorIcon,
328
+ getSlotProps: getErrorContainerProps,
329
+ externalSlotProps: slotProps.errorIcon,
330
+ ownerState: {},
331
+ className: classes.errorIcon
332
+ });
333
+ const LoadingIcon = slots.loadingIcon ?? TreeItemLoadingContainer;
334
+ const loadingContainerProps = useSlotProps({
335
+ elementType: LoadingIcon,
336
+ getSlotProps: getLoadingContainerProps,
337
+ externalSlotProps: slotProps.loadingIcon,
338
+ ownerState: {},
339
+ className: classes.loadingIcon
340
+ });
300
341
  return /*#__PURE__*/_jsx(TreeItemProvider, _extends({}, getContextProviderProps(), {
301
342
  children: /*#__PURE__*/_jsxs(Root, _extends({}, rootProps, {
302
343
  children: [/*#__PURE__*/_jsxs(Content, _extends({}, contentProps, {
303
- children: [/*#__PURE__*/_jsx(IconContainer, _extends({}, iconContainerProps, {
304
- children: /*#__PURE__*/_jsx(TreeItemIcon, {
344
+ children: [/*#__PURE__*/_jsxs(IconContainer, _extends({}, iconContainerProps, {
345
+ children: [status.error && /*#__PURE__*/_jsx(ErrorIcon, _extends({}, errorContainerProps)), status.loading ? /*#__PURE__*/_jsx(LoadingIcon, _extends({}, loadingContainerProps)) : /*#__PURE__*/_jsx(TreeItemIcon, {
305
346
  status: status,
306
347
  slots: slots,
307
348
  slotProps: slotProps
308
- })
349
+ })]
309
350
  })), /*#__PURE__*/_jsx(Checkbox, _extends({}, checkboxProps)), status.editing ? /*#__PURE__*/_jsx(LabelInput, _extends({}, labelInputProps)) : /*#__PURE__*/_jsx(Label, _extends({}, labelProps)), /*#__PURE__*/_jsx(DragAndDropOverlay, _extends({}, dragAndDropOverlayProps))]
310
351
  })), children && /*#__PURE__*/_jsx(TreeItemGroupTransition, _extends({
311
352
  as: GroupTransition
@@ -49,6 +49,18 @@ export interface TreeItemSlots extends TreeItemIconSlots {
49
49
  * @default TreeItemDragAndDropOverlay
50
50
  */
51
51
  dragAndDropOverlay?: React.ElementType;
52
+ /**
53
+ * The component that is rendered when the item is in an error state.
54
+ * Warning: This slot is only useful when using the `<RichTreeViewPro />` component is lazy loading is enabled.
55
+ * @default TreeItemErrorContainer
56
+ */
57
+ errorIcon?: React.ElementType;
58
+ /**
59
+ * The component that is rendered when the item is in an loading state.
60
+ * Warning: This slot is only useful when using the `<RichTreeViewPro />` component is lazy loading is enabled.
61
+ * @default TreeItemLoadingContainer
62
+ */
63
+ loadingIcon?: React.ElementType;
52
64
  }
53
65
  export interface TreeItemSlotProps extends TreeItemIconSlotProps {
54
66
  root?: SlotComponentProps<'li', {}, {}>;
@@ -59,6 +71,8 @@ export interface TreeItemSlotProps extends TreeItemIconSlotProps {
59
71
  label?: SlotComponentProps<'div', {}, {}>;
60
72
  labelInput?: SlotComponentProps<'input', {}, {}>;
61
73
  dragAndDropOverlay?: SlotComponentProps<'div', {}, {}>;
74
+ errorIcon?: SlotComponentProps<'div', {}, {}>;
75
+ loadingIcon?: SlotComponentProps<'div', {}, {}>;
62
76
  }
63
77
  export interface TreeItemProps extends Omit<UseTreeItemParameters, 'rootRef'>, Omit<React.HTMLAttributes<HTMLLIElement>, 'onFocus'> {
64
78
  className?: string;
@@ -63,9 +63,11 @@ process.env.NODE_ENV !== "production" ? TreeItemIcon.propTypes = {
63
63
  disabled: PropTypes.bool.isRequired,
64
64
  editable: PropTypes.bool.isRequired,
65
65
  editing: PropTypes.bool.isRequired,
66
+ error: PropTypes.bool.isRequired,
66
67
  expandable: PropTypes.bool.isRequired,
67
68
  expanded: PropTypes.bool.isRequired,
68
69
  focused: PropTypes.bool.isRequired,
70
+ loading: PropTypes.bool.isRequired,
69
71
  selected: PropTypes.bool.isRequired
70
72
  }).isRequired
71
73
  } : void 0;
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react';
2
+ import type { UseTreeViewLazyLoadingSignature } from '../../internals/plugins/useTreeViewLazyLoading';
2
3
  import type { UseTreeViewSelectionSignature } from '../../internals/plugins/useTreeViewSelection';
3
4
  import type { UseTreeViewExpansionSignature } from '../../internals/plugins/useTreeViewExpansion';
4
5
  import type { UseTreeViewItemsSignature } from '../../internals/plugins/useTreeViewItems';
@@ -21,7 +22,7 @@ type UseTreeItemUtilsMinimalPlugins = readonly [UseTreeViewSelectionSignature, U
21
22
  /**
22
23
  * Plugins that `useTreeItemUtils` can use if they are present, but are not required.
23
24
  */
24
- export type UseTreeItemUtilsOptionalPlugins = readonly [UseTreeViewLabelSignature];
25
+ export type UseTreeItemUtilsOptionalPlugins = readonly [UseTreeViewLabelSignature, UseTreeViewLazyLoadingSignature];
25
26
  interface UseTreeItemUtilsReturnValue<TSignatures extends UseTreeItemUtilsMinimalPlugins, TOptionalSignatures extends UseTreeItemUtilsOptionalPlugins> {
26
27
  interactions: UseTreeItemInteractions;
27
28
  status: UseTreeItemStatus;
@@ -30,7 +31,7 @@ interface UseTreeItemUtilsReturnValue<TSignatures extends UseTreeItemUtilsMinima
30
31
  */
31
32
  publicAPI: TreeViewPublicAPI<TSignatures, TOptionalSignatures>;
32
33
  }
33
- export declare const isItemExpandable: (reactChildren: React.ReactNode) => boolean;
34
+ export declare const itemHasChildren: (reactChildren: React.ReactNode) => boolean;
34
35
  export declare const useTreeItemUtils: <TSignatures extends UseTreeItemUtilsMinimalPlugins = UseTreeItemUtilsMinimalPlugins, TOptionalSignatures extends UseTreeItemUtilsOptionalPlugins = UseTreeItemUtilsOptionalPlugins>({
35
36
  itemId,
36
37
  children
@@ -4,10 +4,11 @@ import { useTreeViewContext } from "../../internals/TreeViewProvider/index.js";
4
4
  import { useTreeViewLabel } from "../../internals/plugins/useTreeViewLabel/index.js";
5
5
  import { hasPlugin } from "../../internals/utils/plugins.js";
6
6
  import { useSelector } from "../../internals/hooks/useSelector.js";
7
- import { selectorIsItemExpanded } from "../../internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js";
7
+ import { selectorIsItemExpandable, selectorIsItemExpanded } from "../../internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js";
8
8
  import { selectorIsItemFocused } from "../../internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.js";
9
9
  import { selectorIsItemDisabled } from "../../internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js";
10
10
  import { selectorIsItemSelected } from "../../internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.js";
11
+ import { selectorGetTreeItemError, selectorIsItemLoading, selectorIsLazyLoadingEnabled } from "../../internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.js";
11
12
  import { selectorIsItemBeingEdited, selectorIsItemEditable } from "../../internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.js";
12
13
 
13
14
  /**
@@ -18,9 +19,9 @@ import { selectorIsItemBeingEdited, selectorIsItemEditable } from "../../interna
18
19
  * Plugins that `useTreeItemUtils` can use if they are present, but are not required.
19
20
  */
20
21
 
21
- export const isItemExpandable = reactChildren => {
22
+ export const itemHasChildren = reactChildren => {
22
23
  if (Array.isArray(reactChildren)) {
23
- return reactChildren.length > 0 && reactChildren.some(isItemExpandable);
24
+ return reactChildren.length > 0 && reactChildren.some(itemHasChildren);
24
25
  }
25
26
  return Boolean(reactChildren);
26
27
  };
@@ -37,6 +38,11 @@ export const useTreeItemUtils = ({
37
38
  },
38
39
  publicAPI
39
40
  } = useTreeViewContext();
41
+ const isItemExpandable = useSelector(store, selectorIsItemExpandable, itemId);
42
+ const isLazyLoadingEnabled = useSelector(store, selectorIsLazyLoadingEnabled);
43
+ const loading = useSelector(store, state => isLazyLoadingEnabled ? selectorIsItemLoading(state, itemId) : false);
44
+ const error = useSelector(store, state => isLazyLoadingEnabled ? Boolean(selectorGetTreeItemError(state, itemId)) : false);
45
+ const isExpandable = itemHasChildren(children) || isItemExpandable;
40
46
  const isExpanded = useSelector(store, selectorIsItemExpanded, itemId);
41
47
  const isFocused = useSelector(store, selectorIsItemFocused, itemId);
42
48
  const isSelected = useSelector(store, selectorIsItemSelected, itemId);
@@ -47,13 +53,15 @@ export const useTreeItemUtils = ({
47
53
  isItemEditable: label.isItemEditable
48
54
  }));
49
55
  const status = {
50
- expandable: isItemExpandable(children),
56
+ expandable: isExpandable,
51
57
  expanded: isExpanded,
52
58
  focused: isFocused,
53
59
  selected: isSelected,
54
60
  disabled: isDisabled,
55
61
  editing: isEditing,
56
- editable: isEditable
62
+ editable: isEditable,
63
+ loading,
64
+ error
57
65
  };
58
66
  const handleExpansion = event => {
59
67
  if (status.disabled) {
@@ -66,7 +74,11 @@ export const useTreeItemUtils = ({
66
74
 
67
75
  // If already expanded and trying to toggle selection don't close
68
76
  if (status.expandable && !(multiple && selectorIsItemExpanded(store.value, itemId))) {
69
- instance.toggleItemExpansion(event, itemId);
77
+ // make sure the children selection is propagated again
78
+ instance.setItemExpansion({
79
+ event,
80
+ itemId
81
+ });
70
82
  }
71
83
  };
72
84
  const handleSelection = event => {
@@ -81,14 +93,14 @@ export const useTreeItemUtils = ({
81
93
  if (event.shiftKey) {
82
94
  instance.expandSelectionRange(event, itemId);
83
95
  } else {
84
- instance.selectItem({
96
+ instance.setItemSelection({
85
97
  event,
86
98
  itemId,
87
99
  keepExistingSelection: true
88
100
  });
89
101
  }
90
102
  } else {
91
- instance.selectItem({
103
+ instance.setItemSelection({
92
104
  event,
93
105
  itemId,
94
106
  shouldBeSelected: true
@@ -100,7 +112,7 @@ export const useTreeItemUtils = ({
100
112
  if (multiSelect && hasShift) {
101
113
  instance.expandSelectionRange(event, itemId);
102
114
  } else {
103
- instance.selectItem({
115
+ instance.setItemSelection({
104
116
  event,
105
117
  itemId,
106
118
  keepExistingSelection: multiSelect,
@@ -4,4 +4,4 @@ import { RichTreeViewPluginSignatures } from "../RichTreeView/RichTreeView.plugi
4
4
  /**
5
5
  * Hook that instantiates a [[TreeViewApiRef]].
6
6
  */
7
- export declare const useTreeViewApiRef: <TSignatures extends readonly TreeViewAnyPluginSignature[] = readonly [import("../internals").UseTreeViewItemsSignature, import("../internals").UseTreeViewExpansionSignature, import("../internals").UseTreeViewSelectionSignature, import("../internals").UseTreeViewFocusSignature, import("../internals").UseTreeViewKeyboardNavigationSignature, import("../internals").UseTreeViewIconsSignature, import("../internals").UseTreeViewLabelSignature]>() => React.RefObject<TreeViewPublicAPI<TSignatures> | undefined>;
7
+ export declare const useTreeViewApiRef: <TSignatures extends readonly TreeViewAnyPluginSignature[] = RichTreeViewPluginSignatures>() => React.RefObject<TreeViewPublicAPI<TSignatures> | undefined>;
package/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view v8.0.0-alpha.13
2
+ * @mui/x-tree-view v8.0.0-alpha.14
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -2,7 +2,7 @@ export { useTreeView } from "./useTreeView/index.js";
2
2
  export { TreeViewProvider, useTreeViewContext } from "./TreeViewProvider/index.js";
3
3
  export { RichTreeViewItems } from "./components/RichTreeViewItems.js";
4
4
  export type { RichTreeViewItemsSlots, RichTreeViewItemsSlotProps } from './components/RichTreeViewItems';
5
- export { unstable_resetCleanupTracking } from "./hooks/useInstanceEventHandler.js";
5
+ export { unstable_resetCleanupTracking, useInstanceEventHandler } from "./hooks/useInstanceEventHandler.js";
6
6
  export { useSelector } from "./hooks/useSelector.js";
7
7
  export type { TreeViewPlugin, TreeViewPluginSignature, ConvertPluginsIntoSignatures, MergeSignaturesProperty, TreeViewPublicAPI, TreeViewState, TreeViewExperimentalFeatures, TreeViewItemMeta, TreeViewInstance, TreeViewItemPlugin, TreeViewUsedStore } from './models';
8
8
  export type { TreeViewCorePluginParameters } from './corePlugins';
@@ -21,6 +21,11 @@ export { selectorItemMetaLookup, selectorItemMeta, selectorItemIndex, selectorIt
21
21
  export type { UseTreeViewItemsSignature, UseTreeViewItemsParameters, UseTreeViewItemsState } from './plugins/useTreeViewItems';
22
22
  export { useTreeViewLabel } from "./plugins/useTreeViewLabel/index.js";
23
23
  export type { UseTreeViewLabelSignature, UseTreeViewLabelParameters } from './plugins/useTreeViewLabel';
24
+ export { selectorIsItemExpanded } from "./plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js";
25
+ export { selectorIsItemSelected } from "./plugins/useTreeViewSelection/useTreeViewSelection.selectors.js";
26
+ export { selectorDataSourceState, selectorGetTreeItemError } from "./plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.js";
27
+ export type { UseTreeViewLazyLoadingSignature } from './plugins/useTreeViewLazyLoading';
28
+ export type { UseTreeViewLazyLoadingParameters } from './plugins/useTreeViewLazyLoading';
24
29
  export { useTreeViewJSXItems } from "./plugins/useTreeViewJSXItems/index.js";
25
30
  export type { UseTreeViewJSXItemsSignature, UseTreeViewJSXItemsParameters } from './plugins/useTreeViewJSXItems';
26
31
  export { createSelector } from "./utils/selectors.js";
@@ -1,7 +1,7 @@
1
1
  export { useTreeView } from "./useTreeView/index.js";
2
2
  export { TreeViewProvider, useTreeViewContext } from "./TreeViewProvider/index.js";
3
3
  export { RichTreeViewItems } from "./components/RichTreeViewItems.js";
4
- export { unstable_resetCleanupTracking } from "./hooks/useInstanceEventHandler.js";
4
+ export { unstable_resetCleanupTracking, useInstanceEventHandler } from "./hooks/useInstanceEventHandler.js";
5
5
  export { useSelector } from "./hooks/useSelector.js";
6
6
 
7
7
  // Core plugins
@@ -15,6 +15,9 @@ export { useTreeViewIcons } from "./plugins/useTreeViewIcons/index.js";
15
15
  export { useTreeViewItems, buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from "./plugins/useTreeViewItems/index.js";
16
16
  export { selectorItemMetaLookup, selectorItemMeta, selectorItemIndex, selectorItemOrderedChildrenIds } from "./plugins/useTreeViewItems/useTreeViewItems.selectors.js";
17
17
  export { useTreeViewLabel } from "./plugins/useTreeViewLabel/index.js";
18
+ export { selectorIsItemExpanded } from "./plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js";
19
+ export { selectorIsItemSelected } from "./plugins/useTreeViewSelection/useTreeViewSelection.selectors.js";
20
+ export { selectorDataSourceState, selectorGetTreeItemError } from "./plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.js";
18
21
  export { useTreeViewJSXItems } from "./plugins/useTreeViewJSXItems/index.js";
19
22
  export { createSelector } from "./utils/selectors.js";
20
23
  export { isTargetInDescendants } from "./utils/tree.js";
@@ -4,6 +4,7 @@ import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
4
4
  import { selectorIsItemExpandable, selectorIsItemExpanded } from "./useTreeViewExpansion.selectors.js";
5
5
  import { createExpandedItemsMap, getExpansionTrigger } from "./useTreeViewExpansion.utils.js";
6
6
  import { selectorItemMeta, selectorItemOrderedChildrenIds } from "../useTreeViewItems/useTreeViewItems.selectors.js";
7
+ import { publishTreeViewEvent } from "../../utils/publishTreeViewEvent.js";
7
8
  export const useTreeViewExpansion = ({
8
9
  instance,
9
10
  store,
@@ -37,26 +38,48 @@ export const useTreeViewExpansion = ({
37
38
  params.onExpandedItemsChange?.(event, value);
38
39
  models.expandedItems.setControlledValue(value);
39
40
  };
40
- const toggleItemExpansion = useEventCallback((event, itemId) => {
41
- const isExpandedBefore = selectorIsItemExpanded(store.value, itemId);
42
- instance.setItemExpansion(event, itemId, !isExpandedBefore);
43
- });
44
- const setItemExpansion = useEventCallback((event, itemId, isExpanded) => {
45
- const isExpandedBefore = selectorIsItemExpanded(store.value, itemId);
46
- if (isExpandedBefore === isExpanded) {
47
- return;
48
- }
41
+ const applyItemExpansion = useEventCallback(({
42
+ itemId,
43
+ event,
44
+ shouldBeExpanded
45
+ }) => {
49
46
  let newExpanded;
50
- if (isExpanded) {
47
+ if (shouldBeExpanded) {
51
48
  newExpanded = [itemId].concat(models.expandedItems.value);
52
49
  } else {
53
50
  newExpanded = models.expandedItems.value.filter(id => id !== itemId);
54
51
  }
55
52
  if (params.onItemExpansionToggle) {
56
- params.onItemExpansionToggle(event, itemId, isExpanded);
53
+ params.onItemExpansionToggle(event, itemId, shouldBeExpanded);
57
54
  }
58
55
  setExpandedItems(event, newExpanded);
59
56
  });
57
+ const setItemExpansion = useEventCallback(({
58
+ itemId,
59
+ event = null,
60
+ shouldBeExpanded
61
+ }) => {
62
+ const isExpandedBefore = selectorIsItemExpanded(store.value, itemId);
63
+ const cleanShouldBeExpanded = shouldBeExpanded ?? !isExpandedBefore;
64
+ if (isExpandedBefore === cleanShouldBeExpanded) {
65
+ return;
66
+ }
67
+ const eventParameters = {
68
+ isExpansionPrevented: false,
69
+ shouldBeExpanded: cleanShouldBeExpanded,
70
+ event,
71
+ itemId
72
+ };
73
+ publishTreeViewEvent(instance, 'beforeItemToggleExpansion', eventParameters);
74
+ if (eventParameters.isExpansionPrevented) {
75
+ return;
76
+ }
77
+ instance.applyItemExpansion({
78
+ itemId,
79
+ event,
80
+ shouldBeExpanded: cleanShouldBeExpanded
81
+ });
82
+ });
60
83
  const expandAllSiblings = (event, itemId) => {
61
84
  const itemMeta = selectorItemMeta(store.value, itemId);
62
85
  if (itemMeta == null) {
@@ -80,7 +103,7 @@ export const useTreeViewExpansion = ({
80
103
  },
81
104
  instance: {
82
105
  setItemExpansion,
83
- toggleItemExpansion,
106
+ applyItemExpansion,
84
107
  expandAllSiblings
85
108
  }
86
109
  };
@@ -90,6 +90,8 @@ export declare const selectorIsItemExpandable: ((state: any, itemId: string | nu
90
90
  [itemId: string]: number;
91
91
  };
92
92
  };
93
+ loading: boolean;
94
+ error: Error | null;
93
95
  }) => {
94
96
  [itemId: string]: import("../..").TreeViewItemMeta;
95
97
  };
@@ -109,6 +111,8 @@ export declare const selectorIsItemExpandable: ((state: any, itemId: string | nu
109
111
  [itemId: string]: number;
110
112
  };
111
113
  };
114
+ loading: boolean;
115
+ error: Error | null;
112
116
  }) => {
113
117
  [itemId: string]: import("../..").TreeViewItemMeta;
114
118
  }) & {
@@ -7,26 +7,38 @@ import { UseTreeViewLabelSignature } from "../useTreeViewLabel/index.js";
7
7
  export interface UseTreeViewExpansionPublicAPI {
8
8
  /**
9
9
  * Change the expansion status of a given item.
10
- * @param {React.SyntheticEvent} event The DOM event that triggered the change.
11
- * @param {string} itemId The id of the item to expand of collapse.
12
- * @param {boolean} isExpanded If `true` the item will be expanded. If `false` the item will be collapsed.
10
+ * @param {object} parameters The parameters of the method.
11
+ * @param {string} parameters.itemId The id of the item to expand of collapse.
12
+ * @param {React.SyntheticEvent} parameters.event The DOM event that triggered the change.
13
+ * @param {boolean} parameters.shouldBeExpanded If `true` the item will be expanded. If `false` the item will be collapsed. If not defined, the item's expansion status will be the toggled.
13
14
  */
14
- setItemExpansion: (event: React.SyntheticEvent, itemId: string, isExpanded: boolean) => void;
15
+ setItemExpansion: (parameters: {
16
+ itemId: string;
17
+ event?: React.SyntheticEvent;
18
+ shouldBeExpanded?: boolean;
19
+ }) => void;
15
20
  }
16
21
  export interface UseTreeViewExpansionInstance extends UseTreeViewExpansionPublicAPI {
17
- /**
18
- * Toggle the current expansion of an item.
19
- * If it is expanded, it will be collapsed, and vice versa.
20
- * @param {React.SyntheticEvent} event The DOM event that triggered the change.
21
- * @param {TreeViewItemId} itemId The id of the item to toggle.
22
- */
23
- toggleItemExpansion: (event: React.SyntheticEvent, itemId: TreeViewItemId) => void;
24
22
  /**
25
23
  * Expand all the siblings (i.e.: the items that have the same parent) of a given item.
26
24
  * @param {React.SyntheticEvent} event The DOM event that triggered the change.
27
25
  * @param {TreeViewItemId} itemId The id of the item whose siblings will be expanded.
28
26
  */
29
27
  expandAllSiblings: (event: React.KeyboardEvent, itemId: TreeViewItemId) => void;
28
+ /**
29
+ * APply the new expansion status of a given item.
30
+ * Is used by the `setItemExpansion` method and by the `useTreeViewLazyLoading` plugin.
31
+ * Unlike `setItemExpansion`, this method does not trigger the lazy loading.
32
+ * @param {object} parameters The parameters of the method.
33
+ * @param {string} parameters.itemId The id of the item to expand of collapse.
34
+ * @param {React.SyntheticEvent | null} parameters.event The DOM event that triggered the change.
35
+ * @param {boolean} parameters.shouldBeExpanded If `true` the item will be expanded. If `false` the item will be collapsed.
36
+ */
37
+ applyItemExpansion: (parameters: {
38
+ itemId: string;
39
+ event: React.SyntheticEvent | null;
40
+ shouldBeExpanded: boolean;
41
+ }) => void;
30
42
  }
31
43
  export interface UseTreeViewExpansionParameters {
32
44
  /**
@@ -42,17 +54,17 @@ export interface UseTreeViewExpansionParameters {
42
54
  defaultExpandedItems?: string[];
43
55
  /**
44
56
  * Callback fired when Tree Items are expanded/collapsed.
45
- * @param {React.SyntheticEvent} event The DOM event that triggered the change.
57
+ * @param {React.SyntheticEvent} event The DOM event that triggered the change. Can be null when the change is caused by the `publicAPI.setItemExpansion()` method.
46
58
  * @param {array} itemIds The ids of the expanded items.
47
59
  */
48
- onExpandedItemsChange?: (event: React.SyntheticEvent, itemIds: string[]) => void;
60
+ onExpandedItemsChange?: (event: React.SyntheticEvent | null, itemIds: string[]) => void;
49
61
  /**
50
62
  * Callback fired when a Tree Item is expanded or collapsed.
51
- * @param {React.SyntheticEvent} event The DOM event that triggered the change.
63
+ * @param {React.SyntheticEvent | null} event The DOM event that triggered the change. Can be null when the change is caused by the `publicAPI.setItemExpansion()` method.
52
64
  * @param {array} itemId The itemId of the modified item.
53
65
  * @param {array} isExpanded `true` if the item has just been expanded, `false` if it has just been collapsed.
54
66
  */
55
- onItemExpansionToggle?: (event: React.SyntheticEvent, itemId: string, isExpanded: boolean) => void;
67
+ onItemExpansionToggle?: (event: React.SyntheticEvent | null, itemId: string, isExpanded: boolean) => void;
56
68
  /**
57
69
  * The slot that triggers the item's expansion when clicked.
58
70
  * @default 'content'
@@ -66,6 +78,16 @@ export interface UseTreeViewExpansionState {
66
78
  expansionTrigger: 'content' | 'iconContainer';
67
79
  };
68
80
  }
81
+ interface UseTreeViewExpansionEventLookup {
82
+ beforeItemToggleExpansion: {
83
+ params: {
84
+ isExpansionPrevented: boolean;
85
+ shouldBeExpanded: boolean;
86
+ event: React.SyntheticEvent | null;
87
+ itemId: TreeViewItemId;
88
+ };
89
+ };
90
+ }
69
91
  export type UseTreeViewExpansionSignature = TreeViewPluginSignature<{
70
92
  params: UseTreeViewExpansionParameters;
71
93
  defaultizedParams: UseTreeViewExpansionDefaultizedParameters;
@@ -75,4 +97,6 @@ export type UseTreeViewExpansionSignature = TreeViewPluginSignature<{
75
97
  state: UseTreeViewExpansionState;
76
98
  dependencies: [UseTreeViewItemsSignature];
77
99
  optionalDependencies: [UseTreeViewLabelSignature];
78
- }>;
100
+ events: UseTreeViewExpansionEventLookup;
101
+ }>;
102
+ export {};