@vaadin/vaadin-grid 22.0.0-alpha6 → 22.0.0-beta1

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.
Files changed (84) hide show
  1. package/package.json +24 -34
  2. package/src/vaadin-grid-column-group.d.ts +14 -57
  3. package/src/vaadin-grid-column-group.js +4 -311
  4. package/src/vaadin-grid-column.d.ts +14 -142
  5. package/src/vaadin-grid-column.js +4 -759
  6. package/src/vaadin-grid-filter-column.d.ts +14 -30
  7. package/src/vaadin-grid-filter-column.js +4 -111
  8. package/src/vaadin-grid-filter.d.ts +11 -60
  9. package/src/vaadin-grid-filter.js +4 -116
  10. package/src/vaadin-grid-selection-column.d.ts +12 -75
  11. package/src/vaadin-grid-selection-column.js +4 -276
  12. package/src/vaadin-grid-sort-column.d.ts +12 -56
  13. package/src/vaadin-grid-sort-column.js +4 -109
  14. package/src/vaadin-grid-sorter.d.ts +11 -82
  15. package/src/vaadin-grid-sorter.js +4 -221
  16. package/src/vaadin-grid-tree-column.d.ts +14 -31
  17. package/src/vaadin-grid-tree-column.js +4 -110
  18. package/src/vaadin-grid-tree-toggle.d.ts +11 -91
  19. package/src/vaadin-grid-tree-toggle.js +4 -196
  20. package/src/vaadin-grid.d.ts +10 -422
  21. package/src/vaadin-grid.js +4 -1026
  22. package/theme/lumo/vaadin-grid-column-group.js +1 -1
  23. package/theme/lumo/vaadin-grid-column.js +1 -1
  24. package/theme/lumo/vaadin-grid-filter-column.js +1 -2
  25. package/theme/lumo/vaadin-grid-filter.js +1 -2
  26. package/theme/lumo/vaadin-grid-selection-column.js +1 -2
  27. package/theme/lumo/vaadin-grid-sort-column.js +1 -2
  28. package/theme/lumo/vaadin-grid-sorter.js +1 -2
  29. package/theme/lumo/vaadin-grid-tree-column.js +1 -2
  30. package/theme/lumo/vaadin-grid-tree-toggle.js +1 -2
  31. package/theme/lumo/vaadin-grid.js +1 -9
  32. package/theme/material/vaadin-grid-column-group.js +1 -1
  33. package/theme/material/vaadin-grid-column.js +1 -1
  34. package/theme/material/vaadin-grid-filter-column.js +1 -2
  35. package/theme/material/vaadin-grid-filter.js +1 -2
  36. package/theme/material/vaadin-grid-selection-column.js +1 -2
  37. package/theme/material/vaadin-grid-sort-column.js +1 -2
  38. package/theme/material/vaadin-grid-sorter.js +1 -2
  39. package/theme/material/vaadin-grid-tree-column.js +1 -2
  40. package/theme/material/vaadin-grid-tree-toggle.js +1 -2
  41. package/theme/material/vaadin-grid.js +1 -2
  42. package/vaadin-grid.d.ts +0 -1
  43. package/src/array-data-provider.js +0 -145
  44. package/src/interfaces.d.ts +0 -78
  45. package/src/vaadin-grid-a11y-mixin.d.ts +0 -27
  46. package/src/vaadin-grid-a11y-mixin.js +0 -158
  47. package/src/vaadin-grid-active-item-mixin.d.ts +0 -28
  48. package/src/vaadin-grid-active-item-mixin.js +0 -117
  49. package/src/vaadin-grid-array-data-provider-mixin.d.ts +0 -20
  50. package/src/vaadin-grid-array-data-provider-mixin.js +0 -75
  51. package/src/vaadin-grid-column-reordering-mixin.d.ts +0 -47
  52. package/src/vaadin-grid-column-reordering-mixin.js +0 -387
  53. package/src/vaadin-grid-column-resizing-mixin.d.ts +0 -11
  54. package/src/vaadin-grid-column-resizing-mixin.js +0 -111
  55. package/src/vaadin-grid-data-provider-mixin.d.ts +0 -126
  56. package/src/vaadin-grid-data-provider-mixin.js +0 -520
  57. package/src/vaadin-grid-drag-and-drop-mixin.d.ts +0 -73
  58. package/src/vaadin-grid-drag-and-drop-mixin.js +0 -435
  59. package/src/vaadin-grid-dynamic-columns-mixin.d.ts +0 -27
  60. package/src/vaadin-grid-dynamic-columns-mixin.js +0 -180
  61. package/src/vaadin-grid-event-context-mixin.d.ts +0 -33
  62. package/src/vaadin-grid-event-context-mixin.js +0 -57
  63. package/src/vaadin-grid-filter-mixin.d.ts +0 -13
  64. package/src/vaadin-grid-filter-mixin.js +0 -76
  65. package/src/vaadin-grid-helpers.js +0 -23
  66. package/src/vaadin-grid-keyboard-navigation-mixin.d.ts +0 -31
  67. package/src/vaadin-grid-keyboard-navigation-mixin.js +0 -891
  68. package/src/vaadin-grid-row-details-mixin.d.ts +0 -54
  69. package/src/vaadin-grid-row-details-mixin.js +0 -200
  70. package/src/vaadin-grid-scroll-mixin.d.ts +0 -22
  71. package/src/vaadin-grid-scroll-mixin.js +0 -202
  72. package/src/vaadin-grid-selection-mixin.d.ts +0 -39
  73. package/src/vaadin-grid-selection-mixin.js +0 -93
  74. package/src/vaadin-grid-sort-mixin.d.ts +0 -21
  75. package/src/vaadin-grid-sort-mixin.js +0 -139
  76. package/src/vaadin-grid-styles.js +0 -297
  77. package/src/vaadin-grid-styling-mixin.d.ts +0 -37
  78. package/src/vaadin-grid-styling-mixin.js +0 -71
  79. package/theme/lumo/vaadin-grid-sorter-styles.js +0 -54
  80. package/theme/lumo/vaadin-grid-styles.js +0 -380
  81. package/theme/lumo/vaadin-grid-tree-toggle-styles.js +0 -112
  82. package/theme/material/vaadin-grid-sorter-styles.js +0 -72
  83. package/theme/material/vaadin-grid-styles.js +0 -252
  84. package/theme/material/vaadin-grid-tree-toggle-styles.js +0 -42
