@mui/x-tree-view 8.0.0-alpha.0 → 8.0.0-alpha.2

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 (159) hide show
  1. package/CHANGELOG.md +651 -6
  2. package/README.md +2 -2
  3. package/RichTreeView/RichTreeView.js +2 -4
  4. package/RichTreeView/RichTreeView.types.d.ts +5 -18
  5. package/SimpleTreeView/SimpleTreeView.types.d.ts +2 -2
  6. package/TreeItem/TreeItem.js +4 -4
  7. package/TreeItem/TreeItem.types.d.ts +4 -2
  8. package/TreeItemDragAndDropOverlay/TreeItemDragAndDropOverlay.js +1 -1
  9. package/TreeItemIcon/TreeItemIcon.types.d.ts +1 -1
  10. package/TreeItemProvider/TreeItemProvider.d.ts +2 -4
  11. package/TreeItemProvider/TreeItemProvider.js +26 -11
  12. package/TreeItemProvider/TreeItemProvider.types.d.ts +1 -0
  13. package/hooks/index.d.ts +1 -0
  14. package/hooks/index.js +2 -1
  15. package/hooks/useTreeItemModel.d.ts +2 -0
  16. package/hooks/useTreeItemModel.js +11 -0
  17. package/hooks/useTreeItemUtils/useTreeItemUtils.d.ts +2 -1
  18. package/hooks/useTreeItemUtils/useTreeItemUtils.js +31 -15
  19. package/hooks/useTreeViewApiRef.d.ts +1 -0
  20. package/index.js +1 -1
  21. package/internals/TreeViewItemDepthContext/TreeViewItemDepthContext.d.ts +3 -1
  22. package/internals/TreeViewProvider/TreeViewChildrenItemProvider.d.ts +2 -1
  23. package/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +6 -22
  24. package/internals/TreeViewProvider/TreeViewProvider.js +1 -2
  25. package/internals/TreeViewProvider/TreeViewProvider.types.d.ts +4 -2
  26. package/internals/components/RichTreeViewItems.d.ts +3 -5
  27. package/internals/components/RichTreeViewItems.js +42 -30
  28. package/internals/corePlugins/useTreeViewId/useTreeViewId.js +10 -11
  29. package/internals/corePlugins/useTreeViewId/useTreeViewId.selectors.d.ts +36 -0
  30. package/internals/corePlugins/useTreeViewId/useTreeViewId.selectors.js +9 -0
  31. package/internals/corePlugins/useTreeViewId/useTreeViewId.types.d.ts +1 -5
  32. package/internals/hooks/useSelector.d.ts +4 -0
  33. package/internals/hooks/useSelector.js +6 -0
  34. package/internals/index.d.ts +6 -1
  35. package/internals/index.js +5 -1
  36. package/internals/models/itemPlugin.d.ts +5 -5
  37. package/internals/models/plugin.d.ts +20 -8
  38. package/internals/models/treeView.d.ts +6 -0
  39. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +36 -24
  40. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.d.ts +124 -0
  41. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js +17 -0
  42. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +6 -14
  43. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.utils.d.ts +1 -0
  44. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.utils.js +7 -0
  45. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +62 -40
  46. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.d.ts +182 -0
  47. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.js +34 -0
  48. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +4 -16
  49. package/internals/plugins/useTreeViewIcons/useTreeViewIcons.js +15 -13
  50. package/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.d.ts +1 -1
  51. package/internals/plugins/useTreeViewItems/index.d.ts +1 -1
  52. package/internals/plugins/useTreeViewItems/useTreeViewItems.js +58 -98
  53. package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.d.ts +718 -0
  54. package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +103 -0
  55. package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +15 -52
  56. package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +29 -26
  57. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +27 -18
  58. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.js +13 -5
  59. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +19 -30
  60. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.d.ts +74 -0
  61. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.js +26 -0
  62. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.types.d.ts +7 -24
  63. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.itemPlugin.js +8 -6
  64. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +45 -34
  65. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.d.ts +32 -0
  66. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.js +9 -0
  67. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +6 -6
  68. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.d.ts +6 -6
  69. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +23 -13
  70. package/internals/useTreeView/useTreeView.js +30 -17
  71. package/internals/useTreeView/useTreeView.types.d.ts +2 -3
  72. package/internals/useTreeView/useTreeViewBuildContext.d.ts +3 -1
  73. package/internals/useTreeView/useTreeViewBuildContext.js +24 -18
  74. package/internals/utils/TreeViewStore.d.ts +12 -0
  75. package/internals/utils/TreeViewStore.js +24 -0
  76. package/internals/utils/selectors.d.ts +9 -0
  77. package/internals/utils/selectors.js +37 -0
  78. package/internals/utils/tree.d.ts +8 -8
  79. package/internals/utils/tree.js +51 -43
  80. package/models/items.d.ts +3 -2
  81. package/modern/RichTreeView/RichTreeView.js +2 -4
  82. package/modern/TreeItem/TreeItem.js +4 -4
  83. package/modern/TreeItemDragAndDropOverlay/TreeItemDragAndDropOverlay.js +1 -1
  84. package/modern/TreeItemProvider/TreeItemProvider.js +26 -11
  85. package/modern/hooks/index.js +2 -1
  86. package/modern/hooks/useTreeItemModel.js +11 -0
  87. package/modern/hooks/useTreeItemUtils/useTreeItemUtils.js +31 -15
  88. package/modern/index.js +1 -1
  89. package/modern/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +6 -22
  90. package/modern/internals/TreeViewProvider/TreeViewProvider.js +1 -2
  91. package/modern/internals/components/RichTreeViewItems.js +42 -30
  92. package/modern/internals/corePlugins/useTreeViewId/useTreeViewId.js +10 -11
  93. package/modern/internals/corePlugins/useTreeViewId/useTreeViewId.selectors.js +9 -0
  94. package/modern/internals/hooks/useSelector.js +6 -0
  95. package/modern/internals/index.js +5 -1
  96. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +36 -24
  97. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js +17 -0
  98. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.utils.js +7 -0
  99. package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +62 -40
  100. package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.js +34 -0
  101. package/modern/internals/plugins/useTreeViewIcons/useTreeViewIcons.js +15 -13
  102. package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.js +58 -98
  103. package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +103 -0
  104. package/modern/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +29 -26
  105. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +27 -18
  106. package/modern/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.js +13 -5
  107. package/modern/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +19 -30
  108. package/modern/internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.js +26 -0
  109. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.itemPlugin.js +8 -6
  110. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +45 -34
  111. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.js +9 -0
  112. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +23 -13
  113. package/modern/internals/useTreeView/useTreeView.js +30 -17
  114. package/modern/internals/useTreeView/useTreeViewBuildContext.js +24 -18
  115. package/modern/internals/utils/TreeViewStore.js +24 -0
  116. package/modern/internals/utils/selectors.js +37 -0
  117. package/modern/internals/utils/tree.js +51 -43
  118. package/modern/useTreeItem/useTreeItem.js +26 -11
  119. package/node/RichTreeView/RichTreeView.js +2 -4
  120. package/node/TreeItem/TreeItem.js +4 -4
  121. package/node/TreeItemDragAndDropOverlay/TreeItemDragAndDropOverlay.js +2 -2
  122. package/node/TreeItemProvider/TreeItemProvider.js +26 -10
  123. package/node/hooks/index.js +8 -1
  124. package/node/hooks/useTreeItemModel.js +17 -0
  125. package/node/hooks/useTreeItemUtils/useTreeItemUtils.js +32 -15
  126. package/node/index.js +1 -1
  127. package/node/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +6 -22
  128. package/node/internals/TreeViewProvider/TreeViewProvider.js +1 -2
  129. package/node/internals/components/RichTreeViewItems.js +42 -30
  130. package/node/internals/corePlugins/useTreeViewId/useTreeViewId.js +12 -13
  131. package/node/internals/corePlugins/useTreeViewId/useTreeViewId.selectors.js +15 -0
  132. package/node/internals/hooks/useSelector.js +13 -0
  133. package/node/internals/index.js +47 -1
  134. package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +36 -24
  135. package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js +23 -0
  136. package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.utils.js +14 -0
  137. package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +62 -40
  138. package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.js +40 -0
  139. package/node/internals/plugins/useTreeViewIcons/useTreeViewIcons.js +16 -13
  140. package/node/internals/plugins/useTreeViewItems/useTreeViewItems.js +60 -100
  141. package/node/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +109 -0
  142. package/node/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +30 -27
  143. package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +27 -18
  144. package/node/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.js +13 -5
  145. package/node/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +19 -30
  146. package/node/internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.js +32 -0
  147. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.itemPlugin.js +8 -6
  148. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +46 -35
  149. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.js +15 -0
  150. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +24 -14
  151. package/node/internals/useTreeView/useTreeView.js +30 -17
  152. package/node/internals/useTreeView/useTreeViewBuildContext.js +25 -18
  153. package/node/internals/utils/TreeViewStore.js +31 -0
  154. package/node/internals/utils/selectors.js +44 -0
  155. package/node/internals/utils/tree.js +51 -43
  156. package/node/useTreeItem/useTreeItem.js +26 -11
  157. package/package.json +6 -4
  158. package/useTreeItem/useTreeItem.js +26 -11
  159. package/useTreeItem/useTreeItem.types.d.ts +9 -0
