@vaadin/grid 24.2.0-dev.f254716fe → 24.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/grid",
3
- "version": "24.2.0-dev.f254716fe",
3
+ "version": "24.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -46,18 +46,18 @@
46
46
  "dependencies": {
47
47
  "@open-wc/dedupe-mixin": "^1.3.0",
48
48
  "@polymer/polymer": "^3.0.0",
49
- "@vaadin/a11y-base": "24.2.0-dev.f254716fe",
50
- "@vaadin/checkbox": "24.2.0-dev.f254716fe",
51
- "@vaadin/component-base": "24.2.0-dev.f254716fe",
52
- "@vaadin/lit-renderer": "24.2.0-dev.f254716fe",
53
- "@vaadin/text-field": "24.2.0-dev.f254716fe",
54
- "@vaadin/vaadin-lumo-styles": "24.2.0-dev.f254716fe",
55
- "@vaadin/vaadin-material-styles": "24.2.0-dev.f254716fe",
56
- "@vaadin/vaadin-themable-mixin": "24.2.0-dev.f254716fe"
49
+ "@vaadin/a11y-base": "~24.2.0",
50
+ "@vaadin/checkbox": "~24.2.0",
51
+ "@vaadin/component-base": "~24.2.0",
52
+ "@vaadin/lit-renderer": "~24.2.0",
53
+ "@vaadin/text-field": "~24.2.0",
54
+ "@vaadin/vaadin-lumo-styles": "~24.2.0",
55
+ "@vaadin/vaadin-material-styles": "~24.2.0",
56
+ "@vaadin/vaadin-themable-mixin": "~24.2.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@esm-bundle/chai": "^4.3.4",
60
- "@vaadin/testing-helpers": "^0.4.3",
60
+ "@vaadin/testing-helpers": "^0.5.0",
61
61
  "lit": "^2.0.0",
62
62
  "sinon": "^13.0.2"
63
63
  },
@@ -65,5 +65,5 @@
65
65
  "web-types.json",
66
66
  "web-types.lit.json"
67
67
  ],
68
- "gitHead": "da54950b9f8c14c6451ede0d426e16a489c7fb9b"
68
+ "gitHead": "8b9e860d53fc0132d05d3e8701eeded2dca74eba"
69
69
  }
@@ -7,6 +7,7 @@ import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nod
7
7
  import { PolymerElement } from '@polymer/polymer/polymer-element.js';
8
8
  import { animationFrame } from '@vaadin/component-base/src/async.js';
9
9
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
10
+ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
10
11
  import { ColumnBaseMixin } from './vaadin-grid-column.js';
11
12
  import { updateColumnOrders } from './vaadin-grid-helpers.js';
12
13
 
@@ -39,6 +40,7 @@ import { updateColumnOrders } from './vaadin-grid-helpers.js';
39
40
  * column2.renderer = (root, column, model) => { ... };