@@ -3,1033 +3,11 @@
3
3
  * Copyright (c) 2021 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { beforeNextRender } from '@polymer/polymer/lib/utils/render-status.js';
7
- import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
8
- import { animationFrame } from '@polymer/polymer/lib/utils/async.js';
9
- import { ElementMixin } from '@vaadin/vaadin-element-mixin/vaadin-element-mixin.js';
10
- import { processTemplates } from '@vaadin/vaadin-element-mixin/templates.js';
11
- import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
12
- import { PolymerElement, html } from '@polymer/polymer/polymer-element.js';
13
- import { A11yMixin } from './vaadin-grid-a11y-mixin.js';
14
- import { ActiveItemMixin } from './vaadin-grid-active-item-mixin.js';
15
- import { ArrayDataProviderMixin } from './vaadin-grid-array-data-provider-mixin.js';
16
- import { ColumnResizingMixin } from './vaadin-grid-column-resizing-mixin.js';
17
- import { DataProviderMixin } from './vaadin-grid-data-provider-mixin.js';
18
- import { DynamicColumnsMixin } from './vaadin-grid-dynamic-columns-mixin.js';
19
- import { EventContextMixin } from './vaadin-grid-event-context-mixin.js';
20
- import { FilterMixin } from './vaadin-grid-filter-mixin.js';
21
- import { RowDetailsMixin } from './vaadin-grid-row-details-mixin.js';
22
- import { ScrollMixin } from './vaadin-grid-scroll-mixin.js';
23
- import { SelectionMixin } from './vaadin-grid-selection-mixin.js';
24
- import { SortMixin } from './vaadin-grid-sort-mixin.js';
25
- import { StylingMixin } from './vaadin-grid-styling-mixin.js';
26
- import { DragAndDropMixin } from './vaadin-grid-drag-and-drop-mixin.js';
27
- import { KeyboardNavigationMixin } from './vaadin-grid-keyboard-navigation-mixin.js';
28
- import { ColumnReorderingMixin } from './vaadin-grid-column-reordering-mixin.js';
29
- import { Virtualizer } from '@vaadin/vaadin-virtual-list/src/virtualizer.js';
30
- import './vaadin-grid-column.js';
31
- import './vaadin-grid-styles.js';
32
-
33
- const TOUCH_DEVICE = (() => {
34
- try {
35
- document.createEvent('TouchEvent');
36
- return true;
37
- } catch (e) {
38
- return false;
39
- }
40
- })();
6
+ import { Grid } from '@vaadin/grid/src/vaadin-grid.js';
41
7
 