@@ -5,6 +5,7 @@ import { useTreeViewModels } from "./useTreeViewModels.js";
5
5
  import { TREE_VIEW_CORE_PLUGINS } from "../corePlugins/index.js";
6
6
  import { extractPluginParamsFromProps } from "./extractPluginParamsFromProps.js";
7
7
  import { useTreeViewBuildContext } from "./useTreeViewBuildContext.js";
8
+ import { TreeViewStore } from "../utils/TreeViewStore.js";
8
9
  export function useTreeViewApiInitialization(inputApiRef) {
9
10
  const fallbackPublicApiRef = React.useRef({});
10
11
  if (inputApiRef) {
@@ -15,12 +16,13 @@ export function useTreeViewApiInitialization(inputApiRef) {
15
16
  }
16
17
  return fallbackPublicApiRef.current;
17
18
  }
19
+ let globalId = 0;
18
20
  export const useTreeView = ({
19
21
  plugins: inPlugins,
20
22
  rootRef,
21
23
  props
22
24
  }) => {
23
- const plugins = [...TREE_VIEW_CORE_PLUGINS, ...inPlugins];
25
+ const plugins = React.useMemo(() => [...TREE_VIEW_CORE_PLUGINS, ...inPlugins], [inPlugins]);
24
26
  const {
25
27
  pluginParams,
26
28
  forwardedProps,
@@ -38,22 +40,30 @@ export const useTreeView = ({
38
40
  const publicAPI = useTreeViewApiInitialization(apiRef);
39
41
  const innerRootRef = React.useRef(null);
40
42
  const handleRootRef = useForkRef(innerRootRef, rootRef);
41
- const contextValue = useTreeViewBuildContext({
42
- plugins,
43
- instance,
44
- publicAPI,
45
- rootRef: innerRootRef
46
- });
47
- const [state, setState] = React.useState(() => {
48
- const temp = {};
43
+ const storeRef = React.useRef(null);
44
+ if (storeRef.current == null) {
45
+ globalId += 1;
46
+ const initialState = {
47
+ cacheKey: {
48
+ id: globalId
49
+ }
50
+ };
49
51
  plugins.forEach(plugin => {
50
52
  if (plugin.getInitialState) {
51
- Object.assign(temp, plugin.getInitialState(pluginParams));
53
+ Object.assign(initialState, plugin.getInitialState(pluginParams));
52
54
  }
53
55
  });
54
- return temp;
56
+ storeRef.current = new TreeViewStore(initialState);
57
+ }
58
+ const baseContextValue = useTreeViewBuildContext({
59
+ plugins,
60
+ instance,
61
+ publicAPI,
62
+ store: storeRef.current,
63
+ rootRef: innerRootRef
55
64
  });
56
65
  const rootPropsGetters = [];
66
+ const pluginContextValues = [];
57
67
  const runPlugin = plugin => {
58
68
  const pluginResponse = plugin({
59
69
  instance,
@@ -61,11 +71,10 @@ export const useTreeView = ({
61
71
  slots,
62
72
  slotProps,
63
73
  experimentalFeatures,
64
- state,
65
- setState,
66
74
  rootRef: innerRootRef,
67
75
  models,
68
- plugins
76
+ plugins,
77
+ store: storeRef.current
69
78
  });
70
79
  if (pluginResponse.getRootProps) {
71
80
  rootPropsGetters.push(pluginResponse.getRootProps);
@@ -77,7 +86,7 @@ export const useTreeView = ({
77
86
  Object.assign(instance, pluginResponse.instance);
78
87
  }
79
88
  if (pluginResponse.contextValue) {
80
- Object.assign(contextValue, pluginResponse.contextValue);
89
+ pluginContextValues.push(pluginResponse.contextValue);
81
90
  }
82
91
  };
83
92
  plugins.forEach(runPlugin);
@@ -92,10 +101,14 @@ export const useTreeView = ({
92
101
  });
93
102
  return rootProps;
94
103
  };
104
+ const contextValue = React.useMemo(() => {
105
+ const copiedBaseContextValue = _extends({}, baseContextValue);
106
+ return Object.assign(copiedBaseContextValue, ...pluginContextValues);
107
+ // eslint-disable-next-line react-hooks/exhaustive-deps
108
+ }, [baseContextValue, ...pluginContextValues]);
95
109
  return {
96
110
  getRootProps,
97
111
  rootRef: handleRootRef,
98
- contextValue,
99
- instance
112
+ contextValue
100
113
  };
101
114
  };
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
- import { EventHandlers } from '@mui/utils';
2
+ import { EventHandlers } from '@mui/utils/types';
3
3
  import type { TreeViewContextValue } from '../TreeViewProvider';
4
- import { TreeViewAnyPluginSignature, ConvertSignaturesIntoPlugins, MergeSignaturesProperty, TreeViewInstance, TreeViewPublicAPI, TreeViewExperimentalFeatures } from '../models';
4
+ import { TreeViewAnyPluginSignature, ConvertSignaturesIntoPlugins, MergeSignaturesProperty, TreeViewPublicAPI, TreeViewExperimentalFeatures } from '../models';
5
5
  export interface UseTreeViewParameters<TSignatures extends readonly TreeViewAnyPluginSignature[], TProps extends Partial<UseTreeViewBaseProps<TSignatures>>> {
6
6
  plugins: ConvertSignaturesIntoPlugins<TSignatures>;
7
7
  rootRef?: React.Ref<HTMLUListElement> | undefined;
@@ -20,5 +20,4 @@ export interface UseTreeViewReturnValue<TSignatures extends readonly TreeViewAny
20
20
  getRootProps: <TOther extends EventHandlers = {}>(otherHandlers?: TOther) => UseTreeViewRootSlotProps;
21
21
  rootRef: React.RefCallback<HTMLUListElement> | null;
22
22
  contextValue: TreeViewContextValue<TSignatures>;
23
- instance: TreeViewInstance<TSignatures>;
24
23
  }
@@ -2,9 +2,11 @@ import * as React from 'react';
2
2
  import { TreeViewContextValue } from '../TreeViewProvider';
3
3
  import { ConvertSignaturesIntoPlugins, TreeViewAnyPluginSignature, TreeViewInstance, TreeViewPublicAPI } from '../models';
4
4
  import { TreeViewCorePluginSignatures } from '../corePlugins';
5
- export declare const useTreeViewBuildContext: <TSignatures extends readonly TreeViewAnyPluginSignature[]>({ plugins, instance, publicAPI, rootRef, }: {
5
+ import { TreeViewStore } from '../utils/TreeViewStore';
6
+ export declare const useTreeViewBuildContext: <TSignatures extends readonly TreeViewAnyPluginSignature[]>({ plugins, instance, publicAPI, store, rootRef, }: {
6
7
  plugins: ConvertSignaturesIntoPlugins<readonly [...TreeViewCorePluginSignatures, ...TSignatures]>;
7
8
  instance: TreeViewInstance<TSignatures>;
8
9
  publicAPI: TreeViewPublicAPI<TSignatures>;
10
+ store: TreeViewStore<TSignatures>;
9
11
  rootRef: React.RefObject<HTMLUListElement>;
10
12
  }) => TreeViewContextValue<TSignatures>;
@@ -1,10 +1,12 @@
1
+ import * as React from 'react';
1
2
  export const useTreeViewBuildContext = ({
2
3
  plugins,
3
4
  instance,
4
5
  publicAPI,
6
+ store,
5
7
  rootRef
6
8
  }) => {
7
- const runItemPlugins = itemPluginProps => {
9
+ const runItemPlugins = React.useCallback(itemPluginProps => {
8
10
  let finalRootRef = null;
9
11
  let finalContentRef = null;
10
12
  const pluginPropEnhancers = [];
@@ -49,10 +51,11 @@ export const useTreeViewBuildContext = ({
49
51
  rootRef: finalRootRef,
50
52
  propsEnhancers
51
53
  };
52
- };
53
- const wrapItem = ({
54
+ }, [plugins]);
55
+ const wrapItem = React.useCallback(({
54
56
  itemId,
55
- children
57
+ children,
58
+ idAttribute
56
59
  }) => {
57
60
  let finalChildren = children;
58
61
  // The wrappers are reversed to ensure that the first wrapper is the outermost one.
@@ -60,15 +63,16 @@ export const useTreeViewBuildContext = ({
60
63
  const plugin = plugins[i];
61
64
  if (plugin.wrapItem) {
62
65
  finalChildren = plugin.wrapItem({
66
+ instance,
63
67
  itemId,
64
68
  children: finalChildren,
65
- instance
69
+ idAttribute
66
70
  });
67
71
  }
68
72
  }
69
73
  return finalChildren;
70
- };
71
- const wrapRoot = ({
74
+ }, [plugins, instance]);
75
+ const wrapRoot = React.useCallback(({
72
76
  children
73
77
  }) => {
74
78
  let finalChildren = children;
@@ -77,19 +81,21 @@ export const useTreeViewBuildContext = ({
77
81
  const plugin = plugins[i];
78
82
  if (plugin.wrapRoot) {
79
83
  finalChildren = plugin.wrapRoot({
80
- children: finalChildren,
81
- instance
84
+ children: finalChildren
82
85
  });
83
86
  }
84
87
  }
85
88
  return finalChildren;
86
- };
87
- return {
88
- runItemPlugins,
89
- wrapItem,
90
- wrapRoot,
91
- instance,
92
- rootRef,
93
- publicAPI
94
- };
89
+ }, [plugins]);
90
+ return React.useMemo(() => {
91
+ return {
92
+ runItemPlugins,
93
+ wrapItem,
94
+ wrapRoot,
95
+ instance,
96
+ publicAPI,
97
+ store,
98
+ rootRef
99
+ };
100
+ }, [runItemPlugins, wrapItem, wrapRoot, instance, publicAPI, store, rootRef]);
95
101
  };
@@ -0,0 +1,12 @@
1
+ import type { TreeViewAnyPluginSignature, TreeViewState } from '../models';
2
+ type Listener<T> = (value: T) => void;
3
+ export type StoreUpdater<TSignatures extends readonly TreeViewAnyPluginSignature[]> = (prevState: TreeViewState<TSignatures>) => TreeViewState<TSignatures>;
4
+ export declare class TreeViewStore<TSignatures extends readonly TreeViewAnyPluginSignature[]> {
5
+ value: TreeViewState<TSignatures>;
6
+ private listeners;
7
+ constructor(value: TreeViewState<TSignatures>);
8
+ subscribe: (fn: Listener<TreeViewState<TSignatures>>) => () => void;
9
+ getSnapshot: () => TreeViewState<TSignatures>;
10
+ update: (updater: StoreUpdater<TSignatures>) => void;
11
+ }
12
+ export {};
@@ -0,0 +1,24 @@
1
+ export class TreeViewStore {
2
+ constructor(value) {
3
+ this.value = void 0;
4
+ this.listeners = void 0;
5
+ this.subscribe = fn => {
6
+ this.listeners.add(fn);
7
+ return () => {
8
+ this.listeners.delete(fn);
9
+ };
10
+ };
11
+ this.getSnapshot = () => {
12
+ return this.value;
13
+ };
14
+ this.update = updater => {
15
+ const newState = updater(this.value);
16
+ if (newState !== this.value) {
17
+ this.value = newState;
18
+ this.listeners.forEach(l => l(newState));
19
+ }
20
+ };
21
+ this.value = value;
22
+ this.listeners = new Set();
23
+ }
24
+ }
@@ -0,0 +1,9 @@
1
+ import { CreateSelectorFunction } from 'reselect';
2
+ import { TreeViewAnyPluginSignature, TreeViewState } from '../models';
3
+ export type TreeViewRootSelector<TSignature extends TreeViewAnyPluginSignature> = <TSignatures extends [TSignature]>(state: TreeViewState<TSignatures>) => TSignature['state'][keyof TSignature['state']];
4
+ export type TreeViewSelector<TState, TArgs, TResult> = (state: TState, args: TArgs) => TResult;
5
+ /**
6
+ * Method wrapping reselect's createSelector to provide caching for tree view instances.
7
+ *
8
+ */
9
+ export declare const createSelector: CreateSelectorFunction;
@@ -0,0 +1,37 @@
1
+ import { lruMemoize, createSelectorCreator } from 'reselect';
2
+ const reselectCreateSelector = createSelectorCreator({
3
+ memoize: lruMemoize,
4
+ memoizeOptions: {
5
+ maxSize: 1,
6
+ equalityCheck: Object.is
7
+ }
8
+ });
9
+ const cache = new WeakMap();
10
+ /**
11
+ * Method wrapping reselect's createSelector to provide caching for tree view instances.
12
+ *
13
+ */
14
+ export const createSelector = (...createSelectorArgs) => {
15
+ const selector = (state, selectorArgs) => {
16
+ const cacheKey = state.cacheKey;
17
+
18
+ // If there is no cache for the current tree view instance, create one.
19
+ let cacheForCurrentTreeViewInstance = cache.get(cacheKey);
20
+ if (!cacheForCurrentTreeViewInstance) {
21
+ cacheForCurrentTreeViewInstance = new Map();
22
+ cache.set(cacheKey, cacheForCurrentTreeViewInstance);
23
+ }
24
+
25
+ // If there is a cached selector, execute it.
26
+ const cachedSelector = cacheForCurrentTreeViewInstance.get(createSelectorArgs);
27
+ if (cachedSelector) {
28
+ return cachedSelector(state, selectorArgs);
29
+ }
30
+
31
+ // Otherwise, create a new selector and cache it and execute it.
32
+ const fn = reselectCreateSelector(...createSelectorArgs);
33
+ cacheForCurrentTreeViewInstance.set(createSelectorArgs, fn);
34
+ return fn(state, selectorArgs);
35
+ };
36
+ return selector;
37
+ };
@@ -1,10 +1,10 @@
1
- import { TreeViewInstance } from '../models';
1
+ import { TreeViewState } from '../models';
2
2
  import type { UseTreeViewExpansionSignature } from '../plugins/useTreeViewExpansion';
3
3
  import type { UseTreeViewItemsSignature } from '../plugins/useTreeViewItems';
4
- export declare const getPreviousNavigableItem: (instance: TreeViewInstance<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>, itemId: string) => string | null;
5
- export declare const getNextNavigableItem: (instance: TreeViewInstance<[UseTreeViewExpansionSignature, UseTreeViewItemsSignature]>, itemId: string) => string | null;
6
- export declare const getLastNavigableItem: (instance: TreeViewInstance<[UseTreeViewExpansionSignature, UseTreeViewItemsSignature]>) => string;
7
- export declare const getFirstNavigableItem: (instance: TreeViewInstance<[UseTreeViewItemsSignature]>) => string;
4
+ export declare const getPreviousNavigableItem: (state: TreeViewState<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>, itemId: string) => string | null;
5
+ export declare const getNextNavigableItem: (state: TreeViewState<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>, itemId: string) => string | null;
6
+ export declare const getLastNavigableItem: (state: TreeViewState<[UseTreeViewExpansionSignature, UseTreeViewItemsSignature]>) => string;
7
+ export declare const getFirstNavigableItem: (state: TreeViewState<[UseTreeViewExpansionSignature, UseTreeViewItemsSignature]>) => string;
8
8
  /**
9
9
  * This is used to determine the start and end of a selection range so
10
10
  * we can get the items between the two border items.
@@ -19,9 +19,9 @@ export declare const getFirstNavigableItem: (instance: TreeViewInstance<[UseTree
19
19
  * Another way to put it is which item is shallower in a trémaux tree
20
20
  * https://en.wikipedia.org/wiki/Tr%C3%A9maux_tree
21
21
  */
22
- export declare const findOrderInTremauxTree: (instance: TreeViewInstance<[UseTreeViewItemsSignature]>, itemAId: string, itemBId: string) => string[];
23
- export declare const getNonDisabledItemsInRange: (instance: TreeViewInstance<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>, itemAId: string, itemBId: string) => string[];
24
- export declare const getAllNavigableItems: (instance: TreeViewInstance<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>) => string[];
22
+ export declare const findOrderInTremauxTree: (state: TreeViewState<[UseTreeViewExpansionSignature, UseTreeViewItemsSignature]>, itemAId: string, itemBId: string) => string[];
23
+ export declare const getNonDisabledItemsInRange: (state: TreeViewState<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>, itemAId: string, itemBId: string) => string[];
24
+ export declare const getAllNavigableItems: (state: TreeViewState<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>) => string[];
25
25
  /**
26
26
  * Checks if the target is in a descendant of this item.
27
27
  * This can prevent from firing some logic on the ancestors on the interacted item when the event handler is on the root.
@@ -1,7 +1,9 @@
1
- const getLastNavigableItemInArray = (instance, items) => {
1
+ import { selectorIsItemExpandable, selectorIsItemExpanded } from "../plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js";
2
+ import { selectorCanItemBeFocused, selectorIsItemDisabled, selectorItemIndex, selectorItemMeta, selectorItemOrderedChildrenIds, selectorItemParentId } from "../plugins/useTreeViewItems/useTreeViewItems.selectors.js";
3
+ const getLastNavigableItemInArray = (state, items) => {
2
4
  // Equivalent to Array.prototype.findLastIndex
3
5
  let itemIndex = items.length - 1;
4
- while (itemIndex >= 0 && !instance.isItemNavigable(items[itemIndex])) {
6
+ while (itemIndex >= 0 && !selectorCanItemBeFocused(state, items[itemIndex])) {
5
7
  itemIndex -= 1;
6
8
  }
7
9
  if (itemIndex === -1) {
@@ -9,10 +11,13 @@ const getLastNavigableItemInArray = (instance, items) => {
9
11
  }
10
12
  return items[itemIndex];
11
13
  };
12
- export const getPreviousNavigableItem = (instance, itemId) => {
13
- const itemMeta = instance.getItemMeta(itemId);
14
- const siblings = instance.getItemOrderedChildrenIds(itemMeta.parentId);
15
- const itemIndex = instance.getItemIndex(itemId);
14
+ export const getPreviousNavigableItem = (state, itemId) => {
15
+ const itemMeta = selectorItemMeta(state, itemId);
16
+ if (!itemMeta) {
17
+ return null;
18
+ }
19
+ const siblings = selectorItemOrderedChildrenIds(state, itemMeta.parentId);
20
+ const itemIndex = selectorItemIndex(state, itemId);
16
21
 
17
22
  // TODO: What should we do if the parent is not navigable?
18
23
  if (itemIndex === 0) {
@@ -21,7 +26,7 @@ export const getPreviousNavigableItem = (instance, itemId) => {
21
26
 
22
27
  // Finds the previous navigable sibling.
23
28
  let previousNavigableSiblingIndex = itemIndex - 1;
24
- while (!instance.isItemNavigable(siblings[previousNavigableSiblingIndex]) && previousNavigableSiblingIndex >= 0) {
29
+ while (!selectorCanItemBeFocused(state, siblings[previousNavigableSiblingIndex]) && previousNavigableSiblingIndex >= 0) {
25
30
  previousNavigableSiblingIndex -= 1;
26
31
  }
27
32
  if (previousNavigableSiblingIndex === -1) {
@@ -31,51 +36,51 @@ export const getPreviousNavigableItem = (instance, itemId) => {
31
36
  }
32
37
 
33
38
  // Otherwise, we can try to go up a level and find the previous navigable item.
34
- return getPreviousNavigableItem(instance, itemMeta.parentId);
39
+ return getPreviousNavigableItem(state, itemMeta.parentId);
35
40
  }
36
41
 
37
42
  // Finds the last navigable ancestor of the previous navigable sibling.
38
43
  let currentItemId = siblings[previousNavigableSiblingIndex];
39
- let lastNavigableChild = getLastNavigableItemInArray(instance, instance.getItemOrderedChildrenIds(currentItemId));
40
- while (instance.isItemExpanded(currentItemId) && lastNavigableChild != null) {
44
+ let lastNavigableChild = getLastNavigableItemInArray(state, selectorItemOrderedChildrenIds(state, currentItemId));
45
+ while (selectorIsItemExpanded(state, currentItemId) && lastNavigableChild != null) {
41
46
  currentItemId = lastNavigableChild;
42
- lastNavigableChild = instance.getItemOrderedChildrenIds(currentItemId).find(instance.isItemNavigable);
47
+ lastNavigableChild = selectorItemOrderedChildrenIds(state, currentItemId).find(childId => selectorCanItemBeFocused(state, childId));
43
48
  }
44
49
  return currentItemId;
45
50
  };
46
- export const getNextNavigableItem = (instance, itemId) => {
51
+ export const getNextNavigableItem = (state, itemId) => {
47
52
  // If the item is expanded and has some navigable children, return the first of them.
48
- if (instance.isItemExpanded(itemId)) {
49
- const firstNavigableChild = instance.getItemOrderedChildrenIds(itemId).find(instance.isItemNavigable);
53
+ if (selectorIsItemExpanded(state, itemId)) {
54
+ const firstNavigableChild = selectorItemOrderedChildrenIds(state, itemId).find(childId => selectorCanItemBeFocused(state, childId));
50
55
  if (firstNavigableChild != null) {
51
56
  return firstNavigableChild;
52
57
  }
53
58
  }
54
- let itemMeta = instance.getItemMeta(itemId);
59
+ let itemMeta = selectorItemMeta(state, itemId);
55
60
  while (itemMeta != null) {
56
61
  // Try to find the first navigable sibling after the current item.
57
- const siblings = instance.getItemOrderedChildrenIds(itemMeta.parentId);
58
- const currentItemIndex = instance.getItemIndex(itemMeta.id);
62
+ const siblings = selectorItemOrderedChildrenIds(state, itemMeta.parentId);
63
+ const currentItemIndex = selectorItemIndex(state, itemMeta.id);
59
64
  if (currentItemIndex < siblings.length - 1) {
60
65
  let nextItemIndex = currentItemIndex + 1;
61
- while (!instance.isItemNavigable(siblings[nextItemIndex]) && nextItemIndex < siblings.length - 1) {
66
+ while (!selectorCanItemBeFocused(state, siblings[nextItemIndex]) && nextItemIndex < siblings.length - 1) {
62
67
  nextItemIndex += 1;
63
68
  }
64
- if (instance.isItemNavigable(siblings[nextItemIndex])) {
69
+ if (selectorCanItemBeFocused(state, siblings[nextItemIndex])) {
65
70
  return siblings[nextItemIndex];
66
71
  }
67
72
  }
68
73
 
69
74
  // If the sibling does not exist, go up a level to the parent and try again.
70
- itemMeta = instance.getItemMeta(itemMeta.parentId);
75
+ itemMeta = selectorItemMeta(state, itemMeta.parentId);
71
76
  }
72
77
  return null;
73
78
  };
74
- export const getLastNavigableItem = instance => {
79
+ export const getLastNavigableItem = state => {
75
80
  let itemId = null;
76
- while (itemId == null || instance.isItemExpanded(itemId)) {
77
- const children = instance.getItemOrderedChildrenIds(itemId);
78
- const lastNavigableChild = getLastNavigableItemInArray(instance, children);
81
+ while (itemId == null || selectorIsItemExpanded(state, itemId)) {
82
+ const children = selectorItemOrderedChildrenIds(state, itemId);
83
+ const lastNavigableChild = getLastNavigableItemInArray(state, children);
79
84
 
80
85
  // The item has no navigable children.
81
86
  if (lastNavigableChild == null) {
@@ -85,7 +90,7 @@ export const getLastNavigableItem = instance => {
85
90
  }
86
91
  return itemId;
87
92
  };
88
- export const getFirstNavigableItem = instance => instance.getItemOrderedChildrenIds(null).find(instance.isItemNavigable);
93
+ export const getFirstNavigableItem = state => selectorItemOrderedChildrenIds(state, null).find(itemId => selectorCanItemBeFocused(state, itemId));
89
94
 
90
95
  /**
91
96
  * This is used to determine the start and end of a selection range so
@@ -101,12 +106,15 @@ export const getFirstNavigableItem = instance => instance.getItemOrderedChildren
101
106
  * Another way to put it is which item is shallower in a trémaux tree
102
107
  * https://en.wikipedia.org/wiki/Tr%C3%A9maux_tree
103
108
  */
104
- export const findOrderInTremauxTree = (instance, itemAId, itemBId) => {
109
+ export const findOrderInTremauxTree = (state, itemAId, itemBId) => {
105
110
  if (itemAId === itemBId) {
106
111
  return [itemAId, itemBId];
107
112
  }
108
- const itemMetaA = instance.getItemMeta(itemAId);
109
- const itemMetaB = instance.getItemMeta(itemBId);
113
+ const itemMetaA = selectorItemMeta(state, itemAId);
114
+ const itemMetaB = selectorItemMeta(state, itemBId);
115
+ if (!itemMetaA || !itemMetaB) {
116
+ return [itemAId, itemBId];
117
+ }
110
118
  if (itemMetaA.parentId === itemMetaB.id || itemMetaB.parentId === itemMetaA.id) {
111
119
  return itemMetaB.parentId === itemMetaA.id ? [itemMetaA.id, itemMetaB.id] : [itemMetaB.id, itemMetaA.id];
112
120
  }
@@ -124,7 +132,7 @@ export const findOrderInTremauxTree = (instance, itemAId, itemBId) => {
124
132
  aAncestorIsCommon = bFamily.indexOf(aAncestor) !== -1;
125
133
  continueA = aAncestor !== null;
126
134
  if (!aAncestorIsCommon && continueA) {
127
- aAncestor = instance.getItemMeta(aAncestor).parentId;
135
+ aAncestor = selectorItemParentId(state, aAncestor);
128
136
  }
129
137
  }
130
138
  if (continueB && !aAncestorIsCommon) {
@@ -132,53 +140,53 @@ export const findOrderInTremauxTree = (instance, itemAId, itemBId) => {
132
140
  bAncestorIsCommon = aFamily.indexOf(bAncestor) !== -1;
133
141
  continueB = bAncestor !== null;
134
142
  if (!bAncestorIsCommon && continueB) {
135
- bAncestor = instance.getItemMeta(bAncestor).parentId;
143
+ bAncestor = selectorItemParentId(state, bAncestor);
136
144
  }
137
145
  }
138
146
  }
139
147
  const commonAncestor = aAncestorIsCommon ? aAncestor : bAncestor;
140
- const ancestorFamily = instance.getItemOrderedChildrenIds(commonAncestor);
148
+ const ancestorFamily = selectorItemOrderedChildrenIds(state, commonAncestor);
141
149
  const aSide = aFamily[aFamily.indexOf(commonAncestor) - 1];
142
150
  const bSide = bFamily[bFamily.indexOf(commonAncestor) - 1];
143
151
  return ancestorFamily.indexOf(aSide) < ancestorFamily.indexOf(bSide) ? [itemAId, itemBId] : [itemBId, itemAId];
144
152
  };
145
- export const getNonDisabledItemsInRange = (instance, itemAId, itemBId) => {
153
+ export const getNonDisabledItemsInRange = (state, itemAId, itemBId) => {
146
154
  const getNextItem = itemId => {
147
155
  // If the item is expanded and has some children, return the first of them.
148
- if (instance.isItemExpandable(itemId) && instance.isItemExpanded(itemId)) {
149
- return instance.getItemOrderedChildrenIds(itemId)[0];
156
+ if (selectorIsItemExpandable(state, itemId) && selectorIsItemExpanded(state, itemId)) {
157
+ return selectorItemOrderedChildrenIds(state, itemId)[0];
150
158
  }
151
- let itemMeta = instance.getItemMeta(itemId);
159
+ let itemMeta = selectorItemMeta(state, itemId);
152
160
  while (itemMeta != null) {
153
161
  // Try to find the first navigable sibling after the current item.
154
- const siblings = instance.getItemOrderedChildrenIds(itemMeta.parentId);
155
- const currentItemIndex = instance.getItemIndex(itemMeta.id);
162
+ const siblings = selectorItemOrderedChildrenIds(state, itemMeta.parentId);
163
+ const currentItemIndex = selectorItemIndex(state, itemMeta.id);
156
164
  if (currentItemIndex < siblings.length - 1) {
157
165
  return siblings[currentItemIndex + 1];
158
166
  }
159
167
 
160
168
  // If the item is the last of its siblings, go up a level to the parent and try again.
161
- itemMeta = instance.getItemMeta(itemMeta.parentId);
169
+ itemMeta = itemMeta.parentId ? selectorItemMeta(state, itemMeta.parentId) : null;
162
170
  }
163
171
  throw new Error('Invalid range');
164
172
  };
165
- const [first, last] = findOrderInTremauxTree(instance, itemAId, itemBId);
173
+ const [first, last] = findOrderInTremauxTree(state, itemAId, itemBId);
166
174
  const items = [first];
167
175
  let current = first;
168
176
  while (current !== last) {
169
177
  current = getNextItem(current);
170
- if (!instance.isItemDisabled(current)) {
178
+ if (!selectorIsItemDisabled(state, current)) {
171
179
  items.push(current);
172
180
  }
173
181
  }
174
182
  return items;
175
183
  };
176
- export const getAllNavigableItems = instance => {
177
- let item = getFirstNavigableItem(instance);
184
+ export const getAllNavigableItems = state => {
185
+ let item = getFirstNavigableItem(state);
178
186
  const navigableItems = [];
179
187
  while (item != null) {
180
188
  navigableItems.push(item);
181
- item = getNextNavigableItem(instance, item);
189
+ item = getNextNavigableItem(state, item);
182
190
  }
183
191
  return navigableItems;
184
192
  };
package/models/items.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  export type TreeViewItemId = string;
2
- export type TreeViewBaseItem<R extends {} = {
2
+ export type TreeViewDefaultItemModelProperties = {
3
3
  id: string;
4
4
  label: string;
5
- }> = R & {
5
+ };
6
+ export type TreeViewBaseItem<R extends {} = TreeViewDefaultItemModelProperties> = R & {
6
7
  children?: TreeViewBaseItem<R>[];
7
8
  };
8
9
  export type TreeViewItemsReorderingAction = 'reorder-above' | 'reorder-below' | 'make-child' | 'move-to-parent';
@@ -56,8 +56,7 @@ const RichTreeView = /*#__PURE__*/React.forwardRef(function RichTreeView(inProps
56
56
  }
57
57
  const {
58
58
  getRootProps,
59
- contextValue,
60
- instance
59
+ contextValue
61
60
  } = useTreeView({
62
61
  plugins: RICH_TREE_VIEW_PLUGINS,
63
62
  rootRef: ref,
@@ -81,8 +80,7 @@ const RichTreeView = /*#__PURE__*/React.forwardRef(function RichTreeView(inProps
81
80
  children: /*#__PURE__*/_jsx(Root, _extends({}, rootProps, {
82
81
  children: /*#__PURE__*/_jsx(RichTreeViewItems, {
83
82
  slots: slots,
84
- slotProps: slotProps,
85
- itemsToRender: instance.getItemsToRender()
83
+ slotProps: slotProps
86
84
  })
87
85
  }))
88
86
  });
@@ -210,6 +210,7 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
210
210
  } = props,
211
211
  other = _objectWithoutPropertiesLoose(props, _excluded2);
212
212
  const {
213
+ getContextProviderProps,
213
214
  getRootProps,
214
215
  getContentProps,
215
216
  getIconContainerProps,
@@ -296,8 +297,7 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
296
297
  ownerState: {},
297
298
  className: classes.dragAndDropOverlay
298
299
  });
299
- return /*#__PURE__*/_jsx(TreeItemProvider, {
300
- itemId: itemId,
300
+ return /*#__PURE__*/_jsx(TreeItemProvider, _extends({}, getContextProviderProps(), {
301
301
  children: /*#__PURE__*/_jsxs(Root, _extends({}, rootProps, {
302
302
  children: [/*#__PURE__*/_jsxs(Content, _extends({}, contentProps, {
303
303
  children: [/*#__PURE__*/_jsx(IconContainer, _extends({}, iconContainerProps, {
@@ -311,7 +311,7 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
311
311
  as: GroupTransition
312
312
  }, groupTransitionProps))]
313
313
  }))
314
- });
314
+ }));
315
315
  });
316
316
  process.env.NODE_ENV !== "production" ? TreeItem.propTypes = {
317
317
  // ----------------------------- Warning --------------------------------
@@ -321,7 +321,7 @@ process.env.NODE_ENV !== "production" ? TreeItem.propTypes = {
321
321
  /**
322
322
  * The content of the component.
323
323
  */
324
- children: PropTypes.node,
324
+ children: PropTypes /* @typescript-to-proptypes-ignore */.any,
325
325
  /**
326
326
  * Override or extend the styles applied to the component.
327
327
  */
@@ -4,7 +4,7 @@ import _extends from "@babel/runtime/helpers/esm/extends";
4
4
  import * as React from 'react';
5
5
  import PropTypes from 'prop-types';
6
6
  import { alpha } from '@mui/material/styles';
7
- import { shouldForwardProp } from '@mui/system';
7
+ import { shouldForwardProp } from '@mui/system/createStyled';
8
8
  import { styled } from "../internals/zero-styled/index.js";
9
9
  import { jsx as _jsx } from "react/jsx-runtime";
10
10
  const TreeItemDragAndDropOverlayRoot = styled('div', {