40
41
  * ```
41
42
  *
43
+ * @customElement
42
44
  * @extends HTMLElement
43
45
  * @mixes ColumnBaseMixin
44
46
  */
@@ -396,6 +398,6 @@ class GridColumnGroup extends ColumnBaseMixin(PolymerElement) {
396
398
  }
397
399
  }
398
400
 
399
- customElements.define(GridColumnGroup.is, GridColumnGroup);
401
+ defineCustomElement(GridColumnGroup);
400
402
 
401
403
  export { GridColumnGroup };
@@ -6,7 +6,9 @@
6
6
  import { PolymerElement } from '@polymer/polymer/polymer-element.js';
7
7
  import { animationFrame } from '@vaadin/component-base/src/async.js';
8
8
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
9
+ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
9
10
  import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
11
+ import { get } from '@vaadin/component-base/src/path-utils.js';
10
12
  import { processTemplates } from '@vaadin/component-base/src/templates.js';
11
13
  import { updateCellState } from './vaadin-grid-helpers.js';
12
14
 
@@ -487,7 +489,7 @@ export const ColumnBaseMixin = (superClass) =>
487
489
 
488
490
  /** @private */
489
491
  _textAlignChanged(textAlign) {
490
- if (textAlign === undefined) {
492
+ if (textAlign === undefined || this._grid === undefined) {
491
493
  return;
492
494
  }
493
495
  if (['start', 'end', 'center'].indexOf(textAlign) === -1) {
@@ -713,7 +715,7 @@ export const ColumnBaseMixin = (superClass) =>
713
715
  return;
714
716
  }
715
717
 
716
- this.__setTextContent(root, this.get(this.path, item));
718
+ this.__setTextContent(root, get(this.path, item));
717
719
  }
718
720
 
719
721
  /**
@@ -783,6 +785,7 @@ export const ColumnBaseMixin = (superClass) =>
783
785
  * See [`<vaadin-grid>`](#/elements/vaadin-grid) documentation for instructions on how
784
786
  * to configure the `<vaadin-grid-column>`.
785
787
  *
788
+ * @customElement
786
789
  * @extends HTMLElement
787
790
  * @mixes ColumnBaseMixin
788
791
  */
@@ -894,6 +897,6 @@ class GridColumn extends ColumnBaseMixin(DirMixin(PolymerElement)) {
894
897
  }
895
898
  }
896
899
 
897
- customElements.define(GridColumn.is, GridColumn);
900
+ defineCustomElement(GridColumn);
898
901
 
899
902
  export { GridColumn };
@@ -33,6 +33,31 @@ export type GridDataProvider<TItem> = (
33
33
  callback: GridDataProviderCallback<TItem>,
34
34
  ) => void;
35
35
 
36
+ export declare class ItemCache<TItem> {
37
+ grid: HTMLElement;
38
+ parentCache: ItemCache<TItem> | undefined;
39
+ parentItem: TItem | undefined;
40
+ itemCaches: object | null;
41
+ items: object | null;
42
+ effectiveSize: number;
43
+ size: number;
44
+ pendingRequests: object | null;
45
+
46
+ constructor(grid: HTMLElement, parentCache: ItemCache<TItem> | undefined, parentItem: TItem | undefined);
47
+
48
+ isLoading(): boolean;
49
+
50
+ getItemForIndex(index: number): TItem | undefined;
51
+
52
+ updateSize(): void;
53
+
54
+ ensureSubCacheForScaledIndex(scaledIndex: number): void;
55
+
56
+ getCacheAndIndex(index: number): { cache: ItemCache<TItem>; scaledIndex: number };
57
+
58
+ getFlatIndex(scaledIndex: number): number;
59
+ }
60
+
36
61
  export declare function DataProviderMixin<TItem, T extends Constructor<HTMLElement>>(
37
62
  base: T,
38
63
  ): Constructor<DataProviderMixinClass<TItem>> & T;
@@ -4,10 +4,116 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { timeOut } from '@vaadin/component-base/src/async.js';
7
- import { DataProviderController } from '@vaadin/component-base/src/data-provider-controller.js';
8
7
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
8
+ import { get } from '@vaadin/component-base/src/path-utils.js';
9
9
  import { getBodyRowCells, updateCellsPart, updateState } from './vaadin-grid-helpers.js';
10
10
 
11
+ /**
12
+ * @private
13
+ */
14
+ export const ItemCache = class ItemCache {
15
+ /**
16
+ * @param {!HTMLElement} grid
17
+ * @param {!ItemCache | undefined} parentCache
18
+ * @param {!GridItem | undefined} parentItem
19
+ */
20
+ constructor(grid, parentCache, parentItem) {
21
+ /** @type {!HTMLElement} */
22
+ this.grid = grid;
23
+ /** @type {!ItemCache | undefined} */
24
+ this.parentCache = parentCache;
25
+ /** @type {!GridItem | undefined} */
26
+ this.parentItem = parentItem;
27
+ /** @type {object} */
28
+ this.itemCaches = {};
29
+ /** @type {object[]} */
30
+ this.items = [];
31
+ /** @type {number} */
32
+ this.effectiveSize = 0;
33
+ /** @type {number} */
34
+ this.size = 0;
35
+ /** @type {object} */
36
+ this.pendingRequests = {};
37
+ }
38
+
39
+ /**
40
+ * @return {boolean}
41
+ */
42
+ isLoading() {
43
+ return Boolean(
44
+ Object.keys(this.pendingRequests).length ||
45
+ Object.keys(this.itemCaches).filter((index) => {
46
+ return this.itemCaches[index].isLoading();
47
+ })[0],
48
+ );
49
+ }
50
+
51
+ /**
52
+ * @param {number} index
53
+ * @return {!GridItem | undefined}
54
+ */
55
+ getItemForIndex(index) {
56
+ const { cache, scaledIndex } = this.getCacheAndIndex(index);
57
+ return cache.items[scaledIndex];
58
+ }
59
+
60
+ updateSize() {
61
+ this.effectiveSize =
62
+ !this.parentItem || this.grid._isExpanded(this.parentItem)
63
+ ? this.size +
64
+ Object.keys(this.itemCaches).reduce((prev, curr) => {
65
+ const subCache = this.itemCaches[curr];
66
+ subCache.updateSize();
67
+ return prev + subCache.effectiveSize;
68
+ }, 0)
69
+ : 0;
70
+ }
71
+
72
+ /**
73
+ * @param {number} scaledIndex
74
+ */
75
+ ensureSubCacheForScaledIndex(scaledIndex) {
76
+ if (!this.itemCaches[scaledIndex]) {
77
+ const subCache = new ItemCache(this.grid, this, this.items[scaledIndex]);
78
+ this.itemCaches[scaledIndex] = subCache;
79
+ this.grid._loadPage(0, subCache);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @param {number} index
85
+ * @return {{cache: !ItemCache, scaledIndex: number}}
86
+ */
87
+ getCacheAndIndex(index) {
88
+ let thisLevelIndex = index;
89
+ for (const [index, subCache] of Object.entries(this.itemCaches)) {
90
+ const numberIndex = Number(index);
91
+ if (thisLevelIndex <= numberIndex) {
92
+ return { cache: this, scaledIndex: thisLevelIndex };
93
+ } else if (thisLevelIndex <= numberIndex + subCache.effectiveSize) {
94
+ return subCache.getCacheAndIndex(thisLevelIndex - numberIndex - 1);
95
+ }
96
+ thisLevelIndex -= subCache.effectiveSize;
97
+ }
98
+ return { cache: this, scaledIndex: thisLevelIndex };
99
+ }
100
+
101
+ /**
102
+ * Gets the scaled index as flattened index on this cache level.
103
+ * In practice, this means that the effective size of any expanded
104
+ * subcaches preceding the index are added to the value.
105
+ * @param {number} scaledIndex
106
+ * @return {number} The flat index on this cache level.
107
+ */
108
+ getFlatIndex(scaledIndex) {
109
+ const clampedIndex = Math.max(0, Math.min(this.size - 1, scaledIndex));
110
+
111
+ return Object.entries(this.itemCaches).reduce((prev, [index, subCache]) => {
112
+ return clampedIndex > Number(index) ? prev + subCache.effectiveSize : prev;
113
+ }, clampedIndex);
114
+ }
115
+ };
116
+
11
117
  /**
12
118
  * @polymerMixin
13
119
  */
@@ -75,6 +181,18 @@ export const DataProviderMixin = (superClass) =>
75
181
  reflectToAttribute: true,
76
182
  },
77
183
 
184
+ /**
185
+ * @type {!ItemCache}
186
+ * @protected
187
+ */
188
+ _cache: {
189
+ type: Object,
190
+ value() {
191
+ const cache = new ItemCache(this);
192
+ return cache;
193
+ },
194
+ },
195
+
78
196
  /**
79
197
  * @protected
80
198
  */
@@ -126,32 +244,12 @@ export const DataProviderMixin = (superClass) =>
126
244
  return ['_sizeChanged(size)', '_expandedItemsChanged(expandedItems.*)'];
127
245
  }
128
246
 
129
- constructor() {
130
- super();
131
-
132
- /** @type {DataProviderController} */
133
- this._dataProviderController = new DataProviderController(this, {
134
- size: this.size,
135
- pageSize: this.pageSize,
136
- isExpanded: this._isExpanded.bind(this),
137
- dataProvider: this.dataProvider ? this.dataProvider.bind(this) : null,
138
- dataProviderParams: () => {
139
- return {
140
- sortOrders: this._mapSorters(),
141
- filters: this._mapFilters(),
142
- };
143
- },
144
- });
145
-
146
- this._dataProviderController.addEventListener('page-requested', this._onDataProviderPageRequested.bind(this));
147
- this._dataProviderController.addEventListener('page-received', this._onDataProviderPageReceived.bind(this));
148
- this._dataProviderController.addEventListener('page-loaded', this._onDataProviderPageLoaded.bind(this));
149
- }
150
-
151
247
  /** @private */
152
248
  _sizeChanged(size) {
153
- this._dataProviderController.setSize(size);
154
- this._effectiveSize = this._dataProviderController.effectiveSize;
249
+ const delta = size - this._cache.size;
250
+ this._cache.size += delta;
251
+ this._cache.effectiveSize += delta;
252
+ this._effectiveSize = this._cache.effectiveSize;
155
253
  }
156
254
 
157
255
  /** @private */
@@ -174,17 +272,17 @@ export const DataProviderMixin = (superClass) =>
174
272
  }
175
273
 
176
274
  el.index = index;
177
-
178
- const { item } = this._dataProviderController.getFlatIndexInfo(index);
275
+ const { cache, scaledIndex } = this._cache.getCacheAndIndex(index);
276
+ const item = cache.items[scaledIndex];
179
277
  if (item) {
180
278
  this.__updateLoading(el, false);
181
279
  this._updateItem(el, item);
182
280
  if (this._isExpanded(item)) {
183
- this._dataProviderController.ensureFlatIndexChildrenLoaded(index);
281
+ cache.ensureSubCacheForScaledIndex(scaledIndex);
184
282
  }
185
283
  } else {
186
284
  this.__updateLoading(el, true);
187
- this._dataProviderController.ensureFlatIndexLoaded(index);
285
+ this._loadPage(this._getPageForIndex(scaledIndex), cache);
188
286
  }
189
287
  }
190
288
 
@@ -210,7 +308,7 @@ export const DataProviderMixin = (superClass) =>
210
308
  * @return {!GridItem | !unknown}
211
309
  */
212
310
  getItemId(item) {
213
- return this.itemIdPath ? this.get(this.itemIdPath, item) : item;
311
+ return this.itemIdPath ? get(this.itemIdPath, item) : item;
214
312
  }
215
313
 
216
314
  /**
@@ -224,8 +322,8 @@ export const DataProviderMixin = (superClass) =>
224
322
 
225
323
  /** @private */
226
324
  _expandedItemsChanged() {
227
- this._dataProviderController.recalculateEffectiveSize();
228
- this._effectiveSize = this._dataProviderController.effectiveSize;
325
+ this._cache.updateSize();
326
+ this._effectiveSize = this._cache.effectiveSize;
229
327
  this.__updateVisibleRows();
230
328
  }
231
329
 
@@ -265,68 +363,122 @@ export const DataProviderMixin = (superClass) =>
265
363
  * @return {number}
266
364
  * @protected
267
365
  */
268
- _getIndexLevel(index = 0) {
269
- const { level } = this._dataProviderController.getFlatIndexInfo(index);
366
+ _getIndexLevel(index) {
367
+ let { cache } = this._cache.getCacheAndIndex(index);
368
+ let level = 0;
369
+ while (cache.parentCache) {
370
+ cache = cache.parentCache;
371
+ level += 1;
372
+ }
270
373
  return level;
271
374
  }
272
375
 
273
- /** @protected */
274
- _onDataProviderPageRequested() {
275
- this._setLoading(true);
276
- }
277
-
278
- /** @protected */
279
- _onDataProviderPageReceived() {
280
- // With the new items added, update the cache size and the grid's effective size
281
- this._effectiveSize = this._dataProviderController.effectiveSize;
376
+ /**
377
+ * @param {number} page
378
+ * @param {ItemCache} cache
379
+ * @protected
380
+ */
381
+ _loadPage(page, cache) {
382
+ // Make sure same page isn't requested multiple times.
383
+ if (!cache.pendingRequests[page] && this.dataProvider) {
384
+ this._setLoading(true);
385
+ cache.pendingRequests[page] = true;
386
+ const params = {
387
+ page,
388
+ pageSize: this.pageSize,
389
+ sortOrders: this._mapSorters(),
390
+ filters: this._mapFilters(),
391
+ parentItem: cache.parentItem,
392
+ };
393
+
394
+ this.dataProvider(params, (items, size) => {
395
+ if (size !== undefined) {
396
+ cache.size = size;
397
+ } else if (params.parentItem) {
398
+ cache.size = items.length;
399
+ }
282
400
 
283
- // After updating the cache, check if some of the expanded items should have sub-caches loaded
284
- this._getRenderedRows().forEach((row) => {
285
- this._dataProviderController.ensureFlatIndexChildrenLoaded(row.index);
286
- });
401
+ // Populate the cache with new items
402
+ items.forEach((item, itemsIndex) => {
403
+ const itemIndex = page * this.pageSize + itemsIndex;
404
+ cache.items[itemIndex] = item;
405
+ });
406
+
407
+ // With the new items added, update the cache size and the grid's effective size
408
+ this._cache.updateSize();
409
+ this._effectiveSize = this._cache.effectiveSize;
410
+
411
+ // After updating the cache, check if some of the expanded items should have sub-caches loaded
412
+ this._getRenderedRows().forEach((row) => {
413
+ const { cache, scaledIndex } = this._cache.getCacheAndIndex(row.index);
414
+ const item = cache.items[scaledIndex];
415
+ if (item && this._isExpanded(item)) {
416
+ cache.ensureSubCacheForScaledIndex(scaledIndex);
417
+ }
418
+ });
419
+
420
+ this._hasData = true;
421
+
422
+ // Remove the pending request
423
+ delete cache.pendingRequests[page];
424
+
425
+ // Schedule a debouncer to update the visible rows
426
+ this._debouncerApplyCachedData = Debouncer.debounce(this._debouncerApplyCachedData, timeOut.after(0), () => {
427
+ this._setLoading(false);
428
+
429
+ this._getRenderedRows().forEach((row) => {
430
+ const cachedItem = this._cache.getItemForIndex(row.index);
431
+ if (cachedItem) {
432
+ this._getItem(row.index, row);
433
+ }
434
+ });
435
+
436
+ this.__scrollToPendingIndexes();
437
+ this.__dispatchPendingBodyCellFocus();
438
+ });
439
+
440
+ // If the grid is not loading anything, flush the debouncer immediately
441
+ if (!this._cache.isLoading()) {
442
+ this._debouncerApplyCachedData.flush();
443
+ }
287
444
 
288
- this._hasData = true;
445
+ // Notify that new data has been received
446
+ this._onDataProviderPageLoaded();
447
+ });
448
+ }
289
449
  }
290
450
 
291
451
  /** @protected */
292
- _onDataProviderPageLoaded() {
293
- // Schedule a debouncer to update the visible rows
294
- this._debouncerApplyCachedData = Debouncer.debounce(this._debouncerApplyCachedData, timeOut.after(0), () => {
295
- this._setLoading(false);
296
-
297
- this._getRenderedRows().forEach((row) => {
298
- const { item } = this._dataProviderController.getFlatIndexInfo(row.index);
299
- if (item) {
300
- this._getItem(row.index, row);
301
- }
302
- });
303
-
304
- this.__scrollToPendingIndexes();
305
- });
452
+ _onDataProviderPageLoaded() {}
306
453
 
307
- // If the grid is not loading anything, flush the debouncer immediately
308
- if (!this._dataProviderController.isLoading()) {
309
- this._debouncerApplyCachedData.flush();
310
- }
454
+ /**
455
+ * @param {number} index
456
+ * @return {number}
457
+ * @private
458
+ */
459
+ _getPageForIndex(index) {
460
+ return Math.floor(index / this.pageSize);
311
461
  }
312
462
 
313
463
  /**
314
464
  * Clears the cached pages and reloads data from dataprovider when needed.
315
465
  */
316
466
  clearCache() {
317
- this._dataProviderController.clearCache();
467
+ this._cache = new ItemCache(this);
468
+ this._cache.size = this.size || 0;
469
+ this._cache.updateSize();
318
470
  this._hasData = false;
319
471
  this.__updateVisibleRows();
320
- this._ensureFirstPageLoaded();
472
+
473
+ if (!this._effectiveSize) {
474
+ this._loadPage(0, this._cache);
475
+ }
321
476
  }
322
477
 
323
478
  /** @private */
324
479
  _pageSizeChanged(pageSize, oldPageSize) {
325
- this._dataProviderController.setPageSize(pageSize);
326
480
  if (oldPageSize !== undefined && pageSize !== oldPageSize) {
327
- this._hasData = false;
328
- this.__updateVisibleRows();
329
- this._ensureFirstPageLoaded();
481
+ this.clearCache();
330
482
  }
331
483
  }
332
484
 
@@ -344,11 +496,8 @@ export const DataProviderMixin = (superClass) =>
344
496
 
345
497
  /** @private */
346
498
  _dataProviderChanged(dataProvider, oldDataProvider) {
347
- this._dataProviderController.setDataProvider(dataProvider ? dataProvider.bind(this) : null);
348
-
349
499
  if (oldDataProvider !== undefined) {
350
- this._hasData = false;
351
- this.__updateVisibleRows();
500
+ this.clearCache();
352
501
  }
353
502
 
354
503
  this._ensureFirstPageLoaded();
@@ -365,7 +514,7 @@ export const DataProviderMixin = (superClass) =>
365
514
  if (!this._hasData) {
366
515
  // Load data before adding rows to make sure they have content when
367
516
  // rendered for the first time.
368
- this._dataProviderController.ensureFirstPageLoaded();
517
+ this._loadPage(0, this._cache);
369
518
  }
370
519
  }
371
520
 
@@ -415,15 +564,39 @@ export const DataProviderMixin = (superClass) =>
415
564
  // ending up in a loading state. Try scrolling to the index until the target
416
565
  // index stabilizes.
417
566
  let targetIndex;
418
- while (targetIndex !== (targetIndex = this._dataProviderController.getFlatIndexByPath(indexes))) {
567
+ while (targetIndex !== (targetIndex = this.__getGlobalFlatIndex(indexes))) {
419
568
  this._scrollToFlatIndex(targetIndex);
420
569
  }
421
570
 
422
- if (this._dataProviderController.isLoading() || !this.clientHeight) {
571
+ if (this._cache.isLoading() || !this.clientHeight) {
423
572
  this.__pendingScrollToIndexes = indexes;
424
573
  }
425
574
  }
426
575
 
576
+ /**
577
+ * Recursively returns the globally flat index of the item the given indexes point to.
578
+ * Each index in the array points to a sub-item of the previous index.
579
+ * Using `Infinity` as an index will point to the last item on the level.
580
+ *
581
+ * @param {!Array<number>} indexes
582
+ * @param {!ItemCache} cache
583
+ * @param {number} flatIndex
584
+ * @return {number}
585
+ * @private
586
+ */
587
+ __getGlobalFlatIndex([levelIndex, ...subIndexes], cache = this._cache, flatIndex = 0) {
588
+ if (levelIndex === Infinity) {
589
+ // Treat Infinity as the last index on the level
590
+ levelIndex = cache.size - 1;
591
+ }
592
+ const flatIndexOnLevel = cache.getFlatIndex(levelIndex);
593
+ const subCache = cache.itemCaches[levelIndex];
594
+ if (subCache && subCache.effectiveSize && subIndexes.length) {
595
+ return this.__getGlobalFlatIndex(subIndexes, subCache, flatIndex + flatIndexOnLevel + 1);
596
+ }
597
+ return flatIndex + flatIndexOnLevel;
598
+ }
599
+
427
600
  /** @private */
428
601
  __scrollToPendingIndexes() {
429
602
  if (this.__pendingScrollToIndexes && this.$.items.children.length) {
@@ -112,7 +112,7 @@ export const DynamicColumnsMixin = (superClass) =>
112
112
  if (hasColumnElements(info.addedNodes) || hasColumnElements(info.removedNodes)) {
113
113
  const allRemovedCells = info.removedNodes.flatMap((c) => c._allCells);
114
114
  const filterNotConnected = (element) =>
115
- allRemovedCells.filter((cell) => cell._content.contains(element)).length;
115
+ allRemovedCells.filter((cell) => cell && cell._content.contains(element)).length;
116
116
 
117
117
  this.__removeSorters(this._sorters.filter(filterNotConnected));
118
118
  this.__removeFilters(this._filters.filter(filterNotConnected));
@@ -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 './vaadin-grid-filter.js';
7
+ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
7
8
  import { GridColumn } from './vaadin-grid-column.js';
8
9
 
9
10
  /**
@@ -18,6 +19,9 @@ import { GridColumn } from './vaadin-grid-column.js';
18
19
  * <vaadin-grid-column>
19
20
  * ...
20
21
  * ```