42
8
  /**
43
- * `<vaadin-grid>` is a free, high quality data grid / data table Web Component. The content of the
44
- * the grid can be populated by using renderer callback function.
45
- *
46
- * ### Quick Start
47
- *
48
- * Start with an assigning an array to the [`items`](#/elements/vaadin-grid#property-items) property to visualize your data.
49
- *
50
- * Use the [`<vaadin-grid-column>`](#/elements/vaadin-grid-column) element to configure the grid columns. Set `path` and `header`
51
- * shorthand properties for the columns to define what gets rendered in the cells of the column.
52
- *
53
- * #### Example:
54
- * ```html
55
- * <vaadin-grid>
56
- * <vaadin-grid-column path="name.first" header="First name"></vaadin-grid-column>
57
- * <vaadin-grid-column path="name.last" header="Last name"></vaadin-grid-column>
58
- * <vaadin-grid-column path="email"></vaadin-grid-column>
59
- * </vaadin-grid>
60
- * ```
61
- *
62
- * For custom content `vaadin-grid-column` element provides you with three types of `renderer` callback functions: `headerRenderer`,
63
- * `renderer` and `footerRenderer`.
64
- *
65
- * Each of those renderer functions provides `root`, `column`, `model` arguments when applicable.
66
- * Generate DOM content, append it to the `root` element and control the state
67
- * of the host element by accessing `column`. Before generating new content,
68
- * users are able to check if there is already content in `root` for reusing it.
69
- *
70
- * Renderers are called on initialization of new column cells and each time the
71
- * related row model is updated. DOM generated during the renderer call can be reused
72
- * in the next renderer call and will be provided with the `root` argument.
73
- * On first call it will be empty.
74
- *
75
- * #### Example:
76
- * ```html
77
- * <vaadin-grid>
78
- * <vaadin-grid-column></vaadin-grid-column>
79
- * <vaadin-grid-column></vaadin-grid-column>
80
- * <vaadin-grid-column></vaadin-grid-column>
81
- * </vaadin-grid>
82
- * ```
83
- * ```js
84
- * const grid = document.querySelector('vaadin-grid');
85
- * grid.items = [{'name': 'John', 'surname': 'Lennon', 'role': 'singer'},
86
- * {'name': 'Ringo', 'surname': 'Starr', 'role': 'drums'}];
87
- *
88
- * const columns = grid.querySelectorAll('vaadin-grid-column');
89
- *
90
- * columns[0].headerRenderer = function(root) {
91
- * root.textContent = 'Name';
92
- * };
93
- * columns[0].renderer = function(root, column, model) {
94
- * root.textContent = model.item.name;
95
- * };
96
- *
97
- * columns[1].headerRenderer = function(root) {
98
- * root.textContent = 'Surname';
99
- * };
100
- * columns[1].renderer = function(root, column, model) {
101
- * root.textContent = model.item.surname;
102
- * };
103
- *
104
- * columns[2].headerRenderer = function(root) {
105
- * root.textContent = 'Role';
106
- * };
107
- * columns[2].renderer = function(root, column, model) {
108
- * root.textContent = model.item.role;
109
- * };
110
- * ```
111
- *
112
- * The following properties are available in the `model` argument:
113
- *
114
- * Property name | Type | Description
115
- * --------------|------|------------
116
- * `index`| Number | The index of the item.
117
- * `item` | String or Object | The item.
118
- * `level` | Number | Number of the item's tree sublevel, starts from 0.
119
- * `expanded` | Boolean | True if the item's tree sublevel is expanded.
120
- * `selected` | Boolean | True if the item is selected.
121
- * `detailsOpened` | Boolean | True if the item's row details are open.
122
- *
123
- * The following helper elements can be used for further customization:
124
- * - [`<vaadin-grid-column-group>`](#/elements/vaadin-grid-column-group)
125
- * - [`<vaadin-grid-filter>`](#/elements/vaadin-grid-filter)
126
- * - [`<vaadin-grid-sorter>`](#/elements/vaadin-grid-sorter)
127
- * - [`<vaadin-grid-selection-column>`](#/elements/vaadin-grid-selection-column)
128
- * - [`<vaadin-grid-tree-toggle>`](#/elements/vaadin-grid-tree-toggle)
129
- *
130
- * __Note that the helper elements must be explicitly imported.__
131
- * If you want to import everything at once you can use the `all-imports.html` bundle.
132
- *
133
- * ### Lazy Loading with Function Data Provider
134
- *
135
- * In addition to assigning an array to the items property, you can alternatively
136
- * provide the `<vaadin-grid>` data through the
137
- * [`dataProvider`](#/elements/vaadin-grid#property-dataProvider) function property.
138
- * The `<vaadin-grid>` calls this function lazily, only when it needs more data
139
- * to be displayed.
140
- *
141
- * See the [`dataProvider`](#/elements/vaadin-grid#property-dataProvider) in
142
- * the API reference below for the detailed data provider arguments description,
143
- * and the “Assigning Data” page in the demos.
144
- *
145
- * __Note that expanding the tree grid's item will trigger a call to the `dataProvider`.__
146
- *
147
- * __Also, note that when using function data providers, the total number of items
148
- * needs to be set manually. The total number of items can be returned
149
- * in the second argument of the data provider callback:__
150
- *
151
- * ```javascript
152
- * grid.dataProvider = function(params, callback) {
153
- * const url = 'https://api.example/data' +
154
- * '?page=' + params.page + // the requested page index
155
- * '&per_page=' + params.pageSize; // number of items on the page
156
- * const xhr = new XMLHttpRequest();
157
- * xhr.onload = function() {
158
- * const response = JSON.parse(xhr.responseText);
159
- * callback(
160
- * response.employees, // requested page of items
161
- * response.totalSize // total number of items
162
- * );
163
- * };
164
- * xhr.open('GET', url, true);
165
- * xhr.send();
166
- * };
167
- * ```
168
- *
169
- * __Alternatively, you can use the `size` property to set the total number of items:__
170
- *
171
- * ```javascript
172
- * grid.size = 200; // The total number of items
173
- * grid.dataProvider = function(params, callback) {
174
- * const url = 'https://api.example/data' +
175
- * '?page=' + params.page + // the requested page index
176
- * '&per_page=' + params.pageSize; // number of items on the page
177
- * const xhr = new XMLHttpRequest();
178
- * xhr.onload = function() {
179
- * const response = JSON.parse(xhr.responseText);
180
- * callback(response.employees);
181
- * };
182
- * xhr.open('GET', url, true);
183
- * xhr.send();
184
- * };
185
- * ```
186
- *
187
- * ### Styling
188
- *
189
- * The following shadow DOM parts are available for styling:
190
- *
191
- * Part name | Description
192
- * ----------------|----------------
193
- * `row` | Row in the internal table
194
- * `cell` | Cell in the internal table
195
- * `header-cell` | Header cell in the internal table
196
- * `body-cell` | Body cell in the internal table
197
- * `footer-cell` | Footer cell in the internal table
198
- * `details-cell` | Row details cell in the internal table
199
- * `resize-handle` | Handle for resizing the columns
200
- * `reorder-ghost` | Ghost element of the header cell being dragged
201
- *
202
- * The following state attributes are available for styling:
203
- *
204
- * Attribute | Description | Part name
205
- * -------------|-------------|------------
206
- * `loading` | Set when the grid is loading data from data provider | :host
207
- * `interacting` | Keyboard navigation in interaction mode | :host
208
- * `navigating` | Keyboard navigation in navigation mode | :host
209
- * `overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `left`, `right` | :host
210
- * `reordering` | Set when the grid's columns are being reordered | :host
211
- * `dragover` | Set when the grid (not a specific row) is dragged over | :host
212
- * `dragging-rows` : Set when grid rows are dragged | :host
213
- * `reorder-status` | Reflects the status of a cell while columns are being reordered | cell
214
- * `frozen` | Frozen cell | cell
215
- * `last-frozen` | Last frozen cell | cell
216
- * * `first-column` | First visible cell on a row | cell
217
- * `last-column` | Last visible cell on a row | cell
218
- * `selected` | Selected row | row
219
- * `expanded` | Expanded row | row
220
- * `details-opened` | Row with details open | row
221
- * `loading` | Row that is waiting for data from data provider | row
222
- * `odd` | Odd row | row
223
- * `first` | The first body row | row
224
- * `dragstart` | Set for one frame when drag of a row is starting. The value is a number when multiple rows are dragged | row
225
- * `dragover` | Set when the row is dragged over | row
226
- * `drag-disabled` | Set to a row that isn't available for dragging | row
227
- * `drop-disabled` | Set to a row that can't be dropped on top of | row
228
- *
229
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
230
- *
231
- * @fires {CustomEvent} active-item-changed - Fired when the `activeItem` property changes.
232
- * @fires {CustomEvent} cell-activate - Fired when the cell is activated with click or keyboard.
233
- * @fires {CustomEvent} cell-focus - Fired when a cell is focused with click or keyboard navigation.
234
- * @fires {CustomEvent} column-reorder - Fired when the columns in the grid are reordered.
235
- * @fires {CustomEvent} column-resize - Fired when the grid column resize is finished.
236
- * @fires {CustomEvent} expanded-items-changed - Fired when the `expandedItems` property changes.
237
- * @fires {CustomEvent} grid-dragstart - Fired when starting to drag grid rows.
238
- * @fires {CustomEvent} grid-dragend - Fired when the dragging of the rows ends.
239
- * @fires {CustomEvent} grid-drop - Fired when a drop occurs on top of the grid.
240
- * @fires {CustomEvent} loading-changed - Fired when the `loading` property changes.
241
- * @fires {CustomEvent} selected-items-changed - Fired when the `selectedItems` property changes.
242
- *
243
- * @extends HTMLElement
244
- * @mixes ElementMixin
245
- * @mixes ThemableMixin
246
- * @mixes A11yMixin
247
- * @mixes ActiveItemMixin
248
- * @mixes ArrayDataProviderMixin
249
- * @mixes ColumnResizingMixin
250
- * @mixes DataProviderMixin
251
- * @mixes DynamicColumnsMixin
252
- * @mixes FilterMixin
253
- * @mixes RowDetailsMixin
254
- * @mixes ScrollMixin
255
- * @mixes SelectionMixin
256
- * @mixes SortMixin
257
- * @mixes KeyboardNavigationMixin
258
- * @mixes ColumnReorderingMixin
259
- * @mixes EventContextMixin
260
- * @mixes StylingMixin
261
- * @mixes DragAndDropMixin
9
+ * @deprecated Import `Grid` from `@vaadin/grid` instead.
262
10
  */
