@vaadin/grid 24.3.0-alpha2 → 24.3.0-alpha3

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.3.0-alpha2",
3
+ "version": "24.3.0-alpha3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -46,14 +46,14 @@
46
46
  "dependencies": {
47
47
  "@open-wc/dedupe-mixin": "^1.3.0",
48
48
  "@polymer/polymer": "^3.0.0",
49
- "@vaadin/a11y-base": "24.3.0-alpha2",
50
- "@vaadin/checkbox": "24.3.0-alpha2",
51
- "@vaadin/component-base": "24.3.0-alpha2",
52
- "@vaadin/lit-renderer": "24.3.0-alpha2",
53
- "@vaadin/text-field": "24.3.0-alpha2",
54
- "@vaadin/vaadin-lumo-styles": "24.3.0-alpha2",
55
- "@vaadin/vaadin-material-styles": "24.3.0-alpha2",
56
- "@vaadin/vaadin-themable-mixin": "24.3.0-alpha2"
49
+ "@vaadin/a11y-base": "24.3.0-alpha3",
50
+ "@vaadin/checkbox": "24.3.0-alpha3",
51
+ "@vaadin/component-base": "24.3.0-alpha3",
52
+ "@vaadin/lit-renderer": "24.3.0-alpha3",
53
+ "@vaadin/text-field": "24.3.0-alpha3",
54
+ "@vaadin/vaadin-lumo-styles": "24.3.0-alpha3",
55
+ "@vaadin/vaadin-material-styles": "24.3.0-alpha3",
56
+ "@vaadin/vaadin-themable-mixin": "24.3.0-alpha3"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@esm-bundle/chai": "^4.3.4",
@@ -65,5 +65,5 @@
65
65
  "web-types.json",
66
66
  "web-types.lit.json"
67
67
  ],
68
- "gitHead": "0fd437292fa2a2f65e29b424d2456909ad2d684b"
68
+ "gitHead": "9162ca5fb9879dbcc8c68a77c1acb3af2c497a15"
69
69
  }
@@ -93,6 +93,20 @@ export declare class ColumnBaseMixinClass<TItem, Column extends ColumnBaseMixinC
93
93
  * - `column` The `<vaadin-grid-column>` element.
94
94
  */
95
95
  footerRenderer: GridHeaderFooterRenderer<TItem, Column> | null | undefined;
96
+
97
+ /**
98
+ * Custom part name for the header cell.
99
+ *
100
+ * @attr {string} header-part-name
101
+ */
102
+ headerPartName: string | null | undefined;
103
+
104
+ /**
105
+ * Custom part name for the footer cell.
106
+ *
107
+ * @attr {string} footer-part-name
108
+ */
109
+ footerPartName: string | null | undefined;
96
110
  }
97
111
 
98
112
  export interface GridColumnMixin<TItem, Column extends GridColumnMixinClass<TItem, Column>>
@@ -101,6 +101,24 @@ export const ColumnBaseMixin = (superClass) =>
101
101
  type: String,
102
102
  },
103
103
 
104
+ /**
105
+ * Custom part name for the header cell.
106
+ *
107
+ * @attr {string} header-part-name
108
+ */
109
+ headerPartName: {
110
+ type: String,
111
+ },
112
+
113
+ /**
114
+ * Custom part name for the footer cell.
115
+ *
116
+ * @attr {string} footer-part-name
117
+ */
118
+ footerPartName: {
119
+ type: String,
120
+ },
121
+
104
122
  /**
105
123
  * @type {boolean}
106
124
  * @protected
@@ -238,6 +256,7 @@ export const ColumnBaseMixin = (superClass) =>
238
256
  '_reorderStatusChanged(_reorderStatus, _headerCell, _footerCell, _cells.*)',
239
257
  '_hiddenChanged(hidden, _headerCell, _footerCell, _cells.*)',
240
258
  '_rowHeaderChanged(rowHeader, _cells.*)',
259
+ '__headerFooterPartNameChanged(_headerCell, _footerCell, headerPartName, footerPartName)',
241
260
  ];
242
261
  }
243
262
 
@@ -487,7 +506,7 @@ export const ColumnBaseMixin = (superClass) =>
487
506
 
488
507
  /** @private */
