@mui/x-tree-view 9.10.1 → 9.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +118 -0
- package/README.md +1 -11
- package/RichTreeView/RichTreeView.js +2 -0
- package/RichTreeView/RichTreeView.mjs +2 -0
- package/SimpleTreeView/SimpleTreeView.js +1 -0
- package/SimpleTreeView/SimpleTreeView.mjs +1 -0
- package/TreeItemIcon/TreeItemIcon.js +1 -0
- package/TreeItemIcon/TreeItemIcon.mjs +1 -0
- package/hooks/useTreeItemUtils/useTreeItemUtils.js +2 -0
- package/hooks/useTreeItemUtils/useTreeItemUtils.mjs +2 -0
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/internals/MinimalTreeViewStore/MinimalTreeViewStore.d.mts +1 -0
- package/internals/MinimalTreeViewStore/MinimalTreeViewStore.d.ts +1 -0
- package/internals/RichTreeViewStore/RichTreeViewStore.d.mts +8 -2
- package/internals/RichTreeViewStore/RichTreeViewStore.d.ts +8 -2
- package/internals/RichTreeViewStore/RichTreeViewStore.js +5 -2
- package/internals/RichTreeViewStore/RichTreeViewStore.mjs +5 -2
- package/internals/plugins/items/TreeViewItemsPlugin.d.mts +27 -0
- package/internals/plugins/items/TreeViewItemsPlugin.d.ts +27 -0
- package/internals/plugins/items/TreeViewItemsPlugin.js +81 -35
- package/internals/plugins/items/TreeViewItemsPlugin.mjs +82 -36
- package/internals/plugins/items/utils.d.mts +28 -0
- package/internals/plugins/items/utils.d.ts +28 -0
- package/internals/plugins/items/utils.js +49 -0
- package/internals/plugins/items/utils.mjs +48 -0
- package/internals/plugins/selection/TreeViewSelectionPlugin.d.mts +15 -0
- package/internals/plugins/selection/TreeViewSelectionPlugin.d.ts +15 -0
- package/internals/plugins/selection/TreeViewSelectionPlugin.js +50 -10
- package/internals/plugins/selection/TreeViewSelectionPlugin.mjs +50 -10
- package/internals/plugins/selection/itemPlugin.js +3 -37
- package/internals/plugins/selection/itemPlugin.mjs +4 -38
- package/internals/plugins/selection/selectors.d.mts +11 -0
- package/internals/plugins/selection/selectors.d.ts +11 -0
- package/internals/plugins/selection/selectors.js +56 -3
- package/internals/plugins/selection/selectors.mjs +56 -3
- package/models/items.d.mts +2 -1
- package/models/items.d.ts +2 -1
- package/package.json +3 -3
- package/useTreeItem/useTreeItem.types.d.mts +4 -0
- package/useTreeItem/useTreeItem.types.d.ts +4 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import _formatErrorMessage from "@mui/x-internals/formatErrorMessage";
|
|
1
2
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
3
|
import { idSelectors } from "../id/index.mjs";
|
|
3
4
|
import { itemsSelectors } from "./selectors.mjs";
|
|
4
|
-
import { buildItemsLookups, TREE_VIEW_ROOT_PARENT_ID } from "./utils.mjs";
|
|
5
|
+
import { buildItemsLookups, buildItemsLookupsRecursively, buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from "./utils.mjs";
|
|
5
6
|
export class TreeViewItemsPlugin {
|
|
6
7
|
// We can't type `store`, otherwise we get the following TS error:
|
|
7
8
|
// 'items' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
|
|
@@ -23,41 +24,13 @@ export class TreeViewItemsPlugin {
|
|
|
23
24
|
* Builds the state properties derived from the `items` prop.
|
|
24
25
|
*/
|
|
25
26
|
static buildItemsStateIfNeeded = parameters => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
metaLookup,
|
|
34
|
-
modelLookup,
|
|
35
|
-
orderedChildrenIds,
|
|
36
|
-
childrenIndexes,
|
|
37
|
-
itemsChildren
|
|
38
|
-
} = buildItemsLookups({
|
|
39
|
-
storeParameters: parameters,
|
|
40
|
-
items,
|
|
41
|
-
parentId,
|
|
42
|
-
depth,
|
|
43
|
-
isItemExpandable: (item, children) => !!children && children.length > 0,
|
|
44
|
-
otherItemsMetaLookup: itemMetaLookup
|
|
45
|
-
});
|
|
46
|
-
Object.assign(itemMetaLookup, metaLookup);
|
|
47
|
-
Object.assign(itemModelLookup, modelLookup);
|
|
48
|
-
itemOrderedChildrenIdsLookup[parentIdWithDefault] = orderedChildrenIds;
|
|
49
|
-
itemChildrenIndexesLookup[parentIdWithDefault] = childrenIndexes;
|
|
50
|
-
for (const item of itemsChildren) {
|
|
51
|
-
processSiblings(item.children || [], item.id, depth + 1);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
processSiblings(parameters.items, null, 0);
|
|
55
|
-
return {
|
|
56
|
-
itemMetaLookup,
|
|
57
|
-
itemModelLookup,
|
|
58
|
-
itemOrderedChildrenIdsLookup,
|
|
59
|
-
itemChildrenIndexesLookup
|
|
60
|
-
};
|
|
27
|
+
return buildItemsLookupsRecursively({
|
|
28
|
+
storeParameters: parameters,
|
|
29
|
+
items: parameters.items,
|
|
30
|
+
parentId: null,
|
|
31
|
+
depth: 0,
|
|
32
|
+
isItemExpandable: (item, children) => !!children && children.length > 0
|
|
33
|
+
});
|
|
61
34
|
};
|
|
62
35
|
|
|
63
36
|
/**
|
|
@@ -124,6 +97,79 @@ export class TreeViewItemsPlugin {
|
|
|
124
97
|
});
|
|
125
98
|
this.store.set('itemMetaLookup', itemMetaLookup);
|
|
126
99
|
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Add items to the tree.
|
|
103
|
+
* The items are added as children of the item with the given `parentId`, or at the root level if `parentId` is `null` or not defined.
|
|
104
|
+
* @param {AddItemsParameters<R>} parameters The items to add and their position in the tree.
|
|
105
|
+
*/
|
|
106
|
+
addItems = ({
|
|
107
|
+
items,
|
|
108
|
+
parentId = null,
|
|
109
|
+
index
|
|
110
|
+
}) => {
|
|
111
|
+
if (items.length === 0) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (parentId != null && itemsSelectors.itemMeta(this.store.state, parentId) == null) {
|
|
115
|
+
throw new Error(process.env.NODE_ENV !== "production" ? `MUI X Tree View: Unable to add items to the parent with id "${parentId}" because it is not present in the tree. ` + 'Pass the id of an existing item, or `null` to add the items at the root level.' : _formatErrorMessage(295, parentId));
|
|
116
|
+
}
|
|
117
|
+
const parentDepth = parentId == null ? -1 : itemsSelectors.itemDepth(this.store.state, parentId);
|
|
118
|
+
|
|
119
|
+
// When the items are lazy loaded, an item can be expandable even if its children are not loaded yet.
|
|
120
|
+
const dataSource = this.store.parameters.dataSource;
|
|
121
|
+
const isItemExpandable = (item, children) => {
|
|
122
|
+
if (children != null && children.length > 0) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return dataSource == null ? false : dataSource.getChildrenCount(item) !== 0;
|
|
126
|
+
};
|
|
127
|
+
const {
|
|
128
|
+
itemMetaLookup: metaLookup,
|
|
129
|
+
itemModelLookup: modelLookup,
|
|
130
|
+
itemOrderedChildrenIdsLookup: orderedChildrenIdsLookup,
|
|
131
|
+
itemChildrenIndexesLookup: childrenIndexesLookup
|
|
132
|
+
} = buildItemsLookupsRecursively({
|
|
133
|
+
storeParameters: this.store.parameters,
|
|
134
|
+
items,
|
|
135
|
+
parentId,
|
|
136
|
+
depth: parentDepth + 1,
|
|
137
|
+
isItemExpandable,
|
|
138
|
+
existingItemMetaLookup: this.store.state.itemMetaLookup
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// `buildItemsLookups` allows an id to be re-used by an item with the same parent,
|
|
142
|
+
// which is only valid when rebuilding the state from the `items` prop.
|
|
143
|
+
for (const id of Object.keys(metaLookup)) {
|
|
144
|
+
if (this.store.state.itemMetaLookup[id] != null) {
|
|
145
|
+
throw new Error(process.env.NODE_ENV !== "production" ? `MUI X Tree View: All items must have a unique \`id\` property. ` + `The id "${id}" is used by multiple items. ` + 'Use the `getItemId` prop to specify a custom id for each item if needed.' : _formatErrorMessage(194, id));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const parentIdWithDefault = parentId ?? TREE_VIEW_ROOT_PARENT_ID;
|
|
149
|
+
const existingChildrenIds = itemsSelectors.itemOrderedChildrenIds(this.store.state, parentId);
|
|
150
|
+
const insertionIndex = index ?? existingChildrenIds.length;
|
|
151
|
+
if (insertionIndex < 0 || insertionIndex > existingChildrenIds.length) {
|
|
152
|
+
throw new Error(process.env.NODE_ENV !== "production" ? `MUI X Tree View: Unable to add items at index "${insertionIndex}" because it is out of range. ` + `The index must be between 0 and the amount of children of the parent item (${existingChildrenIds.length}).` : _formatErrorMessage(296, insertionIndex, existingChildrenIds.length));
|
|
153
|
+
}
|
|
154
|
+
const newChildrenIds = orderedChildrenIdsLookup[parentIdWithDefault];
|
|
155
|
+
const mergedChildrenIds = [...existingChildrenIds];
|
|
156
|
+
mergedChildrenIds.splice(insertionIndex, 0, ...newChildrenIds);
|
|
157
|
+
orderedChildrenIdsLookup[parentIdWithDefault] = mergedChildrenIds;
|
|
158
|
+
childrenIndexesLookup[parentIdWithDefault] = buildSiblingIndexes(mergedChildrenIds);
|
|
159
|
+
const newMetaLookup = _extends({}, this.store.state.itemMetaLookup, metaLookup);
|
|
160
|
+
if (parentId != null && !newMetaLookup[parentId].expandable) {
|
|
161
|
+
newMetaLookup[parentId] = _extends({}, newMetaLookup[parentId], {
|
|
162
|
+
expandable: true
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
this.store.update({
|
|
166
|
+
itemMetaLookup: newMetaLookup,
|
|
167
|
+
itemModelLookup: _extends({}, this.store.state.itemModelLookup, modelLookup),
|
|
168
|
+
itemOrderedChildrenIdsLookup: _extends({}, this.store.state.itemOrderedChildrenIdsLookup, orderedChildrenIdsLookup),
|
|
169
|
+
itemChildrenIndexesLookup: _extends({}, this.store.state.itemChildrenIndexesLookup, childrenIndexesLookup)
|
|
170
|
+
});
|
|
171
|
+
this.store.selection.propagateSelectionToNewItems(parentId, newChildrenIds);
|
|
172
|
+
};
|
|
127
173
|
buildPublicAPI = () => {
|
|
128
174
|
return {
|
|
129
175
|
getItem: this.getItem,
|
|
@@ -30,6 +30,34 @@ export declare function buildItemsLookups<R extends TreeViewValidItem<R>>(parame
|
|
|
30
30
|
children: R[];
|
|
31
31
|
}[];
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Builds the items lookups for a tree of items, recursing into the children of each item.
|
|
35
|
+
* The returned lookups only contain the items passed to this method.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildItemsLookupsRecursively<R extends TreeViewValidItem<R>>(parameters: BuildItemsLookupsRecursivelyParameters<R>): {
|
|
38
|
+
itemMetaLookup: {
|
|
39
|
+
[itemId: string]: TreeViewItemMeta;
|
|
40
|
+
};
|
|
41
|
+
itemModelLookup: {
|
|
42
|
+
[itemId: string]: R;
|
|
43
|
+
};
|
|
44
|
+
itemOrderedChildrenIdsLookup: {
|
|
45
|
+
[parentItemId: string]: string[];
|
|
46
|
+
};
|
|
47
|
+
itemChildrenIndexesLookup: {
|
|
48
|
+
[parentItemId: string]: {
|
|
49
|
+
[itemId: string]: number;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
interface BuildItemsLookupsRecursivelyParameters<R extends TreeViewValidItem<R>> extends Omit<BuildItemsLookupsParameters<R>, 'otherItemsMetaLookup'> {
|
|
54
|
+
/**
|
|
55
|
+
* The meta of the items already present in the tree, used to detect duplicated ids.
|
|
56
|
+
*/
|
|
57
|
+
existingItemMetaLookup?: {
|
|
58
|
+
[itemId: string]: TreeViewItemMeta;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
33
61
|
interface BuildItemsLookupsParameters<R extends TreeViewValidItem<R>> {
|
|
34
62
|
items: readonly R[];
|
|
35
63
|
storeParameters: Pick<MinimalTreeViewParameters<R, any>, 'getItemId' | 'getItemLabel' | 'getItemChildren' | 'isItemDisabled' | 'isItemSelectionDisabled'>;
|
|
@@ -30,6 +30,34 @@ export declare function buildItemsLookups<R extends TreeViewValidItem<R>>(parame
|
|
|
30
30
|
children: R[];
|
|
31
31
|
}[];
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Builds the items lookups for a tree of items, recursing into the children of each item.
|
|
35
|
+
* The returned lookups only contain the items passed to this method.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildItemsLookupsRecursively<R extends TreeViewValidItem<R>>(parameters: BuildItemsLookupsRecursivelyParameters<R>): {
|
|
38
|
+
itemMetaLookup: {
|
|
39
|
+
[itemId: string]: TreeViewItemMeta;
|
|
40
|
+
};
|
|
41
|
+
itemModelLookup: {
|
|
42
|
+
[itemId: string]: R;
|
|
43
|
+
};
|
|
44
|
+
itemOrderedChildrenIdsLookup: {
|
|
45
|
+
[parentItemId: string]: string[];
|
|
46
|
+
};
|
|
47
|
+
itemChildrenIndexesLookup: {
|
|
48
|
+
[parentItemId: string]: {
|
|
49
|
+
[itemId: string]: number;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
interface BuildItemsLookupsRecursivelyParameters<R extends TreeViewValidItem<R>> extends Omit<BuildItemsLookupsParameters<R>, 'otherItemsMetaLookup'> {
|
|
54
|
+
/**
|
|
55
|
+
* The meta of the items already present in the tree, used to detect duplicated ids.
|
|
56
|
+
*/
|
|
57
|
+
existingItemMetaLookup?: {
|
|
58
|
+
[itemId: string]: TreeViewItemMeta;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
33
61
|
interface BuildItemsLookupsParameters<R extends TreeViewValidItem<R>> {
|
|
34
62
|
items: readonly R[];
|
|
35
63
|
storeParameters: Pick<MinimalTreeViewParameters<R, any>, 'getItemId' | 'getItemLabel' | 'getItemChildren' | 'isItemDisabled' | 'isItemSelectionDisabled'>;
|
|
@@ -6,7 +6,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.TREE_VIEW_ROOT_PARENT_ID = void 0;
|
|
8
8
|
exports.buildItemsLookups = buildItemsLookups;
|
|
9
|
+
exports.buildItemsLookupsRecursively = buildItemsLookupsRecursively;
|
|
9
10
|
exports.isItemDisabled = exports.buildSiblingIndexes = void 0;
|
|
11
|
+
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
10
12
|
var _formatErrorMessage2 = _interopRequireDefault(require("@mui/x-internals/formatErrorMessage"));
|
|
11
13
|
const TREE_VIEW_ROOT_PARENT_ID = exports.TREE_VIEW_ROOT_PARENT_ID = '__TREE_VIEW_ROOT_PARENT_ID__';
|
|
12
14
|
const buildSiblingIndexes = siblings => {
|
|
@@ -104,6 +106,53 @@ function buildItemsLookups(parameters) {
|
|
|
104
106
|
itemsChildren
|
|
105
107
|
};
|
|
106
108
|
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Builds the items lookups for a tree of items, recursing into the children of each item.
|
|
112
|
+
* The returned lookups only contain the items passed to this method.
|
|
113
|
+
*/
|
|
114
|
+
function buildItemsLookupsRecursively(parameters) {
|
|
115
|
+
const {
|
|
116
|
+
storeParameters,
|
|
117
|
+
items,
|
|
118
|
+
parentId,
|
|
119
|
+
depth,
|
|
120
|
+
isItemExpandable,
|
|
121
|
+
existingItemMetaLookup
|
|
122
|
+
} = parameters;
|
|
123
|
+
const itemMetaLookup = {};
|
|
124
|
+
const itemModelLookup = {};
|
|
125
|
+
const itemOrderedChildrenIdsLookup = {};
|
|
126
|
+
const itemChildrenIndexesLookup = {};
|
|
127
|
+
|
|
128
|
+
// Both the existing items and the ones processed here, to detect duplicated ids.
|
|
129
|
+
const otherItemsMetaLookup = (0, _extends2.default)({}, existingItemMetaLookup);
|
|
130
|
+
const processSiblings = (siblings, siblingsParentId, siblingsDepth) => {
|
|
131
|
+
const lookups = buildItemsLookups({
|
|
132
|
+
storeParameters,
|
|
133
|
+
items: siblings,
|
|
134
|
+
parentId: siblingsParentId,
|
|
135
|
+
depth: siblingsDepth,
|
|
136
|
+
isItemExpandable,
|
|
137
|
+
otherItemsMetaLookup
|
|
138
|
+
});
|
|
139
|
+
Object.assign(itemMetaLookup, lookups.metaLookup);
|
|
140
|
+
Object.assign(otherItemsMetaLookup, lookups.metaLookup);
|
|
141
|
+
Object.assign(itemModelLookup, lookups.modelLookup);
|
|
142
|
+
itemOrderedChildrenIdsLookup[siblingsParentId ?? TREE_VIEW_ROOT_PARENT_ID] = lookups.orderedChildrenIds;
|
|
143
|
+
itemChildrenIndexesLookup[siblingsParentId ?? TREE_VIEW_ROOT_PARENT_ID] = lookups.childrenIndexes;
|
|
144
|
+
for (const item of lookups.itemsChildren) {
|
|
145
|
+
processSiblings(item.children, item.id, siblingsDepth + 1);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
processSiblings(items, parentId, depth);
|
|
149
|
+
return {
|
|
150
|
+
itemMetaLookup,
|
|
151
|
+
itemModelLookup,
|
|
152
|
+
itemOrderedChildrenIdsLookup,
|
|
153
|
+
itemChildrenIndexesLookup
|
|
154
|
+
};
|
|
155
|
+
}
|
|
107
156
|
function checkId({
|
|
108
157
|
id,
|
|
109
158
|
parentId,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
1
2
|
import _formatErrorMessage from "@mui/x-internals/formatErrorMessage";
|
|
2
3
|
export const TREE_VIEW_ROOT_PARENT_ID = '__TREE_VIEW_ROOT_PARENT_ID__';
|
|
3
4
|
export const buildSiblingIndexes = siblings => {
|
|
@@ -93,6 +94,53 @@ export function buildItemsLookups(parameters) {
|
|
|
93
94
|
itemsChildren
|
|
94
95
|
};
|
|
95
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Builds the items lookups for a tree of items, recursing into the children of each item.
|
|
100
|
+
* The returned lookups only contain the items passed to this method.
|
|
101
|
+
*/
|
|
102
|
+
export function buildItemsLookupsRecursively(parameters) {
|
|
103
|
+
const {
|
|
104
|
+
storeParameters,
|
|
105
|
+
items,
|
|
106
|
+
parentId,
|
|
107
|
+
depth,
|
|
108
|
+
isItemExpandable,
|
|
109
|
+
existingItemMetaLookup
|
|
110
|
+
} = parameters;
|
|
111
|
+
const itemMetaLookup = {};
|
|
112
|
+
const itemModelLookup = {};
|
|
113
|
+
const itemOrderedChildrenIdsLookup = {};
|
|
114
|
+
const itemChildrenIndexesLookup = {};
|
|
115
|
+
|
|
116
|
+
// Both the existing items and the ones processed here, to detect duplicated ids.
|
|
117
|
+
const otherItemsMetaLookup = _extends({}, existingItemMetaLookup);
|
|
118
|
+
const processSiblings = (siblings, siblingsParentId, siblingsDepth) => {
|
|
119
|
+
const lookups = buildItemsLookups({
|
|
120
|
+
storeParameters,
|
|
121
|
+
items: siblings,
|
|
122
|
+
parentId: siblingsParentId,
|
|
123
|
+
depth: siblingsDepth,
|
|
124
|
+
isItemExpandable,
|
|
125
|
+
otherItemsMetaLookup
|
|
126
|
+
});
|
|
127
|
+
Object.assign(itemMetaLookup, lookups.metaLookup);
|
|
128
|
+
Object.assign(otherItemsMetaLookup, lookups.metaLookup);
|
|
129
|
+
Object.assign(itemModelLookup, lookups.modelLookup);
|
|
130
|
+
itemOrderedChildrenIdsLookup[siblingsParentId ?? TREE_VIEW_ROOT_PARENT_ID] = lookups.orderedChildrenIds;
|
|
131
|
+
itemChildrenIndexesLookup[siblingsParentId ?? TREE_VIEW_ROOT_PARENT_ID] = lookups.childrenIndexes;
|
|
132
|
+
for (const item of lookups.itemsChildren) {
|
|
133
|
+
processSiblings(item.children, item.id, siblingsDepth + 1);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
processSiblings(items, parentId, depth);
|
|
137
|
+
return {
|
|
138
|
+
itemMetaLookup,
|
|
139
|
+
itemModelLookup,
|
|
140
|
+
itemOrderedChildrenIdsLookup,
|
|
141
|
+
itemChildrenIndexesLookup
|
|
142
|
+
};
|
|
143
|
+
}
|
|
96
144
|
function checkId({
|
|
97
145
|
id,
|
|
98
146
|
parentId,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TreeViewItemId, TreeViewItemSelectionStatus } from "../../../models/index.mjs";
|
|
1
2
|
export declare class TreeViewSelectionPlugin<Multiple extends boolean | undefined> {
|
|
2
3
|
private store;
|
|
3
4
|
private lastSelectedItem;
|
|
@@ -5,7 +6,15 @@ export declare class TreeViewSelectionPlugin<Multiple extends boolean | undefine
|
|
|
5
6
|
constructor(store: any);
|
|
6
7
|
private setSelectedItems;
|
|
7
8
|
private selectRange;
|
|
9
|
+
/**
|
|
10
|
+
* Get the selection status of an item.
|
|
11
|
+
* An item that is not selected is `indeterminate` when some of its selectable descendants are selected.
|
|
12
|
+
* @param {TreeViewItemId} itemId The id of the item to get the selection status of.
|
|
13
|
+
* @returns {TreeViewItemSelectionStatus} The selection status of the item.
|
|
14
|
+
*/
|
|
15
|
+
private getItemSelection;
|
|
8
16
|
buildPublicAPI: () => {
|
|
17
|
+
getItemSelection: (itemId: TreeViewItemId) => TreeViewItemSelectionStatus;
|
|
9
18
|
setItemSelection: ({
|
|
10
19
|
itemId,
|
|
11
20
|
event,
|
|
@@ -18,6 +27,12 @@ export declare class TreeViewSelectionPlugin<Multiple extends boolean | undefine
|
|
|
18
27
|
keepExistingSelection?: boolean;
|
|
19
28
|
}) => void;
|
|
20
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Select the items added below a selected parent when the selection propagates to the descendants.
|
|
32
|
+
* @param {TreeViewItemId | null} parentId The id of the item the new items were added to.
|
|
33
|
+
* @param {TreeViewItemId[]} newItemIds The ids of the items that were just added.
|
|
34
|
+
*/
|
|
35
|
+
propagateSelectionToNewItems: (parentId: TreeViewItemId | null, newItemIds: TreeViewItemId[]) => void;
|
|
21
36
|
/**
|
|
22
37
|
* Select or deselect an item.
|
|
23
38
|
* @param {object} parameters The parameters of the method.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TreeViewItemId, TreeViewItemSelectionStatus } from "../../../models/index.js";
|
|
1
2
|
export declare class TreeViewSelectionPlugin<Multiple extends boolean | undefined> {
|
|
2
3
|
private store;
|
|
3
4
|
private lastSelectedItem;
|
|
@@ -5,7 +6,15 @@ export declare class TreeViewSelectionPlugin<Multiple extends boolean | undefine
|
|
|
5
6
|
constructor(store: any);
|
|
6
7
|
private setSelectedItems;
|
|
7
8
|
private selectRange;
|
|
9
|
+
/**
|
|
10
|
+
* Get the selection status of an item.
|
|
11
|
+
* An item that is not selected is `indeterminate` when some of its selectable descendants are selected.
|
|
12
|
+
* @param {TreeViewItemId} itemId The id of the item to get the selection status of.
|
|
13
|
+
* @returns {TreeViewItemSelectionStatus} The selection status of the item.
|
|
14
|
+
*/
|
|
15
|
+
private getItemSelection;
|
|
8
16
|
buildPublicAPI: () => {
|
|
17
|
+
getItemSelection: (itemId: TreeViewItemId) => TreeViewItemSelectionStatus;
|
|
9
18
|
setItemSelection: ({
|
|
10
19
|
itemId,
|
|
11
20
|
event,
|
|
@@ -18,6 +27,12 @@ export declare class TreeViewSelectionPlugin<Multiple extends boolean | undefine
|
|
|
18
27
|
keepExistingSelection?: boolean;
|
|
19
28
|
}) => void;
|
|
20
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Select the items added below a selected parent when the selection propagates to the descendants.
|
|
32
|
+
* @param {TreeViewItemId | null} parentId The id of the item the new items were added to.
|
|
33
|
+
* @param {TreeViewItemId[]} newItemIds The ids of the items that were just added.
|
|
34
|
+
*/
|
|
35
|
+
propagateSelectionToNewItems: (parentId: TreeViewItemId | null, newItemIds: TreeViewItemId[]) => void;
|
|
21
36
|
/**
|
|
22
37
|
* Select or deselect an item.
|
|
23
38
|
* @param {object} parameters The parameters of the method.
|
|
@@ -41,10 +41,16 @@ class TreeViewSelectionPlugin {
|
|
|
41
41
|
} else {
|
|
42
42
|
cleanModel = newModel;
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
// The store is updated before the callbacks are fired,
|
|
46
|
+
// so that the selection selectors and the `getItemSelection` API method
|
|
47
|
+
// return the new selection status when called from `onItemSelectionToggle` or `onSelectedItemsChange`.
|
|
48
|
+
if (selectedItems === undefined) {
|
|
49
|
+
this.store.set('selectedItems', cleanModel);
|
|
50
|
+
}
|
|
44
51
|
if (onItemSelectionToggle) {
|
|
45
52
|
if (isMultiSelectEnabled) {
|
|
46
53
|
const changes = getAddedAndRemovedItems({
|
|
47
|
-
store: this.store,
|
|
48
54
|
newModel: cleanModel,
|
|
49
55
|
oldModel: oldModel
|
|
50
56
|
});
|
|
@@ -65,9 +71,6 @@ class TreeViewSelectionPlugin {
|
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
|
-
if (selectedItems === undefined) {
|
|
69
|
-
this.store.set('selectedItems', cleanModel);
|
|
70
|
-
}
|
|
71
74
|
onSelectedItemsChange?.(event, cleanModel);
|
|
72
75
|
};
|
|
73
76
|
selectRange = (event, [start, end]) => {
|
|
@@ -91,12 +94,39 @@ class TreeViewSelectionPlugin {
|
|
|
91
94
|
this.setSelectedItems(event, newSelectedItems);
|
|
92
95
|
this.lastSelectedRange = getLookupFromArray(range);
|
|
93
96
|
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get the selection status of an item.
|
|
100
|
+
* An item that is not selected is `indeterminate` when some of its selectable descendants are selected.
|
|
101
|
+
* @param {TreeViewItemId} itemId The id of the item to get the selection status of.
|
|
102
|
+
* @returns {TreeViewItemSelectionStatus} The selection status of the item.
|
|
103
|
+
*/
|
|
104
|
+
getItemSelection = itemId => _selectors.selectionSelectors.itemSelectionStatus(this.store.state, itemId);
|
|
94
105
|
buildPublicAPI = () => {
|
|
95
106
|
return {
|
|
107
|
+
getItemSelection: this.getItemSelection,
|
|
96
108
|
setItemSelection: this.setItemSelection
|
|
97
109
|
};
|
|
98
110
|
};
|
|
99
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Select the items added below a selected parent when the selection propagates to the descendants.
|
|
114
|
+
* @param {TreeViewItemId | null} parentId The id of the item the new items were added to.
|
|
115
|
+
* @param {TreeViewItemId[]} newItemIds The ids of the items that were just added.
|
|
116
|
+
*/
|
|
117
|
+
propagateSelectionToNewItems = (parentId, newItemIds) => {
|
|
118
|
+
const {
|
|
119
|
+
selectionPropagation = _empty.EMPTY_OBJECT
|
|
120
|
+
} = this.store.parameters;
|
|
121
|
+
if (parentId == null || newItemIds.length === 0 || !selectionPropagation.descendants || !_selectors.selectionSelectors.isMultiSelectEnabled(this.store.state) || !_selectors.selectionSelectors.isItemSelected(this.store.state, parentId)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Only propagate to the new items, the rest of the parent's subtree is already up to date.
|
|
126
|
+
const newModel = _selectors.selectionSelectors.selectedItems(this.store.state).concat(newItemIds);
|
|
127
|
+
this.setSelectedItems(null, newModel, newItemIds);
|
|
128
|
+
};
|
|
129
|
+
|
|
100
130
|
/**
|
|
101
131
|
* Select or deselect an item.
|
|
102
132
|
* @param {object} parameters The parameters of the method.
|
|
@@ -116,7 +146,7 @@ class TreeViewSelectionPlugin {
|
|
|
116
146
|
}
|
|
117
147
|
let newSelected;
|
|
118
148
|
const isMultiSelectEnabled = _selectors.selectionSelectors.isMultiSelectEnabled(this.store.state);
|
|
119
|
-
if (keepExistingSelection) {
|
|
149
|
+
if (keepExistingSelection && isMultiSelectEnabled) {
|
|
120
150
|
const oldSelected = _selectors.selectionSelectors.selectedItems(this.store.state);
|
|
121
151
|
const isSelectedBefore = _selectors.selectionSelectors.isItemSelected(this.store.state, itemId);
|
|
122
152
|
if (isSelectedBefore && (shouldBeSelected === false || shouldBeSelected == null)) {
|
|
@@ -199,7 +229,9 @@ class TreeViewSelectionPlugin {
|
|
|
199
229
|
}
|
|
200
230
|
let newSelectedItems = _selectors.selectionSelectors.selectedItems(this.store.state).slice();
|
|
201
231
|
if (Object.keys(this.lastSelectedRange).length === 0) {
|
|
202
|
-
|
|
232
|
+
if (!_selectors.selectionSelectors.isItemSelected(this.store.state, nextItem)) {
|
|
233
|
+
newSelectedItems.push(nextItem);
|
|
234
|
+
}
|
|
203
235
|
this.lastSelectedRange = {
|
|
204
236
|
[currentItem]: true,
|
|
205
237
|
[nextItem]: true
|
|
@@ -212,7 +244,9 @@ class TreeViewSelectionPlugin {
|
|
|
212
244
|
newSelectedItems = newSelectedItems.filter(id => id !== currentItem);
|
|
213
245
|
delete this.lastSelectedRange[currentItem];
|
|
214
246
|
} else {
|
|
215
|
-
|
|
247
|
+
if (!_selectors.selectionSelectors.isItemSelected(this.store.state, nextItem)) {
|
|
248
|
+
newSelectedItems.push(nextItem);
|
|
249
|
+
}
|
|
216
250
|
this.lastSelectedRange[nextItem] = true;
|
|
217
251
|
}
|
|
218
252
|
}
|
|
@@ -233,7 +267,6 @@ function propagateSelection({
|
|
|
233
267
|
let shouldRegenerateModel = false;
|
|
234
268
|
const newModelLookup = getLookupFromArray(newModel);
|
|
235
269
|
const changes = getAddedAndRemovedItems({
|
|
236
|
-
store,
|
|
237
270
|
newModel,
|
|
238
271
|
oldModel
|
|
239
272
|
});
|
|
@@ -313,8 +346,11 @@ function propagateSelection({
|
|
|
313
346
|
});
|
|
314
347
|
return shouldRegenerateModel ? Object.keys(newModelLookup) : newModel;
|
|
315
348
|
}
|
|
349
|
+
|
|
350
|
+
// This method only diffs the two models it receives,
|
|
351
|
+
// it must not read the selection from the store,
|
|
352
|
+
// otherwise the result would depend on whether the store has already been updated or not.
|
|
316
353
|
function getAddedAndRemovedItems({
|
|
317
|
-
store,
|
|
318
354
|
oldModel,
|
|
319
355
|
newModel
|
|
320
356
|
}) {
|
|
@@ -322,8 +358,12 @@ function getAddedAndRemovedItems({
|
|
|
322
358
|
newModel.forEach(id => {
|
|
323
359
|
newModelMap.set(id, true);
|
|
324
360
|
});
|
|
361
|
+
const oldModelMap = new Map();
|
|
362
|
+
oldModel.forEach(id => {
|
|
363
|
+
oldModelMap.set(id, true);
|
|
364
|
+
});
|
|
325
365
|
return {
|
|
326
|
-
added: newModel.filter(itemId => !
|
|
366
|
+
added: newModel.filter(itemId => !oldModelMap.has(itemId)),
|
|
327
367
|
removed: oldModel.filter(itemId => !newModelMap.has(itemId))
|
|
328
368
|
};
|
|
329
369
|
}
|
|
@@ -34,10 +34,16 @@ export class TreeViewSelectionPlugin {
|
|
|
34
34
|
} else {
|
|
35
35
|
cleanModel = newModel;
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
// The store is updated before the callbacks are fired,
|
|
39
|
+
// so that the selection selectors and the `getItemSelection` API method
|
|
40
|
+
// return the new selection status when called from `onItemSelectionToggle` or `onSelectedItemsChange`.
|
|
41
|
+
if (selectedItems === undefined) {
|
|
42
|
+
this.store.set('selectedItems', cleanModel);
|
|
43
|
+
}
|
|
37
44
|
if (onItemSelectionToggle) {
|
|
38
45
|
if (isMultiSelectEnabled) {
|
|
39
46
|
const changes = getAddedAndRemovedItems({
|
|
40
|
-
store: this.store,
|
|
41
47
|
newModel: cleanModel,
|
|
42
48
|
oldModel: oldModel
|
|
43
49
|
});
|
|
@@ -58,9 +64,6 @@ export class TreeViewSelectionPlugin {
|
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
|
-
if (selectedItems === undefined) {
|
|
62
|
-
this.store.set('selectedItems', cleanModel);
|
|
63
|
-
}
|
|
64
67
|
onSelectedItemsChange?.(event, cleanModel);
|
|
65
68
|
};
|
|
66
69
|
selectRange = (event, [start, end]) => {
|
|
@@ -84,12 +87,39 @@ export class TreeViewSelectionPlugin {
|
|
|
84
87
|
this.setSelectedItems(event, newSelectedItems);
|
|
85
88
|
this.lastSelectedRange = getLookupFromArray(range);
|
|
86
89
|
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get the selection status of an item.
|
|
93
|
+
* An item that is not selected is `indeterminate` when some of its selectable descendants are selected.
|
|
94
|
+
* @param {TreeViewItemId} itemId The id of the item to get the selection status of.
|
|
95
|
+
* @returns {TreeViewItemSelectionStatus} The selection status of the item.
|
|
96
|
+
*/
|
|
97
|
+
getItemSelection = itemId => selectionSelectors.itemSelectionStatus(this.store.state, itemId);
|
|
87
98
|
buildPublicAPI = () => {
|
|
88
99
|
return {
|
|
100
|
+
getItemSelection: this.getItemSelection,
|
|
89
101
|
setItemSelection: this.setItemSelection
|
|
90
102
|
};
|
|
91
103
|
};
|
|
92
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Select the items added below a selected parent when the selection propagates to the descendants.
|
|
107
|
+
* @param {TreeViewItemId | null} parentId The id of the item the new items were added to.
|
|
108
|
+
* @param {TreeViewItemId[]} newItemIds The ids of the items that were just added.
|
|
109
|
+
*/
|
|
110
|
+
propagateSelectionToNewItems = (parentId, newItemIds) => {
|
|
111
|
+
const {
|
|
112
|
+
selectionPropagation = EMPTY_OBJECT
|
|
113
|
+
} = this.store.parameters;
|
|
114
|
+
if (parentId == null || newItemIds.length === 0 || !selectionPropagation.descendants || !selectionSelectors.isMultiSelectEnabled(this.store.state) || !selectionSelectors.isItemSelected(this.store.state, parentId)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Only propagate to the new items, the rest of the parent's subtree is already up to date.
|
|
119
|
+
const newModel = selectionSelectors.selectedItems(this.store.state).concat(newItemIds);
|
|
120
|
+
this.setSelectedItems(null, newModel, newItemIds);
|
|
121
|
+
};
|
|
122
|
+
|
|
93
123
|
/**
|
|
94
124
|
* Select or deselect an item.
|
|
95
125
|
* @param {object} parameters The parameters of the method.
|
|
@@ -109,7 +139,7 @@ export class TreeViewSelectionPlugin {
|
|
|
109
139
|
}
|
|
110
140
|
let newSelected;
|
|
111
141
|
const isMultiSelectEnabled = selectionSelectors.isMultiSelectEnabled(this.store.state);
|
|
112
|
-
if (keepExistingSelection) {
|
|
142
|
+
if (keepExistingSelection && isMultiSelectEnabled) {
|
|
113
143
|
const oldSelected = selectionSelectors.selectedItems(this.store.state);
|
|
114
144
|
const isSelectedBefore = selectionSelectors.isItemSelected(this.store.state, itemId);
|
|
115
145
|
if (isSelectedBefore && (shouldBeSelected === false || shouldBeSelected == null)) {
|
|
@@ -192,7 +222,9 @@ export class TreeViewSelectionPlugin {
|
|
|
192
222
|
}
|
|
193
223
|
let newSelectedItems = selectionSelectors.selectedItems(this.store.state).slice();
|
|
194
224
|
if (Object.keys(this.lastSelectedRange).length === 0) {
|
|
195
|
-
|
|
225
|
+
if (!selectionSelectors.isItemSelected(this.store.state, nextItem)) {
|
|
226
|
+
newSelectedItems.push(nextItem);
|
|
227
|
+
}
|
|
196
228
|
this.lastSelectedRange = {
|
|
197
229
|
[currentItem]: true,
|
|
198
230
|
[nextItem]: true
|
|
@@ -205,7 +237,9 @@ export class TreeViewSelectionPlugin {
|
|
|
205
237
|
newSelectedItems = newSelectedItems.filter(id => id !== currentItem);
|
|
206
238
|
delete this.lastSelectedRange[currentItem];
|
|
207
239
|
} else {
|
|
208
|
-
|
|
240
|
+
if (!selectionSelectors.isItemSelected(this.store.state, nextItem)) {
|
|
241
|
+
newSelectedItems.push(nextItem);
|
|
242
|
+
}
|
|
209
243
|
this.lastSelectedRange[nextItem] = true;
|
|
210
244
|
}
|
|
211
245
|
}
|
|
@@ -225,7 +259,6 @@ function propagateSelection({
|
|
|
225
259
|
let shouldRegenerateModel = false;
|
|
226
260
|
const newModelLookup = getLookupFromArray(newModel);
|
|
227
261
|
const changes = getAddedAndRemovedItems({
|
|
228
|
-
store,
|
|
229
262
|
newModel,
|
|
230
263
|
oldModel
|
|
231
264
|
});
|
|
@@ -305,8 +338,11 @@ function propagateSelection({
|
|
|
305
338
|
});
|
|
306
339
|
return shouldRegenerateModel ? Object.keys(newModelLookup) : newModel;
|
|
307
340
|
}
|
|
341
|
+
|
|
342
|
+
// This method only diffs the two models it receives,
|
|
343
|
+
// it must not read the selection from the store,
|
|
344
|
+
// otherwise the result would depend on whether the store has already been updated or not.
|
|
308
345
|
function getAddedAndRemovedItems({
|
|
309
|
-
store,
|
|
310
346
|
oldModel,
|
|
311
347
|
newModel
|
|
312
348
|
}) {
|
|
@@ -314,8 +350,12 @@ function getAddedAndRemovedItems({
|
|
|
314
350
|
newModel.forEach(id => {
|
|
315
351
|
newModelMap.set(id, true);
|
|
316
352
|
});
|
|
353
|
+
const oldModelMap = new Map();
|
|
354
|
+
oldModel.forEach(id => {
|
|
355
|
+
oldModelMap.set(id, true);
|
|
356
|
+
});
|
|
317
357
|
return {
|
|
318
|
-
added: newModel.filter(itemId => !
|
|
358
|
+
added: newModel.filter(itemId => !oldModelMap.has(itemId)),
|
|
319
359
|
removed: oldModel.filter(itemId => !newModelMap.has(itemId))
|
|
320
360
|
};
|
|
321
361
|
}
|