263
- class GridElement extends ElementMixin(
264
- ThemableMixin(
265
- DataProviderMixin(
266
- ArrayDataProviderMixin(
267
- DynamicColumnsMixin(
268
- ActiveItemMixin(
269
- ScrollMixin(
270
- SelectionMixin(
271
- SortMixin(
272
- RowDetailsMixin(
273
- KeyboardNavigationMixin(
274
- A11yMixin(
275
- FilterMixin(
276
- ColumnReorderingMixin(
277
- ColumnResizingMixin(EventContextMixin(DragAndDropMixin(StylingMixin(PolymerElement))))
278
- )
279
- )
280
- )
281
- )
282
- )
283
- )
284
- )
285
- )
286
- )
287
- )
288
- )
289
- )
290
- )
291
- ) {
292
- static get template() {
293
- return html`
294
- <div
295
- id="scroller"
296
- safari$="[[_safari]]"
297
- ios$="[[_ios]]"
298
- loading$="[[loading]]"
299
- column-reordering-allowed$="[[columnReorderingAllowed]]"
300
- >
301
- <table id="table" role="grid" aria-multiselectable="true" tabindex="0">
302
- <caption id="sizer" part="row"></caption>
303
- <thead id="header" role="rowgroup"></thead>
304
- <tbody id="items" role="rowgroup"></tbody>
305
- <tfoot id="footer" role="rowgroup"></tfoot>
306
- </table>
307
-
308
- <div part="reorder-ghost"></div>
309
- </div>
310
-
311
- <div id="focusexit" tabindex="0"></div>
312
- `;
313
- }
314
-
315
- static get is() {
316
- return 'vaadin-grid';
317
- }
318
-
319
- static get observers() {
320
- return [
321
- '_columnTreeChanged(_columnTree, _columnTree.*)',
322
- '_effectiveSizeChanged(_effectiveSize, __virtualizer, _hasData, _columnTree)'
323
- ];
324
- }
325
-
326
- static get properties() {
327
- return {
328
- /** @private */
329
- _safari: {
330
- type: Boolean,
331
- value: /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
332
- },
333
-
334
- /** @private */
335
- _ios: {
336
- type: Boolean,
337
- value:
338
- (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) ||
339
- (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
340
- },
341
-
342
- /** @private */
343
- _firefox: {
344
- type: Boolean,
345
- value: navigator.userAgent.toLowerCase().indexOf('firefox') > -1
346
- },
347
-
348
- /** @private */
349
- _android: {
350
- type: Boolean,
351
- value: /android/i.test(navigator.userAgent)
352
- },
353
-
354
- /** @private */
355
- _touchDevice: {
356
- type: Boolean,
357
- value: TOUCH_DEVICE
358
- },
359
-
360
- /**
361
- * If true, the grid's height is defined by its rows.
362
- *
363
- * Effectively, this disables the grid's virtual scrolling so that all the rows are rendered in the DOM at once.
364
- * If the grid has a large number of items, using the feature is discouraged to avoid performance issues.
365
- * @attr {boolean} all-rows-visible
366
- * @type {boolean}
367
- */
368
- allRowsVisible: {
369
- type: Boolean,
370
- value: false,
371
- reflectToAttribute: true,
372
- observer: '_allRowsVisibleChanged'
373
- },
374
-
375
- /** @private */
376
- _recalculateColumnWidthOnceLoadingFinished: {
377
- type: Boolean,
378
- value: true
379
- },
380
-
381
- /** @private */
382
- isAttached: {
383
- value: false
384
- },
385
-
386
- /**
387
- * An internal property that is mainly used by `vaadin-template-renderer`
388
- * to identify grid elements.
389
- *
390
- * @private
391
- */
392
- __gridElement: {
393
- type: Boolean,
394
- value: true
395
- }
396
- };
397
- }
398
-
399
- constructor() {
400
- super();
401
- this.addEventListener('animationend', this._onAnimationEnd);
402
- }
403
-
404
- /** @protected */
405
- connectedCallback() {
406
- super.connectedCallback();
407
- this.isAttached = true;
408
- this.recalculateColumnWidths();
409
- }
410
-
411
- /** @protected */
412
- disconnectedCallback() {
413
- super.disconnectedCallback();
414
- this.isAttached = false;
415
- }
416
-
417
- /** @private */
418
- __getFirstVisibleItem() {
419
- return this._getVisibleRows().find((row) => this._isInViewport(row));
420
- }
421
-
422
- /** @private */
423
- get _firstVisibleIndex() {
424
- const firstVisibleItem = this.__getFirstVisibleItem();
425
- return firstVisibleItem ? firstVisibleItem.index : undefined;
426
- }
427
-
428
- /** @private */
429
- __getLastVisibleItem() {
430
- return this._getVisibleRows()
431
- .reverse()
432
- .find((row) => this._isInViewport(row));
433
- }
434
-
435
- /** @private */
436
- get _lastVisibleIndex() {
437
- const lastVisibleItem = this.__getLastVisibleItem();
438
- return lastVisibleItem ? lastVisibleItem.index : undefined;
439
- }
440
-
441
- /** @private */
442
- _isInViewport(item) {
443
- const scrollTargetRect = this.$.table.getBoundingClientRect();
444
- const itemRect = item.getBoundingClientRect();
445
- const headerHeight = this.$.header.getBoundingClientRect().height;
446
- const footerHeight = this.$.footer.getBoundingClientRect().height;
447
- return (
448
- itemRect.bottom > scrollTargetRect.top + headerHeight && itemRect.top < scrollTargetRect.bottom - footerHeight
449
- );
450
- }
451
-
452
- /** @private */
453
- _getVisibleRows() {
454
- return Array.from(this.$.items.children)
455
- .filter((item) => !item.hidden)
456
- .sort((a, b) => a.index - b.index);
457
- }
458
-
459
- /** @protected */
460
- ready() {
461
- super.ready();
462
-
463
- this.__virtualizer = new Virtualizer({
464
- createElements: this._createScrollerRows.bind(this),
465
- updateElement: this._updateScrollerItem.bind(this),
466
- scrollContainer: this.$.items,
467
- scrollTarget: this.$.table,
468
- reorderElements: true
469
- });
470
-
471
- new ResizeObserver(() => setTimeout(() => this.__updateFooterPositioning())).observe(this.$.footer);
472
-
473
- processTemplates(this);
474
- }
475
-
476
- /**
477
- * @param {string} name
478
- * @param {?string} oldValue
479
- * @param {?string} newValue
480
- * @protected
481
- */
482
- attributeChangedCallback(name, oldValue, newValue) {
483
- super.attributeChangedCallback(name, oldValue, newValue);
484
- if (name === 'dir') {
485
- this.__isRTL = newValue === 'rtl';
486
- }
487
- }
488
-
489
- /** @private */
490
- __getBodyCellCoordinates(cell) {
491
- if (this.$.items.contains(cell) && cell.localName === 'td') {
492
- return {
493
- item: cell.parentElement._item,
494
- column: cell._column
495
- };
496
- }
497
- }
498
-
499
- /** @private */
500
- __focusBodyCell({ item, column }) {
501
- const row = this._getVisibleRows().find((row) => row._item === item);
502
- const cell = row && [...row.children].find((cell) => cell._column === column);
503
- cell && cell.focus();
504
- }
505
-
506
- /** @private */
507
- _effectiveSizeChanged(effectiveSize, virtualizer, hasData, columnTree) {
508
- if (virtualizer && hasData && columnTree) {
509
- // Changing the virtualizer size may result in the row with focus getting hidden
510
- const cell = this.shadowRoot.activeElement;
511
- const cellCoordinates = this.__getBodyCellCoordinates(cell);
512
-
513
- virtualizer.size = effectiveSize;
514
- virtualizer.flush();
515
-
516
- // If the focused cell's parent row got hidden by the size change, focus the corresponding new cell
517
- cellCoordinates && cell.parentElement.hidden && this.__focusBodyCell(cellCoordinates);
518
- }
519
- }
520
-
521
- /** @private */
522
- __hasRowsWithClientHeight() {
523
- return !!Array.from(this.$.items.children).filter((row) => row.clientHeight).length;
524
- }
525
-
526
- /** @protected */
527
- __itemsReceived() {
528
- if (
529
- this._recalculateColumnWidthOnceLoadingFinished &&
530
- !this._cache.isLoading() &&
531
- this.__hasRowsWithClientHeight()
532
- ) {
533
- this._recalculateColumnWidthOnceLoadingFinished = false;
534
- this.recalculateColumnWidths();
535
- }
536
- }
537
-
538
- /**
539
- * @param {!Array<!GridColumnElement>} cols the columns to auto size based on their content width
540
- * @private
541
- */
542
- _recalculateColumnWidths(cols) {
543
- // Note: The `cols.forEach()` loops below could be implemented as a single loop but this has been
544
- // split for performance reasons to batch these similar actions [write/read] together to avoid
545
- // unnecessary layout trashing.
546
-
547
- // [write] Set automatic width for all cells (breaks column alignment)
548
- cols.forEach((col) => {
549
- col.width = 'auto';
550
- col._origFlexGrow = col.flexGrow;
551
- col.flexGrow = 0;
552
- });
553
- // [read] Measure max cell width in each column
554
- cols.forEach((col) => {
555
- col._currentWidth = 0;
556
- // Note: _allCells only contains cells which are currently rendered in DOM
557
- col._allCells
558
- .filter((c) => {
559
- // Exclude body cells that are out of the visible viewport
560
- return !this.$.items.contains(c) || this._isInViewport(c.parentElement);
561
- })
562
- .forEach((c) => {
563
- // Add 1px buffer to the offset width to avoid too narrow columns (sub-pixel rendering)
564
- const cellWidth = c.offsetWidth + 1;
565
- col._currentWidth = Math.max(col._currentWidth, cellWidth);
566
- });
567
- });
568
- // [write] Set column widths to fit widest measured content
569
- cols.forEach((col) => {
570
- col.width = `${col._currentWidth}px`;
571
- col.flexGrow = col._origFlexGrow;
572
- col._currentWidth = undefined;
573
- col._origFlexGrow = undefined;
574
- });
575
- }
576
-
577
- /**
578
- * Updates the `width` of all columns which have `autoWidth` set to `true`.
579
- */
580
- recalculateColumnWidths() {
581
- if (!this._columnTree) {
582
- return; // No columns
583
- }
584
- if (this._cache.isLoading()) {
585
- this._recalculateColumnWidthOnceLoadingFinished = true;
586
- } else {
587
- const cols = this._getColumns().filter((col) => !col.hidden && col.autoWidth);
588
- this._recalculateColumnWidths(cols);
589
- }
590
- }
591
-
592
- /** @private */
593
- _createScrollerRows(count) {
594
- const rows = [];
595
- for (let i = 0; i < count; i++) {
596
- const row = document.createElement('tr');
597
- row.setAttribute('part', 'row');
598
- row.setAttribute('role', 'row');
599
- row.setAttribute('tabindex', '-1');
600
- if (this._columnTree) {
601
- this._updateRow(row, this._columnTree[this._columnTree.length - 1], 'body', false, true);
602
- }
603
- rows.push(row);
604
- }
605
-
606
- if (this._columnTree) {
607
- this._columnTree[this._columnTree.length - 1].forEach(
608
- (c) => c.isConnected && c.notifyPath && c.notifyPath('_cells.*', c._cells)
609
- );
610
- }
611
-
612
- beforeNextRender(this, () => {
613
- this._updateFirstAndLastColumn();
614
- this._resetKeyboardNavigation();
615
- this._afterScroll();
616
- this.__itemsReceived();
617
- });
618
- return rows;
619
- }
620
-
621
- /** @private */
622
- _createCell(tagName) {
623
- const contentId = (this._contentIndex = this._contentIndex + 1 || 0);
624
- const slotName = 'vaadin-grid-cell-content-' + contentId;
625
-
626
- const cellContent = document.createElement('vaadin-grid-cell-content');
627
- cellContent.setAttribute('slot', slotName);
628
-
629
- const cell = document.createElement(tagName);
630
- cell.id = slotName.replace('-content-', '-');
631
- cell.setAttribute('tabindex', '-1');
632
- cell.setAttribute('role', tagName === 'td' ? 'gridcell' : 'columnheader');
633
-
634
- const slot = document.createElement('slot');
635
- slot.setAttribute('name', slotName);
636
-
637
- cell.appendChild(slot);
638
-
639
- cell._content = cellContent;
640
-
641
- // With native Shadow DOM, mousedown on slotted element does not focus
642
- // focusable slot wrapper, that is why cells are not focused with
643
- // mousedown. Workaround: listen for mousedown and focus manually.
644
- cellContent.addEventListener('mousedown', () => {
645
- if (window.chrome) {
646
- // Chrome bug: focusing before mouseup prevents text selection, see http://crbug.com/771903
647
- const mouseUpListener = () => {
648
- if (!cellContent.contains(this.getRootNode().activeElement)) {
649
- cell.focus();
650
- }
651
- // If focus is in the cell content — respect it, do not change.
652
- document.removeEventListener('mouseup', mouseUpListener, true);
653
- };
654
- document.addEventListener('mouseup', mouseUpListener, true);
655
- } else {
656
- // Focus on mouseup, on the other hand, removes selection on Safari.
657
- // Watch out sync focus removal issue, only async focus works here.
658
- setTimeout(() => {
659
- if (!cellContent.contains(this.getRootNode().activeElement)) {
660
- cell.focus();
661
- }
662
- });
663
- }
664
- });
665
-
666
- return cell;
667
- }
668
-
669
- /**
670
- * @param {!HTMLTableRowElement} row
671
- * @param {!Array<!GridColumnElement>} columns
672
- * @param {?string} section
673
- * @param {boolean} isColumnRow
674
- * @param {boolean} noNotify
675
- * @protected
676
- */
677
- _updateRow(row, columns, section, isColumnRow, noNotify) {
678
- section = section || 'body';
679
-
680
- const contentsFragment = document.createDocumentFragment();
681
-
682
- Array.from(row.children).forEach((cell) => (cell._vacant = true));
683
- row.innerHTML = '';
684
-
685
- columns
686
- .filter((column) => !column.hidden)
687
- .forEach((column, index, cols) => {
688
- let cell;
689
-
690
- if (section === 'body') {
691
- // Body
692
- column._cells = column._cells || [];
693
- cell = column._cells.filter((cell) => cell._vacant)[0];
694
- if (!cell) {
695
- cell = this._createCell('td');
696
- column._cells.push(cell);
697
- }
698
- cell.setAttribute('part', 'cell body-cell');
699
- row.appendChild(cell);
700
-
701
- if (index === cols.length - 1 && this.rowDetailsRenderer) {
702
- // Add details cell as last cell to body rows
703
- this._detailsCells = this._detailsCells || [];
704
- const detailsCell = this._detailsCells.filter((cell) => cell._vacant)[0] || this._createCell('td');
705
- if (this._detailsCells.indexOf(detailsCell) === -1) {
706
- this._detailsCells.push(detailsCell);
707
- }
708
- if (!detailsCell._content.parentElement) {
709
- contentsFragment.appendChild(detailsCell._content);
710
- }
711
- this._configureDetailsCell(detailsCell);
712
- row.appendChild(detailsCell);
713
- this._a11ySetRowDetailsCell(row, detailsCell);
714
- detailsCell._vacant = false;
715
- }
716
-
717
- if (column.notifyPath && !noNotify) {
718
- column.notifyPath('_cells.*', column._cells);
719
- }
720
- } else {
721
- // Header & footer
722
- const tagName = section === 'header' ? 'th' : 'td';
723
- if (isColumnRow || column.localName === 'vaadin-grid-column-group') {
724
- cell = column[`_${section}Cell`] || this._createCell(tagName);
725
- cell._column = column;
726
- row.appendChild(cell);
727
- column[`_${section}Cell`] = cell;
728
- } else {
729
- column._emptyCells = column._emptyCells || [];
730
- cell = column._emptyCells.filter((cell) => cell._vacant)[0] || this._createCell(tagName);
731
- cell._column = column;
732
- row.appendChild(cell);
733
- if (column._emptyCells.indexOf(cell) === -1) {
734
- column._emptyCells.push(cell);
735
- }
736
- }
737
- cell.setAttribute('part', `cell ${section}-cell`);
738
- this.__updateHeaderFooterRowVisibility(row);
739
- }
740
-
741
- if (!cell._content.parentElement) {
742
- contentsFragment.appendChild(cell._content);
743
- }
744
- cell._vacant = false;
745
- cell._column = column;
746
- });
747
-
748
- // Might be empty if only cache was used
749
- this.appendChild(contentsFragment);
750
-
751
- this._frozenCellsChanged();
752
- this._updateFirstAndLastColumnForRow(row);
753
- }
754
-
755
- /**
756
- * @param {HTMLTableRowElement} row
757
- * @protected
758
- */
759
- __updateHeaderFooterRowVisibility(row) {
760
- if (!row) {
761
- return;
762
- }
763
-
764
- const visibleRowCells = Array.from(row.children).filter((cell) => {
765
- const column = cell._column;
766
- if (column._emptyCells && column._emptyCells.indexOf(cell) > -1) {
767
- // The cell is an "empty cell" -> doesn't block hiding the row
768
- return false;
769
- }
770
- if (row.parentElement === this.$.header) {
771
- if (column.headerRenderer) {
772
- // The cell is the header cell of a column that has a header renderer
773
- // -> row should be visible
774
- return true;
775
- }
776
- if (column.header === null) {
777
- // The column header is explicilty set to null -> doesn't block hiding the row
778
- return false;
779
- }
780
- if (column.path || column.header !== undefined) {
781
- // The column has an explicit non-null header or a path that generates a header
782
- // -> row should be visible
783
- return true;
784
- }
785
- } else {
786
- if (column.footerRenderer) {
787
- // The cell is the footer cell of a column that has a footer renderer
788
- // -> row should be visible
789
- return true;
790
- }
791
- }
792
- });
793
-
794
- if (row.hidden !== !visibleRowCells.length) {
795
- row.hidden = !visibleRowCells.length;
796
- this.notifyResize();
797
- }
798
- }
799
-
800
- /** @private */
801
- _updateScrollerItem(row, index) {
802
- this._preventScrollerRotatingCellFocus(row, index);
803
-
804
- if (!this._columnTree) {
805
- return;
806
- }
807
-
808
- this._toggleAttribute('first', index === 0, row);
809
- this._toggleAttribute('odd', index % 2, row);
810
- this._a11yUpdateRowRowindex(row, index);
811
- this._getItem(index, row);
812
- }
813
-
814
- /** @private */
815
- _columnTreeChanged(columnTree) {
816
- this._renderColumnTree(columnTree);
817
- this.recalculateColumnWidths();
818
- }
819
-
820
- /**
821
- * @param {!Array<!GridColumnElement>} columnTree
822
- * @protected
823
- */
824
- _renderColumnTree(columnTree) {
825
- Array.from(this.$.items.children).forEach((row) =>
826
- this._updateRow(row, columnTree[columnTree.length - 1], null, false, true)
827
- );
828
-
829
- while (this.$.header.children.length < columnTree.length) {
830
- const headerRow = document.createElement('tr');
831
- headerRow.setAttribute('part', 'row');
832
- headerRow.setAttribute('role', 'row');
833
- headerRow.setAttribute('tabindex', '-1');
834
- this.$.header.appendChild(headerRow);
835
-
836
- const footerRow = document.createElement('tr');
837
- footerRow.setAttribute('part', 'row');
838
- footerRow.setAttribute('role', 'row');
839
- footerRow.setAttribute('tabindex', '-1');
840
- this.$.footer.appendChild(footerRow);
841
- }
842
- while (this.$.header.children.length > columnTree.length) {
843
- this.$.header.removeChild(this.$.header.firstElementChild);
844
- this.$.footer.removeChild(this.$.footer.firstElementChild);
845
- }
846
-
847
- Array.from(this.$.header.children).forEach((headerRow, index) =>
848
- this._updateRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1)
849
- );
850
-
851
- Array.from(this.$.footer.children).forEach((footerRow, index) =>
852
- this._updateRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0)
853
- );
854
-
855
- // Sizer rows
856
- this._updateRow(this.$.sizer, columnTree[columnTree.length - 1]);
857
-
858
- this._resizeHandler();
859
- this._frozenCellsChanged();
860
- this._updateFirstAndLastColumn();
861
- this._resetKeyboardNavigation();
862
- this._a11yUpdateHeaderRows();
863
- this._a11yUpdateFooterRows();
864
- this.__updateFooterPositioning();
865
- }
866
-
867
- __updateFooterPositioning() {
868
- if (this._firefox) {
869
- // Sticky (or translated) footer in a flexbox host doesn't get included in
870
- // the scroll height calculation on FF. This is a workaround for the issue.
871
- this.$.items.style.paddingBottom = 0;
872
- if (!this.allRowsVisible) {
873
- this.$.items.style.paddingBottom = `${this.$.footer.offsetHeight}px`;
874
- }
875
- }
876
- }
877
-
878
- /**
879
- * @param {!HTMLElement} row
880
- * @param {GridItem} item
881
- * @protected
882
- */
883
- _updateItem(row, item) {
884
- row._item = item;
885
- const model = this.__getRowModel(row);
886
-
887
- this._toggleDetailsCell(row, model.detailsOpened);
888
-
889
- this._a11yUpdateRowLevel(row, model.level);
890
- this._a11yUpdateRowSelected(row, model.selected);
891
- this._a11yUpdateRowExpanded(row, model.expanded);
892
- this._a11yUpdateRowDetailsOpened(row, model.detailsOpened);
893
-
894
- this._toggleAttribute('expanded', model.expanded, row);
895
- this._toggleAttribute('selected', model.selected, row);
896
- this._toggleAttribute('details-opened', model.detailsOpened, row);
897
-
898
- this._generateCellClassNames(row, model);
899
- this._filterDragAndDrop(row, model);
900
-
901
- Array.from(row.children).forEach((cell) => {
902
- if (cell._renderer) {
903
- const owner = cell._column || this;
904
- cell._renderer.call(owner, cell._content, owner, model);
905
- }
906
- });
907
-
908
- this._updateDetailsCellHeight(row);
909
- }
910
-
911
- /** @private */
912
- _resizeHandler() {
913
- this._updateDetailsCellHeights();
914
- this.__updateFooterPositioning();
915
- }
916
-
917
- /** @private */
918
- _onAnimationEnd(e) {
919
- // ShadyCSS applies scoping suffixes to animation names
920
- if (e.animationName.indexOf('vaadin-grid-appear') === 0) {
921
- e.stopPropagation();
922
- this.notifyResize();
923
- this.__itemsReceived();
924
-
925
- requestAnimationFrame(() => {
926
- this.__scrollToPendingIndex();
927
- // This needs to be set programmatically in order to avoid an iOS 10 bug (disappearing grid)
928
- this.$.table.style.webkitOverflowScrolling = 'touch';
929
- });
930
- }
931
- }
932
-
933
- /**
934
- * @param {string} name
935
- * @param {boolean} bool
936
- * @param {!Element} node
937
- * @protected
938
- */
939
- _toggleAttribute(name, bool, node) {
940
- if (node.hasAttribute(name) === !bool) {
941
- if (bool) {
942
- node.setAttribute(name, '');
943
- } else {
944
- node.removeAttribute(name);
945
- }
946
- }
947
- }
948
-
949
- /**
950
- * @param {!HTMLTableRowElement} row
951
- * @return {!GridItemModel}
952
- * @protected
953
- */
954
- __getRowModel(row) {
955
- return {
956
- index: row.index,
957
- item: row._item,
958
- level: this._getIndexLevel(row.index),
959
- expanded: this._isExpanded(row._item),
960
- selected: this._isSelected(row._item),
961
- detailsOpened: !!this.rowDetailsRenderer && this._isDetailsOpened(row._item)
962
- };
963
- }
964
-
965
- /**
966
- * Requests an update for the content of cells.
967
- *
968
- * While performing the update, the following renderers are invoked:
969
- * - `GridElement.rowDetailsRenderer`
970
- * - `GridColumnElement.renderer`
971
- * - `GridColumnElement.headerRenderer`
972
- * - `GridColumnElement.footerRenderer`
973
- *
974
- * It is not guaranteed that the update happens immediately (synchronously) after it is requested.
975
- */
976
- requestContentUpdate() {
977
- if (this._columnTree) {
978
- // header and footer renderers
979
- this._columnTree.forEach((level) => {
980
- level.forEach((column) => {
981
- column._renderHeaderAndFooter();
982
- });
983
- });
984
-
985
- // body and row details renderers
986
- this.__updateVisibleRows();
987
- }
988
- }
989
-
990
- /**
991
- * Manually invoke existing renderers for all the columns
992
- * (header, footer and body cells) and opened row details.
993
- *
994
- * @deprecated Since Vaadin 21, `render()` is deprecated. Please use `requestContentUpdate()` instead.
995
- */
996
- render() {
997
- console.warn('WARNING: Since Vaadin 21, render() is deprecated. Please use requestContentUpdate() instead.');
998
-
999
- this.requestContentUpdate();
1000
- }
1001
-
1002
- /** @protected */
1003
- __updateVisibleRows(start, end) {
1004
- this.__virtualizer && this.__virtualizer.update(start, end);
1005
- }
1006
-
1007
- /**
1008
- * Updates the computed metrics and positioning of internal grid parts
1009
- * (row/details cell positioning etc). Needs to be invoked whenever the sizing of grid
1010
- * content changes asynchronously to ensure consistent appearance (e.g. when a
1011
- * contained image whose bounds aren't known beforehand finishes loading).
1012
- */
1013
- notifyResize() {
1014
- // To be removed in https://github.com/vaadin/web-components/issues/331
1015
- }
1016
-
1017
- /** @private */
1018
- _allRowsVisibleChanged(value, oldValue) {
1019
- if (value || oldValue) {
1020
- this.notifyResize();
1021
- }
1022
- }
1023
-
1024
- /** @protected */
1025
- __forceReflow() {
1026
- this._debouncerForceReflow = Debouncer.debounce(this._debouncerForceReflow, animationFrame, () => {
1027
- this.$.scroller.style.overflow = 'hidden';
1028
- setTimeout(() => (this.$.scroller.style.overflow = ''));
1029
- });
1030
- }
1031
- }
1032
-
1033
- customElements.define(GridElement.is, GridElement);
11
+ export const GridElement = Grid;
1034
12
 
1035
- export { GridElement };
13
+ export * from '@vaadin/grid/src/vaadin-grid.js';