@vaadin/grid 23.1.0-alpha4 → 23.1.0-beta3

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/lit.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './src/lit/renderer-directives.js';
2
+ export * from './src/lit/column-renderer-directives.js';
package/lit.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './src/lit/renderer-directives.js';
2
+ export * from './src/lit/column-renderer-directives.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/grid",
3
- "version": "23.1.0-alpha4",
3
+ "version": "23.1.0-beta3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,6 +23,8 @@
23
23
  "all-imports.js",
24
24
  "src",
25
25
  "theme",
26
+ "lit.js",
27
+ "lit.d.ts",
26
28
  "vaadin-*.d.ts",
27
29
  "vaadin-*.js"
28
30
  ],
@@ -41,19 +43,20 @@
41
43
  "dependencies": {
42
44
  "@open-wc/dedupe-mixin": "^1.3.0",
43
45
  "@polymer/polymer": "^3.0.0",
44
- "@vaadin/checkbox": "23.1.0-alpha4",
45
- "@vaadin/component-base": "23.1.0-alpha4",
46
- "@vaadin/text-field": "23.1.0-alpha4",
47
- "@vaadin/vaadin-lumo-styles": "23.1.0-alpha4",
48
- "@vaadin/vaadin-material-styles": "23.1.0-alpha4",
49
- "@vaadin/vaadin-themable-mixin": "23.1.0-alpha4"
46
+ "@vaadin/checkbox": "23.1.0-beta3",
47
+ "@vaadin/component-base": "23.1.0-beta3",
48
+ "@vaadin/lit-renderer": "23.1.0-beta3",
49
+ "@vaadin/text-field": "23.1.0-beta3",
50
+ "@vaadin/vaadin-lumo-styles": "23.1.0-beta3",
51
+ "@vaadin/vaadin-material-styles": "23.1.0-beta3",
52
+ "@vaadin/vaadin-themable-mixin": "23.1.0-beta3"
50
53
  },
51
54
  "devDependencies": {
52
55
  "@esm-bundle/chai": "^4.3.4",
53
- "@vaadin/polymer-legacy-adapter": "23.1.0-alpha4",
56
+ "@vaadin/polymer-legacy-adapter": "23.1.0-beta3",
54
57
  "@vaadin/testing-helpers": "^0.3.2",
55
58
  "lit": "^2.0.0",
56
59
  "sinon": "^13.0.2"
57
60
  },
58
- "gitHead": "aacdb7fe09811894751f0378ff7fb66071892c71"
61
+ "gitHead": "c787ceb8a312f88631c6d429ff320d5f89b1b838"
59
62
  }