489
508
  _textAlignChanged(textAlign) {
490
- if (textAlign === undefined) {
509
+ if (textAlign === undefined || this._grid === undefined) {
491
510
  return;
492
511
  }
493
512
  if (['start', 'end', 'center'].indexOf(textAlign) === -1) {
@@ -631,6 +650,22 @@ export const ColumnBaseMixin = (superClass) =>
631
650
  this._renderHeaderCellContent(headerRenderer, headerCell);
632
651
  }
633
652
 
653
+ /** @private */
654
+ __headerFooterPartNameChanged(headerCell, footerCell, headerPartName, footerPartName) {
655
+ [
656
+ { cell: headerCell, partName: headerPartName },
657
+ { cell: footerCell, partName: footerPartName },
658
+ ].forEach(({ cell, partName }) => {
659
+ if (cell) {
660
+ const customParts = cell.__customParts || [];
661
+ cell.part.remove(...customParts);
662
+
663
+ cell.__customParts = partName ? partName.trim().split(' ') : [];
664
+ cell.part.add(...cell.__customParts);
665
+ }
666
+ });
667
+ }
668
+
634
669
  /**
635
670
  * Renders the content of body cells using a renderer.
636
671
  *
@@ -134,6 +134,7 @@ export const DataProviderMixin = (superClass) =>
134
134
  this._dataProviderController = new DataProviderController(this, {
135
135
  size: this.size,
136
136
  pageSize: this.pageSize,
137
+ getItemId: this.getItemId.bind(this),
137
138
  isExpanded: this._isExpanded.bind(this),
138
139
  dataProvider: this.dataProvider ? this.dataProvider.bind(this) : null,
139
140
  dataProviderParams: () => {
@@ -332,6 +333,7 @@ export const DataProviderMixin = (superClass) =>
332
333
  });
333
334
 
334
335
  this.__scrollToPendingIndexes();
336
+ this.__dispatchPendingBodyCellFocus();
335
337
  });
336
338
 
337
339
  // If the grid is not loading anything, flush the debouncer immediately
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+
8
+ export declare function GridFilterColumnMixin<T extends Constructor<HTMLElement>>(
9
+ superclass: T,
10
+ ): Constructor<GridFilterColumnMixinClass> & T;
11
+
12
+ export declare class GridFilterColumnMixinClass {
13
+ /**
14
+ * Text to display as the label of the column filter text-field.
15
+ */
16
+ header: string | null | undefined;
17
+
18
+ /**
19
+ * JS Path of the property in the item used for filtering the data.
20
+ */
21
+ path: string | null | undefined;
22
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * @polymerMixin
9
+ */
10
+ export const GridFilterColumnMixin = (superClass) =>
11
+ class extends superClass {
12
+ static get properties() {
13
+ return {
14
+ /**
15
+ * JS Path of the property in the item used for filtering the data.
16
+ */
17
+ path: String,
18
+
19
+ /**
20
+ * Text to display as the label of the column filter text-field.
21
+ */
22
+ header: String,
23
+ };
24
+ }
25
+
26
+ static get observers() {
27
+ return ['_onHeaderRendererOrBindingChanged(_headerRenderer, _headerCell, path, header, _filterValue)'];
28
+ }
29
+
30
+ constructor() {
31
+ super();
32
+
33
+ this.__boundOnFilterValueChanged = this.__onFilterValueChanged.bind(this);
34
+ }
35
+
36
+ /**
37
+ * Renders the grid filter with the custom text field to the header cell.
38
+ *
39
+ * @override
40
+ */
41
+ _defaultHeaderRenderer(root, _column) {
42
+ let filter = root.firstElementChild;
43
+ let textField = filter ? filter.firstElementChild : undefined;
44
+
45
+ if (!filter) {
46
+ filter = document.createElement('vaadin-grid-filter');
47
+ textField = document.createElement('vaadin-text-field');
48
+ textField.setAttribute('theme', 'small');
49
+ textField.setAttribute('style', 'max-width: 100%;');
50
+ textField.setAttribute('focus-target', '');
51
+ textField.addEventListener('value-changed', this.__boundOnFilterValueChanged);
52
+ filter.appendChild(textField);
53
+ root.appendChild(filter);
54
+ }
55
+
56
+ filter.path = this.path;
57
+ filter.value = this._filterValue;
58
+
59
+ textField.__rendererValue = this._filterValue;
60
+ textField.value = this._filterValue;
61
+ textField.label = this.__getHeader(this.header, this.path);
62
+ }
63
+
64
+ /**
65
+ * The filter column doesn't allow to use a custom header renderer
66
+ * to override the header cell content.
67
+ * It always renders the grid filter to the header cell.
68
+ *
69
+ * @override
70
+ */
71
+ _computeHeaderRenderer() {
72
+ return this._defaultHeaderRenderer;
73
+ }
74
+
75
+ /**
76
+ * Updates the internal filter value once the filter text field is changed.
77
+ * The listener handles only user-fired events.
78
+ *
79
+ * @private
80
+ */
81
+ __onFilterValueChanged(e) {
82
+ // Skip if the value is changed by the renderer.
83
+ if (e.detail.value === e.target.__rendererValue) {
84
+ return;
85
+ }
86
+
87
+ this._filterValue = e.detail.value;
88
+ }
89
+
90
+ /** @private */
91
+ __getHeader(header, path) {
92
+ if (header) {
93
+ return header;
94
+ }
95
+
96
+ if (path) {
97
+ return this._generateHeader(path);
98
+ }
99
+ }
100
+ };
@@ -4,7 +4,10 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import type { GridDefaultItem } from './vaadin-grid.js';
7
- import { GridColumn } from './vaadin-grid-column.js';
7
+ import type { GridColumn, GridColumnMixin } from './vaadin-grid-column.js';
8
+ import type { GridFilterColumnMixinClass } from './vaadin-grid-filter-column-mixin.js';
9
+
10
+ export * from './vaadin-grid-filter-column-mixin.js';
8
11
 
9
12
  /**
10
13
  * `<vaadin-grid-filter-column>` is a helper element for the `<vaadin-grid>`
@@ -19,17 +22,12 @@ import { GridColumn } from './vaadin-grid-column.js';
19
22
  * ...
20
23
  * ```
21
24
  */
22
- declare class GridFilterColumn<TItem = GridDefaultItem> extends GridColumn<TItem> {
23
- /**
24
- * Text to display as the label of the column filter text-field.
25
- */
26
- header: string | null | undefined;
25
+ declare class GridFilterColumn<TItem = GridDefaultItem> extends HTMLElement {}
27
26
 
28
- /**
29
- * JS Path of the property in the item used for filtering the data.
30
- */
31
- path: string | null | undefined;
32
- }
27
+ interface GridFilterColumn<TItem = GridDefaultItem>
28
+ extends GridFilterColumnMixinClass,
29
+ GridColumnMixin<TItem, GridColumn<TItem>>,
30
+ GridColumn<TItem> {}
33
31
 
34
32
  declare global {
35
33
  interface HTMLElementTagNameMap {
@@ -6,6 +6,7 @@
6
6
  import './vaadin-grid-filter.js';
7
7
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
8
8
  import { GridColumn } from './vaadin-grid-column.js';
9
+ import { GridFilterColumnMixin } from './vaadin-grid-filter-column-mixin.js';
9
10
 
10
11
  /**
11
12
  * `<vaadin-grid-filter-column>` is a helper element for the `<vaadin-grid>`
@@ -22,100 +23,12 @@ import { GridColumn } from './vaadin-grid-column.js';
22
23
  *
23
24
  * @customElement
24
25
  * @extends GridColumn
26
+ * @mixes GridFilterColumnMixin
25
27
  */
26
- class GridFilterColumn extends GridColumn {
28
+ class GridFilterColumn extends GridFilterColumnMixin(GridColumn) {
27
29
  static get is() {
28
30
  return 'vaadin-grid-filter-column';
29
31
  }
30
-
31
- static get properties() {
32
- return {
33
- /**
34
- * JS Path of the property in the item used for filtering the data.
35
- */
36
- path: String,
37
-
38
- /**
39
- * Text to display as the label of the column filter text-field.
40
- */
41
- header: String,
42
- };
43
- }
44
-
45
- static get observers() {
46
- return ['_onHeaderRendererOrBindingChanged(_headerRenderer, _headerCell, path, header, _filterValue)'];
47
- }
48
-
49
- constructor() {
50
- super();
51
-
52
- this.__boundOnFilterValueChanged = this.__onFilterValueChanged.bind(this);
53
- }
54
-
55
- /**
56
- * Renders the grid filter with the custom text field to the header cell.
57
- *
58
- * @override
59
- */
60
- _defaultHeaderRenderer(root, _column) {
61
- let filter = root.firstElementChild;
62
- let textField = filter ? filter.firstElementChild : undefined;
63
-
64
- if (!filter) {
65
- filter = document.createElement('vaadin-grid-filter');
66
- textField = document.createElement('vaadin-text-field');
67
- textField.setAttribute('theme', 'small');
68
- textField.setAttribute('style', 'max-width: 100%;');
69
- textField.setAttribute('focus-target', '');
70
- textField.addEventListener('value-changed', this.__boundOnFilterValueChanged);
71
- filter.appendChild(textField);
72
- root.appendChild(filter);
73
- }
74
-
75
- filter.path = this.path;
76
- filter.value = this._filterValue;
77
-
78
- textField.__rendererValue = this._filterValue;
79
- textField.value = this._filterValue;
80
- textField.label = this.__getHeader(this.header, this.path);
81
- }
82
-
83
- /**
84
- * The filter column doesn't allow to use a custom header renderer
85
- * to override the header cell content.
86
- * It always renders the grid filter to the header cell.
87
- *
88
- * @override
89
- */
90
- _computeHeaderRenderer() {
91
- return this._defaultHeaderRenderer;
92
- }
93
-
94
- /**
95
- * Updates the internal filter value once the filter text field is changed.
96
- * The listener handles only user-fired events.
97
- *
98
- * @private
99
- */
100
- __onFilterValueChanged(e) {
101
- // Skip if the value is changed by the renderer.
102
- if (e.detail.value === e.target.__rendererValue) {
103
- return;
104
- }
105
-
106
- this._filterValue = e.detail.value;
107
- }
108
-
109
- /** @private */
110
- __getHeader(header, path) {
111
- if (header) {
112
- return header;
113
- }
114
-
115
- if (path) {
116
- return this._generateHeader(path);
117
- }
118
- }
119
32
  }
120
33
 
121
34
  defineCustomElement(GridFilterColumn);
@@ -842,9 +842,12 @@ export const KeyboardNavigationMixin = (superClass) =>
842
842
  }
843
843
 
844
844
  if (cell) {
845
- // Fire a public event for cell.
846
845
  const context = this.getEventContext(e);
847
- cell.dispatchEvent(new CustomEvent('cell-focus', { bubbles: true, composed: true, detail: { context } }));
846
+ this.__pendingBodyCellFocus = this.loading && context.section === 'body';
847
+ if (!this.__pendingBodyCellFocus) {
848
+ // Fire a cell-focus event for the cell
849
+ cell.dispatchEvent(new CustomEvent('cell-focus', { bubbles: true, composed: true, detail: { context } }));
850
+ }
848
851
  this._focusedCell = cell._focusButton || cell;
849
852
 
850
853
  if (isKeyboardActive() && e.target === cell) {
@@ -858,6 +861,16 @@ export const KeyboardNavigationMixin = (superClass) =>
858
861
  this._detectFocusedItemIndex(e);
859
862
  }
860
863
 
864
+ /**
865
+ * @private
866
+ */
867
+ __dispatchPendingBodyCellFocus() {
868
+ // If the body cell focus was pending, dispatch the event once loading is done
869
+ if (this.__pendingBodyCellFocus && this.shadowRoot.activeElement === this._itemsFocusable) {
870
+ this._itemsFocusable.dispatchEvent(new Event('focusin', { bubbles: true, composed: true }));
871
+ }
872
+ }
873
+
861
874
  /**
862
875
  * Get the focusable element depending on the current focus mode.
863
876
  * It can be a row, a cell, or a focusable div inside a cell.
@@ -339,7 +339,10 @@ export const GridMixin = (superClass) =>
339
339
  return 0;
340
340
  }
341
341
 
342
- const columnWidth = Math.max(this.__getIntrinsicWidth(col), this.__getDistributedWidth(col.parentElement, col));
342
+ const columnWidth = Math.max(
343
+ this.__getIntrinsicWidth(col),
344
+ this.__getDistributedWidth((col.assignedSlot || col).parentElement, col),
345
+ );
343
346
 
344
347
  // We're processing a regular grid-column and not a grid-column-group
345
348
  if (!innerColumn) {
@@ -697,7 +700,7 @@ export const GridMixin = (superClass) =>
697
700
  column._emptyCells.push(cell);
698
701
  }
699
702
  }
700
- cell.setAttribute('part', `cell ${section}-cell`);
703
+ cell.part.add('cell', `${section}-cell`);
701
704
  }
702
705
 
703
706
  if (!cell._content.parentElement) {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import { GridSelectionColumnBaseMixinClass } from './vaadin-grid-selection-column-base-mixin.js';
8
+
9
+ /**
10
+ * Fired when the `selectAll` property changes.
11
+ */
12
+ export type GridSelectionColumnSelectAllChangedEvent = CustomEvent<{ value: boolean }>;
13
+
14
+ export interface GridSelectionColumnCustomEventMap {
15
+ 'select-all-changed': GridSelectionColumnSelectAllChangedEvent;
16
+ }
17
+
18
+ export interface GridSelectionColumnEventMap extends HTMLElementEventMap, GridSelectionColumnCustomEventMap {}
19
+
20
+ export declare function GridSelectionColumnMixin<TItem, T extends Constructor<HTMLElement>>(
21
+ superclass: T,
22
+ ): Constructor<GridSelectionColumnMixinClass<TItem>> & T;
23
+
24
+ export declare class GridSelectionColumnMixinClass<TItem> extends GridSelectionColumnBaseMixinClass<TItem> {}
@@ -0,0 +1,194 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { GridSelectionColumnBaseMixin } from './vaadin-grid-selection-column-base-mixin.js';
7
+
8
+ /**
9
+ * @polymerMixin
10
+ */
11
+ export const GridSelectionColumnMixin = (superClass) =>
12
+ class extends GridSelectionColumnBaseMixin(superClass) {
13
+ static get properties() {
14
+ return {
15
+ /**
16
+ * The previous state of activeItem. When activeItem turns to `null`,
17
+ * previousActiveItem will have an Object with just unselected activeItem
18
+ * @private
19
+ */
20
+ __previousActiveItem: Object,
21
+ };
22
+ }
23
+
24
+ static get observers() {
25
+ return ['__onSelectAllChanged(selectAll)'];
26
+ }
27
+
28
+ constructor() {
29
+ super();
30
+
31
+ this.__boundOnActiveItemChanged = this.__onActiveItemChanged.bind(this);
32
+ this.__boundOnDataProviderChanged = this.__onDataProviderChanged.bind(this);
33
+ this.__boundOnSelectedItemsChanged = this.__onSelectedItemsChanged.bind(this);
34
+ }
35
+
36
+ /** @protected */
37
+ disconnectedCallback() {
38
+ this._grid.removeEventListener('active-item-changed', this.__boundOnActiveItemChanged);
39
+ this._grid.removeEventListener('data-provider-changed', this.__boundOnDataProviderChanged);
40
+ this._grid.removeEventListener('filter-changed', this.__boundOnSelectedItemsChanged);
41
+ this._grid.removeEventListener('selected-items-changed', this.__boundOnSelectedItemsChanged);
42
+
43
+ super.disconnectedCallback();
44
+ }
45
+
46
+ /** @protected */
47
+ connectedCallback() {
48
+ super.connectedCallback();
49
+ if (this._grid) {
50
+ this._grid.addEventListener('active-item-changed', this.__boundOnActiveItemChanged);
51
+ this._grid.addEventListener('data-provider-changed', this.__boundOnDataProviderChanged);
52
+ this._grid.addEventListener('filter-changed', this.__boundOnSelectedItemsChanged);
53
+ this._grid.addEventListener('selected-items-changed', this.__boundOnSelectedItemsChanged);
54
+ }
55
+ }
56
+
57
+ /** @private */
58
+ __onSelectAllChanged(selectAll) {
59
+ if (selectAll === undefined || !this._grid) {
60
+ return;
61
+ }
62
+
63
+ if (!this.__selectAllInitialized) {
64
+ // The initial value for selectAll property was applied, avoid clearing pre-selected items
65
+ this.__selectAllInitialized = true;
66
+ return;
67
+ }
68
+
69
+ if (this._selectAllChangeLock) {
70
+ return;
71
+ }
72
+
73
+ if (selectAll && this.__hasArrayDataProvider()) {
74
+ this.__withFilteredItemsArray((items) => {
75
+ this._grid.selectedItems = items;
76
+ });
77
+ } else {
78
+ this._grid.selectedItems = [];
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Return true if array `a` contains all the items in `b`
84
+ * We need this when sorting or to preserve selection after filtering.
85
+ * @private
86
+ */
87
+ __arrayContains(a, b) {
88
+ return Array.isArray(a) && Array.isArray(b) && b.every((i) => a.includes(i));
89
+ }
90
+
91
+ /**
92
+ * Override a method from `GridSelectionColumnBaseMixin` to handle the user
93
+ * selecting all items.
94
+ *
95
+ * @protected
96
+ * @override
97
+ */
98
+ _selectAll() {
99
+ this.selectAll = true;
100
+ }
101
+
102
+ /**
103
+ * Override a method from `GridSelectionColumnBaseMixin` to handle the user
104
+ * deselecting all items.
105
+ *
106
+ * @protected
107
+ * @override
108
+ */
109
+ _deselectAll() {
110
+ this.selectAll = false;
111
+ }
112
+
113
+ /**
114
+ * Override a method from `GridSelectionColumnBaseMixin` to handle the user
115
+ * selecting an item.
116
+ *
117
+ * @param {Object} item the item to select
118
+ * @protected
119
+ * @override
120
+ */
121
+ _selectItem(item) {
122
+ this._grid.selectItem(item);
123
+ }
124
+
125
+ /**
126
+ * Override a method from `GridSelectionColumnBaseMixin` to handle the user
127
+ * deselecting an item.
128
+ *
129
+ * @param {Object} item the item to deselect
130
+ * @protected
131
+ * @override
132
+ */
133
+ _deselectItem(item) {
134
+ this._grid.deselectItem(item);
135
+ }
136
+
137
+ /** @private */
138
+ __onActiveItemChanged(e) {
139
+ const activeItem = e.detail.value;
140
+ if (this.autoSelect) {
141
+ const item = activeItem || this.__previousActiveItem;
142
+ if (item) {
143
+ this._grid._toggleItem(item);
144
+ }
145
+ }
146
+ this.__previousActiveItem = activeItem;
147
+ }
148
+
149
+ /** @private */
150
+ __hasArrayDataProvider() {
151
+ return Array.isArray(this._grid.items) && !!this._grid.dataProvider;
152
+ }
153
+
154
+ /** @private */
155
+ __onSelectedItemsChanged() {
156
+ this._selectAllChangeLock = true;
157
+ if (this.__hasArrayDataProvider()) {
158
+ this.__withFilteredItemsArray((items) => {
159
+ if (!this._grid.selectedItems.length) {
160
+ this.selectAll = false;
161
+ this._indeterminate = false;
162
+ } else if (this.__arrayContains(this._grid.selectedItems, items)) {
163
+ this.selectAll = true;
164
+ this._indeterminate = false;
165
+ } else {
166
+ this.selectAll = false;
167
+ this._indeterminate = true;
168
+ }
169
+ });
170
+ }
171
+ this._selectAllChangeLock = false;
172
+ }
173
+
174
+ /** @private */
175
+ __onDataProviderChanged() {
176
+ this._selectAllHidden = !Array.isArray(this._grid.items);
177
+ }
178
+
179
+ /**
180
+ * Assuming the grid uses an items array data provider, fetches all the filtered items
181
+ * from the data provider and invokes the callback with the resulting array.
182
+ *
183
+ * @private
184
+ */
185
+ __withFilteredItemsArray(callback) {
186
+ const params = {
187
+ page: 0,
188
+ pageSize: Infinity,
189
+ sortOrders: [],
190
+ filters: this._grid._mapFilters(),
191
+ };
192
+ this._grid.dataProvider(params, (items) => callback(items));
193
+ }
194
+ };