22
+ *
23
+ * @customElement
24
+ * @extends GridColumn
21
25
  */
22
26
  class GridFilterColumn extends GridColumn {
23
27
  static get is() {
@@ -114,6 +118,6 @@ class GridFilterColumn extends GridColumn {
114
118
  }
115
119
  }
116
120
 
117
- customElements.define(GridFilterColumn.is, GridFilterColumn);
121
+ defineCustomElement(GridFilterColumn);
118
122
 
119
123
  export { GridFilterColumn };
@@ -8,6 +8,7 @@ import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
8
8
  import { timeOut } from '@vaadin/component-base/src/async.js';
9
9
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
10
10
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
11
+ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
11
12
  import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
12
13
 
13
14
  /**
@@ -35,6 +36,7 @@ import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
35
36
  *
36
37
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
37
38
  *
39
+ * @customElement
38
40
  * @extends HTMLElement
39
41
  */
40
42
  class GridFilter extends ControllerMixin(PolymerElement) {
@@ -125,6 +127,6 @@ class GridFilter extends ControllerMixin(PolymerElement) {
125
127
  }
126
128
  }
127
129
 
128
- customElements.define(GridFilter.is, GridFilter);
130
+ defineCustomElement(GridFilter);
129
131
 
130
132
  export { GridFilter };