@@ -25,12 +25,12 @@ function checkPaths(arrayToCheck, action, items) {
25
25
  for (const i in arrayToCheck) {
26
26
  const path = arrayToCheck[i].path;
27
27
 
28
- // skip simple paths
28
+ // Skip simple paths
29
29
  if (!path || path.indexOf('.') === -1) {
30
30
  continue;
31
31
  }
32
32
 
33
- const parentProperty = path.replace(/\.[^.]*$/, ''); // a.b.c -> a.b
33
+ const parentProperty = path.replace(/\.[^.]*$/, ''); // A.b.c -> a.b
34
34
  if (get(parentProperty, items[0]) === undefined) {
35
35
  console.warn(`Path "${path}" used for ${action} does not exist in all of the items, ${action} is disabled.`);
36
36
  result = false;
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ /* eslint-disable max-classes-per-file */
7
+ import { TemplateResult } from 'lit';
8
+ import { DirectiveResult } from 'lit/directive';
9
+ import { LitRenderer, LitRendererDirective } from '@vaadin/lit-renderer';
10
+ import { GridItemModel } from '../vaadin-grid.js';
11
+ import { GridColumn } from '../vaadin-grid-column.js';
12
+
13
+ export type GridColumnBodyLitRenderer<TItem> = (
14
+ item: TItem,
15
+ model: GridItemModel<TItem>,
16
+ column: GridColumn,
17
+ ) => TemplateResult;
18
+
19
+ export type GridColumnHeaderLitRenderer = (column: GridColumn) => TemplateResult;
20
+ export type GridColumnFooterLitRenderer = (column: GridColumn) => TemplateResult;
21
+
22
+ declare abstract class AbstractGridColumnRendererDirective<R extends LitRenderer> extends LitRendererDirective<
23
+ GridColumn,
24
+ R
25
+ > {
26
+ /**
27
+ * A property to that the renderer callback will be assigned.
28
+ */
29
+ abstract rendererProperty: 'renderer' | 'headerRenderer' | 'footerRenderer';
30
+
31
+ /**
32
+ * Adds the renderer callback to the grid column.
33
+ */
34
+ addRenderer(): void;
35
+
36
+ /**
37
+ * Runs the renderer callback on the grid column.
38
+ */
39
+ runRenderer(): void;
40
+
41
+ /**
42
+ * Removes the renderer callback from the grid column.
43
+ */
44
+ removeRenderer(): void;
45
+ }
46
+
47
+ export declare class GridColumnBodyRendererDirective<TItem> extends AbstractGridColumnRendererDirective<
48
+ GridColumnBodyLitRenderer<TItem>
49
+ > {
50
+ rendererProperty: 'renderer';
51
+ }
52
+
53
+ export declare class GridColumnHeaderRendererDirective extends AbstractGridColumnRendererDirective<GridColumnHeaderLitRenderer> {
54
+ rendererProperty: 'headerRenderer';
55
+ }
56
+
57
+ export declare class GridColumnFooterRendererDirective extends AbstractGridColumnRendererDirective<GridColumnFooterLitRenderer> {
58
+ rendererProperty: 'footerRenderer';
59
+ }
60
+
61
+ /**
62
+ * A Lit directive for rendering the content of the column's body cells.
63
+ *
64
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the grid column
65
+ * via the `renderer` property. The renderer is called for each column's body cell when assigned and whenever
66
+ * a single dependency or an array of dependencies changes.
67
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
68
+ *
69
+ * Dependencies can be a single value or an array of values.
70
+ * Values are checked against previous values with strict equality (`===`),
71
+ * so the check won't detect nested property changes inside objects or arrays.
72
+ * When dependencies are provided as an array, each item is checked against the previous value
73
+ * at the same index with strict equality. Nested arrays are also checked only by strict
74
+ * equality.
75
+ *
76
+ * Example of usage:
77
+ * ```js
78
+ * `<vaadin-grid-column
79
+ * ${columnBodyRenderer((item, model, column) => html`...`)}
80
+ * ></vaadin-grid-column>`
81
+ * ```
82
+ *
83
+ * @param renderer the renderer callback.
84
+ * @param dependencies a single dependency or an array of dependencies
85
+ * which trigger a re-render when changed.
86
+ */
87
+ export declare function columnBodyRenderer<TItem>(
88
+ renderer: GridColumnBodyLitRenderer<TItem>,
89
+ dependencies?: unknown,
90
+ ): DirectiveResult<typeof GridColumnBodyRendererDirective>;
91
+
92
+ /**
93
+ * A Lit directive for rendering the content of the column's header cell.
94
+ *
95
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the grid column
96
+ * via the `headerRenderer` property. The renderer is called once when assigned and whenever
97
+ * a single dependency or an array of dependencies changes.
98
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
99
+ *
100
+ * Dependencies can be a single value or an array of values.
101
+ * Values are checked against previous values with strict equality (`===`),
102
+ * so the check won't detect nested property changes inside objects or arrays.
103
+ * When dependencies are provided as an array, each item is checked against the previous value
104
+ * at the same index with strict equality. Nested arrays are also checked only by strict
105
+ * equality.
106
+ *
107
+ * Example of usage:
108
+ * ```js
109
+ * `<vaadin-grid-column
110
+ * ${columnHeaderRenderer((column) => html`...`)}
111
+ * ></vaadin-grid-column>`
112
+ * ```
113
+ *
114
+ * @param renderer the renderer callback.
115
+ * @param dependencies a single dependency or an array of dependencies
116
+ * which trigger a re-render when changed.
117
+ */
118
+ export declare function columnHeaderRenderer(
119
+ renderer: GridColumnHeaderLitRenderer,
120
+ dependencies?: unknown,
121
+ ): DirectiveResult<typeof GridColumnHeaderRendererDirective>;
122
+
123
+ /**
124
+ * A Lit directive for rendering the content of the column's footer cell.
125
+ *
126
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the grid column
127
+ * via the `footerRenderer` property. The renderer is called once when assigned and whenever
128
+ * a single dependency or an array of dependencies changes.
129
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
130
+ *
131
+ * Dependencies can be a single value or an array of values.
132
+ * Values are checked against previous values with strict equality (`===`),
133
+ * so the check won't detect nested property changes inside objects or arrays.
134
+ * When dependencies are provided as an array, each item is checked against the previous value
135
+ * at the same index with strict equality. Nested arrays are also checked only by strict
136
+ * equality.
137
+ *
138
+ * Example of usage:
139
+ * ```js
140
+ * `<vaadin-grid-column
141
+ * ${columnFooterRenderer((column) => html`...`)}
142
+ * ></vaadin-grid-column>`
143
+ * ```
144
+ *
145
+ * @param renderer the renderer callback.
146
+ * @param dependencies a single dependency or an array of dependencies
147
+ * which trigger a re-render when changed.
148
+ */
149
+ export declare function columnFooterRenderer(
150
+ renderer: GridColumnFooterLitRenderer,
151
+ dependencies?: unknown,
152
+ ): DirectiveResult<typeof GridColumnFooterRendererDirective>;
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ /* eslint-disable max-classes-per-file */
7
+ import { directive } from 'lit/directive.js';
8
+ import { microTask } from '@vaadin/component-base/src/async.js';
9
+ import { Debouncer } from '@vaadin/component-base/src/debounce.js';
10
+ import { LitRendererDirective } from '@vaadin/lit-renderer';
11
+ import { CONTENT_UPDATE_DEBOUNCER } from './renderer-directives.js';
12
+
13
+ class AbstractGridColumnRendererDirective extends LitRendererDirective {
14
+ /**
15
+ * A property to that the renderer callback will be assigned.
16
+ *
17
+ * @abstract
18
+ */
19
+ rendererProperty;
20
+
21
+ /**
22
+ * Adds the renderer callback to the grid column.
23
+ */
24
+ addRenderer() {
25
+ this.element[this.rendererProperty] = (root, column) => {
26
+ this.renderRenderer(root, column);
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Runs the renderer callback on the grid column.
32
+ */
33
+ runRenderer() {
34
+ const grid = this.element._grid;
35
+
36
+ grid[CONTENT_UPDATE_DEBOUNCER] = Debouncer.debounce(grid[CONTENT_UPDATE_DEBOUNCER], microTask, () => {
37
+ grid.requestContentUpdate();
38
+ });
39
+ }
40
+
41
+ /**
42
+ * Removes the renderer callback from the grid column.
43
+ */
44
+ removeRenderer() {
45
+ this.element[this.rendererProperty] = null;
46
+ }
47
+ }
48
+
49
+ export class GridColumnBodyRendererDirective extends AbstractGridColumnRendererDirective {
50
+ rendererProperty = 'renderer';
51
+
52
+ addRenderer() {
53
+ this.element[this.rendererProperty] = (root, column, model) => {
54
+ this.renderRenderer(root, model.item, model, column);
55
+ };
56
+ }
57
+ }
58
+
59
+ export class GridColumnHeaderRendererDirective extends AbstractGridColumnRendererDirective {
60
+ rendererProperty = 'headerRenderer';
61
+ }
62
+
63
+ export class GridColumnFooterRendererDirective extends AbstractGridColumnRendererDirective {
64
+ rendererProperty = 'footerRenderer';
65
+ }
66
+
67
+ /**
68
+ * A Lit directive for rendering the content of the column's body cells.
69
+ *
70
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the grid column
71
+ * via the `renderer` property. The renderer is called for each column's body cell when assigned and whenever
72
+ * a single dependency or an array of dependencies changes.
73
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
74
+ *
75
+ * Dependencies can be a single value or an array of values.
76
+ * Values are checked against previous values with strict equality (`===`),
77
+ * so the check won't detect nested property changes inside objects or arrays.
78
+ * When dependencies are provided as an array, each item is checked against the previous value
79
+ * at the same index with strict equality. Nested arrays are also checked only by strict
80
+ * equality.
81
+ *
82
+ * Example of usage:
83
+ * ```js
84
+ * `<vaadin-grid-column
85
+ * ${columnBodyRenderer((item, model, column) => html`...`)}
86
+ * ></vaadin-grid-column>`
87
+ * ```
88
+ *
89
+ * @param renderer the renderer callback.
90
+ * @param dependencies a single dependency or an array of dependencies
91
+ * which trigger a re-render when changed.
92
+ */
93
+ export const columnBodyRenderer = directive(GridColumnBodyRendererDirective);
94
+
95
+ /**
96
+ * A Lit directive for rendering the content of the column's header cell.
97
+ *
98
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the grid column
99
+ * via the `headerRenderer` property. The renderer is called once when assigned and whenever
100
+ * a single dependency or an array of dependencies changes.
101
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
102
+ *
103
+ * Dependencies can be a single value or an array of values.
104
+ * Values are checked against previous values with strict equality (`===`),
105
+ * so the check won't detect nested property changes inside objects or arrays.
106
+ * When dependencies are provided as an array, each item is checked against the previous value
107
+ * at the same index with strict equality. Nested arrays are also checked only by strict
108
+ * equality.
109
+ *
110
+ * Example of usage:
111
+ * ```js
112
+ * `<vaadin-grid-column
113
+ * ${columnHeaderRenderer((column) => html`...`)}
114
+ * ></vaadin-grid-column>`
115
+ * ```
116
+ *
117
+ * @param renderer the renderer callback.
118
+ * @param dependencies a single dependency or an array of dependencies
119
+ * which trigger a re-render when changed.
120
+ */
121
+ export const columnHeaderRenderer = directive(GridColumnHeaderRendererDirective);
122
+
123
+ /**
124
+ * A Lit directive for rendering the content of the column's footer cell.
125
+ *
126
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the grid column
127
+ * via the `footerRenderer` property. The renderer is called once when assigned and whenever
128
+ * a single dependency or an array of dependencies changes.
129
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
130
+ *
131
+ * Dependencies can be a single value or an array of values.
132
+ * Values are checked against previous values with strict equality (`===`),
133
+ * so the check won't detect nested property changes inside objects or arrays.
134
+ * When dependencies are provided as an array, each item is checked against the previous value
135
+ * at the same index with strict equality. Nested arrays are also checked only by strict
136
+ * equality.
137
+ *
138
+ * Example of usage:
139
+ * ```js
140
+ * `<vaadin-grid-column
141
+ * ${columnFooterRenderer((column) => html`...`)}
142
+ * ></vaadin-grid-column>`
143
+ * ```
144
+ *
145
+ * @param renderer the renderer callback.
146
+ * @param dependencies a single dependency or an array of dependencies
147
+ * which trigger a re-render when changed.
148
+ */
149
+ export const columnFooterRenderer = directive(GridColumnFooterRendererDirective);
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { TemplateResult } from 'lit';
7
+ import { DirectiveResult } from 'lit/directive';
8
+ import { LitRendererDirective } from '@vaadin/lit-renderer';
9
+ import { Grid, GridItemModel } from '../vaadin-grid.js';
10
+
11
+ export type GridRowDetailsLitRenderer<TItem> = (item: TItem, model: GridItemModel<TItem>, grid: Grid) => TemplateResult;
12
+
13
+ export declare class GridRowDetailsRendererDirective<TItem> extends LitRendererDirective<
14
+ Grid,
15
+ GridRowDetailsLitRenderer<TItem>
16
+ > {
17
+ /**
18
+ * Adds the row details renderer callback to the grid.
19
+ */
20
+ addRenderer(): void;
21
+
22
+ /**
23
+ * Runs the row details renderer callback on the grid.
24
+ */
25
+ runRenderer(): void;
26
+
27
+ /**
28
+ * Removes the row details renderer callback from the grid.
29
+ */
30
+ removeRenderer(): void;
31
+ }
32
+
33
+ /**
34
+ * A Lit directive for rendering the content of the row details cell.
35
+ *
36
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the grid
37
+ * via the `rowDetailsRenderer` property. The renderer is called for each grid item that is in `detailsOpened`
38
+ * when assigned and whenever a single dependency or an array of dependencies changes.
39
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
40
+ *
41
+ * Dependencies can be a single value or an array of values.
42
+ * Values are checked against previous values with strict equality (`===`),
43
+ * so the check won't detect nested property changes inside objects or arrays.
44
+ * When dependencies are provided as an array, each item is checked against the previous value
45
+ * at the same index with strict equality. Nested arrays are also checked only by strict
46
+ * equality.
47
+ *
48
+ * Example of usage:
49
+ * ```js
50
+ * `<vaadin-grid
51
+ * ${gridRowDetailsRenderer((item, model, grid) => html`...`)}
52
+ * ></vaadin-grid>`
53
+ * ```
54
+ *
55
+ * @param renderer the renderer callback.
56
+ * @param dependencies a single dependency or an array of dependencies
57
+ * which trigger a re-render when changed.
58
+ */
59
+ export declare function gridRowDetailsRenderer<TItem>(
60
+ renderer: GridRowDetailsLitRenderer<TItem>,
61
+ dependencies?: unknown,
62
+ ): DirectiveResult<typeof GridRowDetailsRendererDirective>;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { directive } from 'lit/directive.js';
7
+ import { microTask } from '@vaadin/component-base/src/async.js';
8
+ import { Debouncer } from '@vaadin/component-base/src/debounce.js';
9
+ import { LitRendererDirective } from '@vaadin/lit-renderer';
10
+
11
+ export const CONTENT_UPDATE_DEBOUNCER = Symbol('contentUpdateDebouncer');
12
+
13
+ export class GridRowDetailsRendererDirective extends LitRendererDirective {
14
+ /**
15
+ * Adds the row details renderer callback to the grid.
16
+ */
17
+ addRenderer() {
18
+ this.element.rowDetailsRenderer = (root, grid, model) => {
19
+ this.renderRenderer(root, model.item, model, grid);
20
+ };
21
+ }
22
+
23
+ /**
24
+ * Runs the row details renderer callback on the grid.
25
+ */
26
+ runRenderer() {
27
+ this.element[CONTENT_UPDATE_DEBOUNCER] = Debouncer.debounce(
28
+ this.element[CONTENT_UPDATE_DEBOUNCER],
29
+ microTask,
30
+ () => {
31
+ this.element.requestContentUpdate();
32
+ },
33
+ );
34
+ }
35
+
36
+ /**
37
+ * Removes the row details renderer callback from the grid.
38
+ */
39
+ removeRenderer() {
40
+ this.element.rowDetailsRenderer = null;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * A Lit directive for rendering the content of the row details cell.
46
+ *
47
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the grid
48
+ * via the `rowDetailsRenderer` property. The renderer is called for each grid item that is in `detailsOpened`
49
+ * when assigned and whenever a single dependency or an array of dependencies changes.
50
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
51
+ *
52
+ * Dependencies can be a single value or an array of values.
53
+ * Values are checked against previous values with strict equality (`===`),
54
+ * so the check won't detect nested property changes inside objects or arrays.
55
+ * When dependencies are provided as an array, each item is checked against the previous value
56
+ * at the same index with strict equality. Nested arrays are also checked only by strict
57
+ * equality.
58
+ *
59
+ * Example of usage:
60
+ * ```js
61
+ * `<vaadin-grid
62
+ * ${gridRowDetailsRenderer((item, model, grid) => html`...`)}
63
+ * ></vaadin-grid>`
64
+ * ```
65
+ *
66
+ * @param renderer the renderer callback.
67
+ * @param dependencies a single dependency or an array of dependencies
68
+ * which trigger a re-render when changed.
69
+ */
70
+ export const gridRowDetailsRenderer = directive(GridRowDetailsRendererDirective);
@@ -50,7 +50,7 @@ class GridColumnGroup extends ColumnBaseMixin(PolymerElement) {
50
50
  return {
51
51
  /** @private */
52
52
  _childColumns: {
53
- value: function () {
53
+ value() {
54
54
  return this._getChildColumns(this);
55
55
  },
56
56
  },
@@ -85,12 +85,9 @@ class GridColumnGroup extends ColumnBaseMixin(PolymerElement) {
85
85
 
86
86
  static get observers() {
87
87
  return [
88
- '_updateVisibleChildColumns(_childColumns)',
89
- '_childColumnsChanged(_childColumns)',
90
88
  '_groupFrozenChanged(frozen, _rootColumns)',
91
89
  '_groupFrozenToEndChanged(frozenToEnd, _rootColumns)',
92
- '_groupHiddenChanged(hidden, _rootColumns)',
93
- '_visibleChildColumnsChanged(_visibleChildColumns)',
90
+ '_groupHiddenChanged(hidden)',
94
91
  '_colSpanChanged(_colSpan, _headerCell, _footerCell)',
95
92
  '_groupOrderChanged(_order, _rootColumns)',
96
93
  '_groupReorderStatusChanged(_reorderStatus, _rootColumns)',
@@ -120,9 +117,12 @@ class GridColumnGroup extends ColumnBaseMixin(PolymerElement) {
120
117
  */
121
118
  _columnPropChanged(path, value) {
122
119
  if (path === 'hidden') {
123
- this._preventHiddenCascade = true;
120
+ // Prevent synchronization of the hidden state to child columns.
121
+ // If the group is currently auto-hidden, and one column is made visible,
122
+ // we don't want the other columns to become visible as well.
123
+ this._preventHiddenSynchronization = true;
124
124
  this._updateVisibleChildColumns(this._childColumns);
125
- this._preventHiddenCascade = false;
125
+ this._preventHiddenSynchronization = false;
126
126
  }
127
127
 
128
128
  if (/flexGrow|width|hidden|_childColumns/.test(path)) {
@@ -205,14 +205,8 @@ class GridColumnGroup extends ColumnBaseMixin(PolymerElement) {
205
205
  /** @private */
206
206
  _updateVisibleChildColumns(childColumns) {
207
207
  this._visibleChildColumns = Array.prototype.filter.call(childColumns, (col) => !col.hidden);
208
- }
209
-
210
- /** @private */
211
- _childColumnsChanged(childColumns) {
212
- if (!this._autoHidden && this.hidden) {
213
- Array.prototype.forEach.call(childColumns, (column) => (column.hidden = true));
214
- this._updateVisibleChildColumns(childColumns);
215
- }
208
+ this._colSpan = this._visibleChildColumns.length;
209
+ this._updateAutoHidden();
216
210
  }
217
211
 
218
212
  /** @protected */
@@ -258,26 +252,31 @@ class GridColumnGroup extends ColumnBaseMixin(PolymerElement) {
258
252
  }
259
253
 
260
254
  /** @private */
261
- _groupHiddenChanged(hidden, rootColumns) {
262
- if (rootColumns && !this._preventHiddenCascade) {
263
- this._ignoreVisibleChildColumns = true;
264
- rootColumns.forEach((column) => (column.hidden = hidden));
265
- this._ignoreVisibleChildColumns = false;
255
+ _groupHiddenChanged(hidden) {
256
+ // When initializing the hidden property, only sync hidden state to columns
257
+ // if group is actually hidden. Otherwise, we could override a hidden column
258
+ // to be visible.
259
+ // We always want to run this though if the property is actually changed.
260
+ if (hidden || this.__groupHiddenInitialized) {
261
+ this._synchronizeHidden();
266
262
  }
263
+ this.__groupHiddenInitialized = true;
264
+ }
267
265
 
268
- this._columnPropChanged('hidden');
266
+ /** @private */
267
+ _updateAutoHidden() {
268
+ const wasAutoHidden = this._autoHidden;
269
+ this._autoHidden = (this._visibleChildColumns || []).length === 0;
270
+ // Only modify hidden state if group was auto-hidden, or becomes auto-hidden
271
+ if (wasAutoHidden || this._autoHidden) {
272
+ this.hidden = this._autoHidden;
273
+ }
269
274
  }
270
275
 
271
276
  /** @private */
272
- _visibleChildColumnsChanged(visibleChildColumns) {
273
- this._colSpan = visibleChildColumns.length;
274
-
275
- if (!this._ignoreVisibleChildColumns) {
276
- if (visibleChildColumns.length === 0) {
277
- this._autoHidden = this.hidden = true;
278
- } else if (this.hidden && this._autoHidden) {
279
- this._autoHidden = this.hidden = false;
280
- }
277
+ _synchronizeHidden() {
278
+ if (this._childColumns && !this._preventHiddenSynchronization) {
279
+ this._childColumns.forEach((column) => (column.hidden = this.hidden));
281
280
  }
282
281
  }
283
282
 
@@ -313,10 +312,14 @@ class GridColumnGroup extends ColumnBaseMixin(PolymerElement) {
313
312
  info.addedNodes.filter(this._isColumnElement).length > 0 ||
314
313
  info.removedNodes.filter(this._isColumnElement).length > 0
315
314
  ) {
316
- this._preventHiddenCascade = true;
315
+ // Prevent synchronization of the hidden state to child columns.
316
+ // If the group is currently auto-hidden, and a visible column is added,
317
+ // we don't want the other columns to become visible as well.
318
+ this._preventHiddenSynchronization = true;
317
319
  this._rootColumns = this._getChildColumns(this);
318
320
  this._childColumns = this._rootColumns;
319
- this._preventHiddenCascade = false;
321
+ this._updateVisibleChildColumns(this._childColumns);
322
+ this._preventHiddenSynchronization = false;
320
323
 
321
324
  // Update the column tree with microtask timing to avoid shady style scope issues
322
325
  microTask.run(() => {
@@ -318,8 +318,8 @@ export const ColumnReorderingMixin = (superClass) =>
318
318
  const differentColumns = column1 !== column2;
319
319
  const sameParent = column1.parentElement === column2.parentElement;
320
320
  const sameFrozen =
321
- (column1.frozen && column2.frozen) || // both columns are frozen
322
- (column1.frozenToEnd && column2.frozenToEnd) || // both columns are frozen to end
321
+ (column1.frozen && column2.frozen) || // Both columns are frozen
322
+ (column1.frozenToEnd && column2.frozenToEnd) || // Both columns are frozen to end
323
323
  (!column1.frozen && !column1.frozenToEnd && !column2.frozen && !column2.frozenToEnd);
324
324
  return differentColumns && sameParent && sameFrozen;
325
325
  }
@@ -22,7 +22,7 @@ export const ColumnBaseMixin = (superClass) =>
22
22
  */
23
23
  resizable: {
24
24
  type: Boolean,
25
- value: function () {
25
+ value() {
26
26
  if (this.localName === 'vaadin-grid-column-group') {
27
27
  return;
28
28
  }
@@ -172,7 +172,7 @@ export const DataProviderMixin = (superClass) =>
172
172
  */
173
173
  _cache: {
174
174
  type: Object,
175
- value: function () {
175
+ value() {
176
176
  const cache = new ItemCache(this);
177
177
  return cache;
178
178
  },
@@ -344,7 +344,7 @@ export const DataProviderMixin = (superClass) =>
344
344
  * @protected
345
345
  */
346
346
  _loadPage(page, cache) {
347
- // make sure same page isn't requested multiple times.
347
+ // Make sure same page isn't requested multiple times.
348
348
  if (!cache.pendingRequests[page] && this.dataProvider) {
349
349
  this._setLoading(true);
350
350
  cache.pendingRequests[page] = true;
@@ -466,7 +466,7 @@ export const DataProviderMixin = (superClass) =>
466
466
  /** @protected */
467
467
  _ensureFirstPageLoaded() {
468
468
  if (!this._hasData) {
469
- // load data before adding rows to make sure they have content when
469
+ // Load data before adding rows to make sure they have content when
470
470
  // rendered for the first time.
471
471
  this._loadPage(0, this._cache);
472
472
  }
@@ -16,7 +16,7 @@ function arrayEquals(arr1, arr2) {
16
16
  for (let i = 0, l = arr1.length; i < l; i++) {
17
17
  // Check if we have nested arrays
18
18
  if (arr1[i] instanceof Array && arr2[i] instanceof Array) {
19
- // recurse into the nested arrays
19
+ // Recurse into the nested arrays
20
20
  if (!arrayEquals(arr1[i], arr2[i])) {
21
21
  return false;
22
22
  }
@@ -14,9 +14,7 @@ export const FilterMixin = (superClass) =>
14
14
  /** @private */
15
15
  _filters: {
16
16
  type: Array,
17
- value: function () {
18
- return [];
19
- },
17
+ value: () => [],
20
18
  },
21
19
  };
22
20
  }
@@ -12,7 +12,7 @@
12
12
  export function updateColumnOrders(columns, scope, baseOrder) {
13
13
  let c = 1;
14
14
  columns.forEach((column) => {
15
- // avoid multiples of 10 because they introduce and extra zero and
15
+ // Avoid multiples of 10 because they introduce and extra zero and
16
16
  // causes the underlying calculations for child order goes wrong
17
17
  if (c % 10 === 0) {
18
18
  c += 1;
@@ -617,6 +617,11 @@ export const KeyboardNavigationMixin = (superClass) =>
617
617
  _onTabKeyDown(e) {
618
618
  const focusTarget = this._predictFocusStepTarget(e.composedPath()[0], e.shiftKey ? -1 : 1);
619
619
 
620
+ // Can be undefined if grid has tabindex
621
+ if (!focusTarget) {
622
+ return;
623
+ }
624
+
620
625
  // Prevent focus-trap logic from intercepting the event.
621
626
  e.stopPropagation();
622
627
 
@@ -734,9 +739,7 @@ export const KeyboardNavigationMixin = (superClass) =>
734
739
  if (cell) {
735
740
  // Fire a public event for cell.
736
741
  const context = this.getEventContext(e);
737
- cell.dispatchEvent(
738
- new CustomEvent('cell-focus', { bubbles: true, composed: true, detail: { context: context } }),
739
- );
742
+ cell.dispatchEvent(new CustomEvent('cell-focus', { bubbles: true, composed: true, detail: { context } }));
740
743
  }
741
744
  }
742
745
 
@@ -17,9 +17,7 @@ export const RowDetailsMixin = (superClass) =>
17
17
  */
18
18
  detailsOpenedItems: {
19
19
  type: Array,
20
- value: function () {
21
- return [];
22
- },
20
+ value: () => [],
23
21
  },
24
22
 
25
23
  /**
@@ -63,9 +63,6 @@ export const ScrollMixin = (superClass) =>
63
63
  ready() {
64
64
  super.ready();
65
65
 
66
- // Preserve accessor to the legacy scrolling functionality
67
- this.$.outerscroller = document.createElement('div');
68
-
69
66
  this.scrollTarget = this.$.table;
70
67
 
71
68
  this.$.items.addEventListener('focusin', (e) => {
@@ -235,7 +235,7 @@ class GridSelectionColumn extends GridColumn {
235
235
  }
236
236
 
237
237
  /**
238
- * iOS needs indeterminate + checked at the same time
238
+ * IOS needs indeterminate + checked at the same time
239
239
  * @private
240
240
  */
241
241
  __isChecked(selectAll, indeterminate) {
@@ -20,11 +20,20 @@ export const SelectionMixin = (superClass) =>
20
20
  notify: true,
21
21
  value: () => [],
22
22
  },
23
+
24
+ /**
25
+ * Set of selected item ids
26
+ * @private
27
+ */
28
+ __selectedKeys: {
29
+ type: Object,
30
+ value: () => new Set(),
31
+ },
23
32
  };
24
33
  }
25
34
 
26
35
  static get observers() {
27
- return ['_selectedItemsChanged(selectedItems.*)'];
36
+ return ['_updateSelectedKeys(itemIdPath, selectedItems.*)'];
28
37
  }
29
38
 
30
39
  /**
@@ -33,7 +42,7 @@ export const SelectionMixin = (superClass) =>
33
42
  * @protected
34
43
  */
35
44
  _isSelected(item) {
36
- return this.selectedItems && this._getItemIndexInArray(item, this.selectedItems) > -1;
45
+ return this.__selectedKeys.has(this.getItemId(item));
37
46
  }
38
47
 
39
48
  /**
@@ -68,8 +77,7 @@ export const SelectionMixin = (superClass) =>
68
77
  * @protected
69
78
  */
70
79
  _toggleItem(item) {
71
- const index = this._getItemIndexInArray(item, this.selectedItems);
72
- if (index === -1) {
80
+ if (!this._isSelected(item)) {
73
81
  this.selectItem(item);
74
82
  } else {
75
83
  this.deselectItem(item);
@@ -77,7 +85,13 @@ export const SelectionMixin = (superClass) =>
77
85
  }
78
86
 
79
87
  /** @private */
80
- _selectedItemsChanged() {
88
+ _updateSelectedKeys() {
89
+ const selectedItems = this.selectedItems || [];
90
+ this.__selectedKeys = new Set();
91
+ selectedItems.forEach((item) => {
92
+ this.__selectedKeys.add(this.getItemId(item));
93
+ });
94
+
81
95
  this.requestContentUpdate();
82
96
  }
83
97
 
@@ -27,17 +27,13 @@ export const SortMixin = (superClass) =>
27
27
  */
28
28
  _sorters: {
29
29
  type: Array,
30
- value: function () {
31
- return [];
32
- },
30
+ value: () => [],
33
31
  },
34
32
 
35
33
  /** @private */
36
34
  _previousSorters: {
37
35
  type: Array,
38
- value: function () {
39
- return [];
40
- },
36
+ value: () => [],
41
37
  },
42
38
  };
43
39
  }
@@ -49,7 +49,7 @@ export const StylingMixin = (superClass) =>
49
49
  */
50
50
  generateCellClassNames() {
51
51
  Array.from(this.$.items.children)
52
- .filter((row) => !row.hidden)
52
+ .filter((row) => !row.hidden && !row.hasAttribute('loading'))
53
53
  .forEach((row) => this._generateCellClassNames(row, this.__getRowModel(row)));
54
54
  }
55
55
 
@@ -95,8 +95,8 @@ export type GridExpandedItemsChangedEvent<TItem> = CustomEvent<{ value: TItem[]
95
95
  */
96
96
  export type GridDragStartEvent<TItem> = CustomEvent<{
97
97
  draggedItems: TItem[];
98
- setDraggedItemsCount: (count: number) => void;
99
- setDragData: (type: string, data: string) => void;
98
+ setDraggedItemsCount(count: number): void;
99
+ setDragData(type: string, data: string): void;
100
100
  }>;
101
101
 
102
102
  /**
@@ -558,7 +558,7 @@ class Grid extends ElementMixin(
558
558
 
559
559
  const columnWidth = Math.max(this.__getIntrinsicWidth(col), this.__getDistributedWidth(col.parentElement, col));
560
560
 
561
- // we're processing a regular grid-column and not a grid-column-group
561
+ // We're processing a regular grid-column and not a grid-column-group
562
562
  if (!innerColumn) {
563
563
  return columnWidth;
564
564
  }
@@ -897,7 +897,8 @@ class Grid extends ElementMixin(
897
897
  }
898
898
 
899
899
  __updateFooterPositioning() {
900
- if (this._firefox) {
900
+ // TODO: fixed in Firefox 99, remove when we can drop Firefox ESR 91 support
901
+ if (this._firefox && parseFloat(navigator.userAgent.match(/Firefox\/(\d{2,3}.\d)/)[1]) < 99) {
901
902
  // Sticky (or translated) footer in a flexbox host doesn't get included in
902
903
  // the scroll height calculation on FF. This is a workaround for the issue.
903
904
  this.$.items.style.paddingBottom = 0;
@@ -989,14 +990,14 @@ class Grid extends ElementMixin(
989
990
  */
990
991
  requestContentUpdate() {
991
992
  if (this._columnTree) {
992
- // header and footer renderers
993
+ // Header and footer renderers
993
994
  this._columnTree.forEach((level) => {
994
995
  level.forEach((column) => {
995
996
  column._renderHeaderAndFooter();
996
997
  });
997
998
  });
998
999
 
999
- // body and row details renderers
1000
+ // Body and row details renderers
1000
1001
  this.__updateVisibleRows();
1001
1002
  }
1002
1003
  }