@vaadin/component-base 24.2.0-dev.f254716fe → 24.3.0-alpha2

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.
@@ -0,0 +1,248 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { Cache } from './cache.js';
7
+ import { getFlatIndexByPath, getFlatIndexContext } from './helpers.js';
8
+
9
+ /**
10
+ * A controller that stores and manages items loaded with a data provider.
11
+ */
12
+ export class DataProviderController extends EventTarget {
13
+ /**
14
+ * The controller host element.
15
+ *
16
+ * @param {HTMLElement}
17
+ */
18
+ host;
19
+
20
+ /**
21
+ * A callback that returns data based on the passed params such as
22
+ * `page`, `pageSize`, `parentItem`, etc.
23
+ */
24
+ dataProvider;
25
+
26
+ /**
27
+ * A callback that returns additional params that need to be passed
28
+ * to the data provider callback with every request.
29
+ */
30
+ dataProviderParams;
31
+
32
+ /**
33
+ * A number of items in the root cache.
34
+ *
35
+ * @type {number}
36
+ */
37
+ size;
38
+
39
+ /**
40
+ * A number of items to display per page.
41
+ *
42
+ * @type {number}
43
+ */
44
+ pageSize;
45
+
46
+ /**
47
+ * A callback that returns whether the given item is expanded.
48
+ *
49
+ * @type {(item: unknown) => boolean}
50
+ */
51
+ isExpanded;
52
+
53
+ /**
54
+ * A reference to the root cache instance.
55
+ *
56
+ * @param {Cache}
57
+ */
58
+ rootCache;
59
+
60
+ constructor(host, { size, pageSize, isExpanded, dataProvider, dataProviderParams }) {
61
+ super();
62
+ this.host = host;
63
+ this.size = size;
64
+ this.pageSize = pageSize;
65
+ this.isExpanded = isExpanded;
66
+ this.dataProvider = dataProvider;
67
+ this.dataProviderParams = dataProviderParams;
68
+ this.rootCache = this.__createRootCache();
69
+ }
70
+
71
+ /**
72
+ * The total number of items, including items from expanded sub-caches.
73
+ */
74
+ get flatSize() {
75
+ return this.rootCache.flatSize;
76
+ }
77
+
78
+ /** @private */
79
+ get __cacheContext() {
80
+ return {
81
+ isExpanded: this.isExpanded,
82
+ // The controller instance is needed to ensure deprecated cache methods work.
83
+ __controller: this,
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Whether the root cache or any of its decendant caches have pending requests.
89
+ *
90
+ * @return {boolean}
91
+ */
92
+ isLoading() {
93
+ return this.rootCache.isLoading;
94
+ }
95
+
96
+ /**
97
+ * Sets the size for the root cache and recalculates the flattened size.
98
+ *
99
+ * @param {number} size
100
+ */
101
+ setSize(size) {
102
+ this.size = size;
103
+ this.rootCache.size = size;
104
+ this.recalculateFlatSize();
105
+ }
106
+
107
+ /**
108
+ * Sets the page size and clears the cache.
109
+ *
110
+ * @param {number} pageSize
111
+ */
112
+ setPageSize(pageSize) {
113
+ this.pageSize = pageSize;
114
+ this.clearCache();
115
+ }
116
+
117
+ /**
118
+ * Sets the data provider callback and clears the cache.
119
+ *
120
+ * @type {Function}
121
+ */
122
+ setDataProvider(dataProvider) {
123
+ this.dataProvider = dataProvider;
124
+ this.clearCache();
125
+ }
126
+
127
+ /**
128
+ * Recalculates the flattened size.
129
+ */
130
+ recalculateFlatSize() {
131
+ this.rootCache.recalculateFlatSize();
132
+ }
133
+
134
+ /**
135
+ * Clears the cache.
136
+ */
137
+ clearCache() {
138
+ this.rootCache = this.__createRootCache();
139
+ }
140
+
141
+ /**
142
+ * Returns context for the given flattened index, including:
143
+ * - the corresponding cache
144
+ * - the associated item (if loaded)
145
+ * - the corresponding index in the cache's items array.
146
+ * - the page containing the index.
147
+ * - the cache level
148
+ */
149
+ getFlatIndexContext(flatIndex) {
150
+ return getFlatIndexContext(this.rootCache, flatIndex);
151
+ }
152
+
153
+ /**
154
+ * Returns the flattened index for the item that the given indexes point to.
155
+ * Each index in the path array points to a sub-item of the previous index.
156
+ * Using `Infinity` as an index will point to the last item on the level.
157
+ *
158
+ * @param {number[]} path
159
+ * @return {number}
160
+ */
161
+ getFlatIndexByPath(path) {
162
+ return getFlatIndexByPath(this.rootCache, path);
163
+ }
164
+
165
+ /**
166
+ * Requests the data provider to load the page with the item corresponding
167
+ * to the given flattened index. If the item is already loaded, the method
168
+ * returns immediatelly.
169
+ *
170
+ * @param {number} flatIndex
171
+ */
172
+ ensureFlatIndexLoaded(flatIndex) {
173
+ const { cache, page, item } = this.getFlatIndexContext(flatIndex);
174
+
175
+ if (!item) {
176
+ this.__loadCachePage(cache, page);
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Creates a sub-cache for the item corresponding to the given flattened index and
182
+ * requests the data provider to load the first page into the created sub-cache.
183
+ * If the sub-cache already exists, the method returns immediatelly.
184
+ *
185
+ * @param {number} flatIndex
186
+ */
187
+ ensureFlatIndexHierarchy(flatIndex) {
188
+ const { cache, item, index } = this.getFlatIndexContext(flatIndex);
189
+
190
+ if (item && this.isExpanded(item) && !cache.getSubCache(index)) {
191
+ const subCache = cache.createSubCache(index);
192
+ this.__loadCachePage(subCache, 0);
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Loads the first page into the root cache.
198
+ */
199
+ loadFirstPage() {
200
+ this.__loadCachePage(this.rootCache, 0);
201
+ }
202
+
203
+ /** @private */
204
+ __createRootCache() {
205
+ return new Cache(this.__cacheContext, this.pageSize, this.size);
206
+ }
207
+
208
+ /** @private */
209
+ __loadCachePage(cache, page) {
210
+ if (!this.dataProvider || cache.pendingRequests[page]) {
211
+ return;
212
+ }
213
+
214
+ let params = {
215
+ page,
216
+ pageSize: this.pageSize,
217
+ parentItem: cache.parentItem,
218
+ };
219
+
220
+ if (this.dataProviderParams) {
221
+ params = { ...params, ...this.dataProviderParams() };
222
+ }
223
+
224
+ const callback = (items, size) => {
225
+ if (size !== undefined) {
226
+ cache.size = size;
227
+ } else if (params.parentItem) {
228
+ cache.size = items.length;
229
+ }
230
+
231
+ cache.setPage(page, items);
232
+
233
+ this.recalculateFlatSize();
234
+
235
+ this.dispatchEvent(new CustomEvent('page-received'));
236
+
237
+ delete cache.pendingRequests[page];
238
+
239
+ this.dispatchEvent(new CustomEvent('page-loaded'));
240
+ };
241
+
242
+ cache.pendingRequests[page] = callback;
243
+
244
+ this.dispatchEvent(new CustomEvent('page-requested'));
245
+
246
+ this.dataProvider(params, callback);
247
+ }
248
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * Returns context for the given flattened index, including:
9
+ * - the corresponding cache
10
+ * - the associated item (if loaded)
11
+ * - the corresponding index in the cache's items array.
12
+ * - the page containing the index.
13
+ * - the cache level
14
+ */
15
+ export function getFlatIndexContext(
16
+ cache: Cache,
17
+ flatIndex: number,
18
+ level: number,
19
+ ): {
20
+ cache: Cache;
21
+ item: unknown | undefined;
22
+ index: number;
23
+ page: number;
24
+ level: number;
25
+ };
26
+
27
+ /**
28
+ * Recursively returns the globally flat index of the item the given indexes point to.
29
+ * Each index in the array points to a sub-item of the previous index.
30
+ * Using `Infinity` as an index will point to the last item on the level.
31
+ */
32
+ export function getFlatIndexByPath(cache: Cache, path: number[], flatIndex: number): number;
@@ -1,5 +1,11 @@
1
1
  /**
2
- * Retreives information for the given flattened index, including:
2
+ * @license
3
+ * Copyright (c) 2021 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * Returns context for the given flattened index, including:
3
9
  * - the corresponding cache
4
10
  * - the associated item (if loaded)
5
11
  * - the corresponding index in the cache's items array.
@@ -10,16 +16,17 @@
10
16
  * @param {number} flatIndex
11
17
  * @return {{ cache: Cache, item: object | undefined, index: number, page: number, level: number }}
12
18
  */
13
- export function getFlatIndexInfo(cache, flatIndex, level = 0) {
19
+ export function getFlatIndexContext(cache, flatIndex, level = 0) {
14
20
  let levelIndex = flatIndex;
15
21
 
16
- for (const [index, subCache] of cache.subCaches) {
22
+ for (const subCache of cache.subCaches) {
23
+ const index = subCache.parentCacheIndex;
17
24
  if (levelIndex <= index) {
18
25
  break;
19
- } else if (levelIndex <= index + subCache.effectiveSize) {
20
- return getFlatIndexInfo(subCache, levelIndex - index - 1, level + 1);
26
+ } else if (levelIndex <= index + subCache.flatSize) {
27
+ return getFlatIndexContext(subCache, levelIndex - index - 1, level + 1);
21
28
  }
22
- levelIndex -= subCache.effectiveSize;
29
+ levelIndex -= subCache.flatSize;
23
30
  }
24
31
 
25
32
  return {
@@ -36,8 +43,8 @@ export function getFlatIndexInfo(cache, flatIndex, level = 0) {
36
43
  * Each index in the array points to a sub-item of the previous index.
37
44
  * Using `Infinity` as an index will point to the last item on the level.
38
45
  *
39
- * @param {!ItemCache} cache
40
- * @param {!Array<number>} indexes
46
+ * @param {Cache} cache
47
+ * @param {number[]} path
41
48
  * @param {number} flatIndex
42
49
  * @return {number}
43
50
  */
@@ -49,7 +56,7 @@ export function getFlatIndexByPath(cache, [levelIndex, ...subIndexes], flatIndex
49
56
 
50
57
  const flatIndexOnLevel = cache.getFlatIndex(levelIndex);
51
58
  const subCache = cache.getSubCache(levelIndex);
52
- if (subCache && subCache.effectiveSize > 0 && subIndexes.length) {
59
+ if (subCache && subCache.flatSize > 0 && subIndexes.length) {
53
60
  return getFlatIndexByPath(subCache, subIndexes, flatIndex + flatIndexOnLevel + 1);
54
61
  }
55
62
  return flatIndex + flatIndexOnLevel;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ export interface CustomElementType extends CustomElementConstructor {
7
+ is: string;
8
+ }
9
+
10
+ export declare function defineCustomElement(CustomElement: CustomElementConstructor): void;
package/src/define.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ export function defineCustomElement(CustomElement) {
8
+ const defined = customElements.get(CustomElement.is);
9
+ if (!defined) {
10
+ Object.defineProperty(CustomElement, 'version', {
11
+ get() {
12
+ return '24.3.0-alpha2';
13
+ },
14
+ });
15
+
16
+ customElements.define(CustomElement.is, CustomElement);
17
+ } else {
18
+ const definedVersion = defined.version;
19
+ if (definedVersion && CustomElement.version && definedVersion === CustomElement.version) {
20
+ // Just loading the same thing again
21
+ console.warn(`The component ${CustomElement.is} has been loaded twice`);
22
+ } else {
23
+ console.error(
24
+ `Tried to define ${CustomElement.is} version ${CustomElement.version} when version ${defined.version} is already in use. Something will probably break.`,
25
+ );
26
+ }
27
+ }
28
+ }
@@ -13,6 +13,13 @@
13
13
  */
14
14
  export function getAncestorRootNodes(node: Node): Node[];
15
15
 
16
+ /**
17
+ * Returns the list of flattened elements for the given `node`.
18
+ * This list consists of a node's children and, for any children that are
19
+ * `<slot>` elements, the expanded flattened list of `assignedElements`.
20
+ */
21
+ export function getFlattenedElements(node: Node): Element[];
22
+
16
23
  /**
17
24
  * Traverses the given node and its parents, including those that are across
18
25
  * the shadow root boundaries, until it finds a node that matches the selector.
package/src/dom-utils.js CHANGED
@@ -40,6 +40,27 @@ export function getAncestorRootNodes(node) {
40
40
  return result;
41
41
  }
42
42
 
43
+ /**
44
+ * Returns the list of flattened elements for the given `node`.
45
+ * This list consists of a node's children and, for any children that are
46
+ * `<slot>` elements, the expanded flattened list of `assignedElements`.
47
+ *
48
+ * @param {Node} node
49
+ * @return {Element[]}
50
+ */
51
+ export function getFlattenedElements(node) {
52
+ const result = [];
53
+ let elements;
54
+ if (node.localName === 'slot') {
55
+ elements = node.assignedElements();
56
+ } else {
57
+ result.push(node);
58
+ elements = [...node.children];
59
+ }
60
+ elements.forEach((elem) => result.push(...getFlattenedElements(elem)));
61
+ return result;
62
+ }
63
+
43
64
  /**
44
65
  * Traverses the given node and its parents, including those that are across
45
66
  * the shadow root boundaries, until it finds a node that matches the selector.
@@ -16,6 +16,7 @@ export declare function ElementMixin<T extends Constructor<HTMLElement>>(
16
16
  ): Constructor<DirMixinClass> & Constructor<ElementMixinClass> & T;
17
17
 
18
18
  export declare class ElementMixinClass {
19
+ static is: string;
19
20
  static version: string;
20
21
 
21
22
  protected static finalize(): void;
@@ -44,10 +44,6 @@ const registered = new Set();
44
44
  */
45
45
  export const ElementMixin = (superClass) =>
46
46
  class VaadinElementMixin extends DirMixin(superClass) {
47
- static get version() {
48
- return '24.2.0-alpha5';
49
- }
50
-
51
47
  /** @protected */
52
48
  static finalize() {
53
49
  super.finalize();
@@ -3,7 +3,6 @@
3
3
  * Copyright (c) 2021 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
7
6
  import { animationFrame } from './async.js';
8
7
  import { Debouncer } from './debounce.js';
9
8
 
@@ -47,30 +46,41 @@ export class OverflowController {
47
46
  * @protected
48
47
  */
49
48
  observe() {
50
- this.__resizeObserver = new ResizeObserver(() => {
49
+ const { host } = this;
50
+
51
+ this.__resizeObserver = new ResizeObserver((entries) => {
51
52
  this.__debounceOverflow = Debouncer.debounce(this.__debounceOverflow, animationFrame, () => {
52
53
  this.__updateOverflow();
53
54
  });
54
55
  });
55
56
 
56
- this.__resizeObserver.observe(this.host);
57
+ this.__resizeObserver.observe(host);
57
58
 
58
- this.__childObserver = new FlattenedNodesObserver(this.host, (info) => {
59
- info.addedNodes.forEach((node) => {
60
- if (node.nodeType === Node.ELEMENT_NODE) {
61
- this.__resizeObserver.observe(node);
62
- }
63
- });
59
+ // Observe initial children
60
+ [...host.children].forEach((child) => {
61
+ this.__resizeObserver.observe(child);
62
+ });
64
63
 
65
- info.removedNodes.forEach((node) => {
66
- if (node.nodeType === Node.ELEMENT_NODE) {
67
- this.__resizeObserver.unobserve(node);
68
- }
64
+ this.__childObserver = new MutationObserver((mutations) => {
65
+ mutations.forEach(({ addedNodes, removedNodes }) => {
66
+ addedNodes.forEach((node) => {
67
+ if (node.nodeType === Node.ELEMENT_NODE) {
68
+ this.__resizeObserver.observe(node);
69
+ }
70
+ });
71
+
72
+ removedNodes.forEach((node) => {
73
+ if (node.nodeType === Node.ELEMENT_NODE) {
74
+ this.__resizeObserver.unobserve(node);
75
+ }
76
+ });
69
77
  });
70
78
 
71
79
  this.__updateOverflow();
72
80
  });
73
81
 
82
+ this.__childObserver.observe(host, { childList: true });
83
+
74
84
  // Update overflow attribute on scroll
75
85
  this.scrollTarget.addEventListener('scroll', this.__boundOnScroll);
76
86
 
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * Convenience method for reading a value from a path.
9
+ */
10
+ export function get(path: string, object: object): unknown;
11
+
12
+ /**
13
+ * Convenience method for setting a value to a path.
14
+ */
15
+ export function set(path: string, value: unknown, object: object): void;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * Convenience method for reading a value from a path.
9
+ *
10
+ * @param {string} path
11
+ * @param {object} object
12
+ */
13
+ export function get(path, object) {
14
+ return path.split('.').reduce((obj, property) => (obj ? obj[property] : undefined), object);
15
+ }
16
+
17
+ /**
18
+ * Convenience method for setting a value to a path.
19
+ *
20
+ * @param {string} path
21
+ * @param {unknown} value
22
+ * @param {object} object
23
+ */
24
+ export function set(path, value, object) {
25
+ const pathParts = path.split('.');
26
+ const lastPart = pathParts.pop();
27
+ const target = pathParts.reduce((target, part) => target[part], object);
28
+ target[lastPart] = value;
29
+ }
@@ -4,6 +4,7 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { dedupeMixin } from '@open-wc/dedupe-mixin';
7
+ import { get, set } from './path-utils.js';
7
8
 
8
9
  const caseMap = {};
9
10
 
@@ -92,15 +93,22 @@ const PolylitMixinImplementation = (superclass) => {
92
93
 
93
94
  let result = defaultDescriptor;
94
95
 
95
- if ('value' in options) {
96
- // Set the default value
97
- this.addCheckedInitializer((instance) => {
98
- if (typeof options.value === 'function') {
99
- instance[name] = options.value.call(instance);
100
- } else {
101
- instance[name] = options.value;
102
- }
103
- });
96
+ if (options.sync) {
97
+ result = {
98
+ get: defaultDescriptor.get,
99
+ set(value) {
100
+ const oldValue = this[name];
101
+ this[key] = value;
102
+ this.requestUpdate(name, oldValue, options);
103
+
104
+ // Enforce synchronous update
105
+ if (this.hasUpdated) {
106
+ this.performUpdate();
107
+ }
108
+ },
109
+ configurable: true,
110
+ enumerable: true,
111
+ };
104
112
  }
105
113
 
106
114
  if (options.readOnly) {
@@ -110,6 +118,10 @@ const PolylitMixinImplementation = (superclass) => {
110
118
  // This is run during construction of the element
111
119
  instance[`_set${upper(name)}`] = function (value) {
112
120
  setter.call(instance, value);
121
+
122
+ if (options.sync) {
123
+ this.performUpdate();
124
+ }
113
125
  };
114
126
  });
115
127
 
@@ -123,6 +135,19 @@ const PolylitMixinImplementation = (superclass) => {
123
135
  };
124
136
  }
125
137
 
138
+ if ('value' in options) {
139
+ // Set the default value
140
+ this.addCheckedInitializer((instance) => {
141
+ const value = typeof options.value === 'function' ? options.value.call(instance) : options.value;
142
+
143
+ if (options.readOnly) {
144
+ instance[`_set${upper(name)}`](value);
145
+ } else {
146
+ instance[name] = value;
147
+ }
148
+ });
149
+ }
150
+
126
151
  if (options.observer) {
127
152
  const method = options.observer;
128
153
 
@@ -175,7 +200,7 @@ const PolylitMixinImplementation = (superclass) => {
175
200
  this.$ = {};
176
201
  }
177
202
 
178
- this.shadowRoot.querySelectorAll('[id]').forEach((node) => {
203
+ this.renderRoot.querySelectorAll('[id]').forEach((node) => {
179
204
  this.$[node.id] = node;
180
205
  });
181
206
  }
@@ -202,8 +227,8 @@ const PolylitMixinImplementation = (superclass) => {
202
227
  }
203
228
 
204
229
  if (!this.__isReadyInvoked) {
205
- this.ready();
206
230
  this.__isReadyInvoked = true;
231
+ this.ready();
207
232
  }
208
233
  }
209
234
 
@@ -254,15 +279,12 @@ const PolylitMixinImplementation = (superclass) => {
254
279
 
255
280
  /** @protected */
256
281
  _get(path, object) {
257
- return path.split('.').reduce((obj, property) => (obj ? obj[property] : undefined), object);
282
+ return get(path, object);
258
283
  }
259
284
 
260
285
  /** @protected */
261
286
  _set(path, value, object) {
262
- const pathParts = path.split('.');
263
- const lastPart = pathParts.pop();
264
- const target = pathParts.reduce((target, part) => target[part], object);
265
- target[lastPart] = value;
287
+ set(path, value, object);
266
288
  }
267
289
  }
268
290
 
@@ -3,8 +3,8 @@
3
3
  * Copyright (c) 2021 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
7
6
  import { isEmptyTextNode } from './dom-utils.js';
7
+ import { SlotObserver } from './slot-observer.js';
8
8
  import { generateUniqueId } from './unique-id-utils.js';
9
9
 
10
10
  /**
@@ -199,17 +199,17 @@ export class SlotController extends EventTarget {
199
199
  const selector = slotName === '' ? 'slot:not([name])' : `slot[name=${slotName}]`;
200
200
  const slot = this.host.shadowRoot.querySelector(selector);
201
201
 
202
- this.__slotObserver = new FlattenedNodesObserver(slot, (info) => {
202
+ this.__slotObserver = new SlotObserver(slot, ({ addedNodes, removedNodes }) => {
203
203
  const current = this.multiple ? this.nodes : [this.node];
204
204
 
205
205
  // Calling `slot.assignedNodes()` includes whitespace text nodes in case of default slot:
206
206
  // unlike comment nodes, they are not filtered out. So we need to manually ignore them.
207
- const newNodes = info.addedNodes.filter((node) => !isEmptyTextNode(node) && !current.includes(node));
207
+ const newNodes = addedNodes.filter((node) => !isEmptyTextNode(node) && !current.includes(node));
208
208
 
209
- if (info.removedNodes.length) {
210
- this.nodes = current.filter((node) => !info.removedNodes.includes(node));
209
+ if (removedNodes.length) {
210
+ this.nodes = current.filter((node) => !removedNodes.includes(node));
211
211
 
212
- info.removedNodes.forEach((node) => {
212
+ removedNodes.forEach((node) => {
213
213
  this.teardownNode(node);
214
214
  });
215
215
  }