@vaadin/grid 24.6.0-alpha2 → 24.6.0-alpha4

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.6.0-alpha2",
3
+ "version": "24.6.0-alpha4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -46,18 +46,18 @@
46
46
  "dependencies": {
47
47
  "@open-wc/dedupe-mixin": "^1.3.0",
48
48
  "@polymer/polymer": "^3.0.0",
49
- "@vaadin/a11y-base": "24.6.0-alpha2",
50
- "@vaadin/checkbox": "24.6.0-alpha2",
51
- "@vaadin/component-base": "24.6.0-alpha2",
52
- "@vaadin/lit-renderer": "24.6.0-alpha2",
53
- "@vaadin/text-field": "24.6.0-alpha2",
54
- "@vaadin/vaadin-lumo-styles": "24.6.0-alpha2",
55
- "@vaadin/vaadin-material-styles": "24.6.0-alpha2",
56
- "@vaadin/vaadin-themable-mixin": "24.6.0-alpha2",
49
+ "@vaadin/a11y-base": "24.6.0-alpha4",
50
+ "@vaadin/checkbox": "24.6.0-alpha4",
51
+ "@vaadin/component-base": "24.6.0-alpha4",
52
+ "@vaadin/lit-renderer": "24.6.0-alpha4",
53
+ "@vaadin/text-field": "24.6.0-alpha4",
54
+ "@vaadin/vaadin-lumo-styles": "24.6.0-alpha4",
55
+ "@vaadin/vaadin-material-styles": "24.6.0-alpha4",
56
+ "@vaadin/vaadin-themable-mixin": "24.6.0-alpha4",
57
57
  "lit": "^3.0.0"
58
58
  },
59
59
  "devDependencies": {
60
- "@vaadin/chai-plugins": "24.6.0-alpha2",
60
+ "@vaadin/chai-plugins": "24.6.0-alpha4",
61
61
  "@vaadin/testing-helpers": "^1.0.0",
62
62
  "sinon": "^18.0.0"
63
63
  },
@@ -65,5 +65,5 @@
65
65
  "web-types.json",
66
66
  "web-types.lit.json"
67
67
  ],
68
- "gitHead": "21fa9ea077a04949a90d00934bfefe3e346bd129"
68
+ "gitHead": "78967d4f3bb46f58f43c2cc621802554acb2efaf"
69
69
  }
@@ -4,9 +4,23 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
7
+ import { animationFrame } from '@vaadin/component-base/src/async.js';
8
+ import { Debouncer } from '@vaadin/component-base/src/debounce.js';
7
9
  import { addValueToAttribute, removeValueFromAttribute } from '@vaadin/component-base/src/dom-utils.js';
8
10
  import { get } from '@vaadin/component-base/src/path-utils.js';
9
11
 
12
+ function isRow(element) {
13
+ return element instanceof HTMLTableRowElement;
14
+ }
15
+
16
+ function isCell(element) {
17
+ return element instanceof HTMLTableCellElement;
18
+ }
19
+
20
+ function isDetailsCell(element) {
21
+ return element.matches('[part~="details-cell"]');
22
+ }
23
+
10
24
  /**
11
25
  * @polymerMixin
12
26
  */
@@ -84,9 +98,7 @@ export const KeyboardNavigationMixin = (superClass) =>
84
98
 
85
99
  /** @private */
86
100
  get __rowFocusMode() {
87
- return (
88
- this.__isRow(this._itemsFocusable) || this.__isRow(this._headerFocusable) || this.__isRow(this._footerFocusable)
89
- );
101
+ return [this._headerFocusable, this._itemsFocusable, this._footerFocusable].some(isRow);
90
102
  }
91
103
 
92
104
  set __rowFocusMode(value) {
@@ -94,15 +106,15 @@ export const KeyboardNavigationMixin = (superClass) =>
94
106
  const focusable = this[prop];
95
107
  if (value) {
96
108
  const parent = focusable && focusable.parentElement;
97
- if (this.__isCell(focusable)) {
109
+ if (isCell(focusable)) {
98
110
  // Cell itself focusable (default)
99
111
  this[prop] = parent;
100
- } else if (this.__isCell(parent)) {
112
+ } else if (isCell(parent)) {
101
113
  // Focus button mode is enabled for the column,
102
114
  // button element inside the cell is focusable.
103
115
  this[prop] = parent.parentElement;
104
116
  }
105
- } else if (!value && this.__isRow(focusable)) {
117
+ } else if (!value && isRow(focusable)) {
106
118
  const cell = focusable.firstElementChild;
107
119
  this[prop] = cell._focusButton || cell;
108
120
  }
@@ -200,7 +212,7 @@ export const KeyboardNavigationMixin = (superClass) =>
200
212
  if (parent) {
201
213
  // Focus button mode is enabled for the column,
202
214
  // button element inside the cell is focusable.
203
- if (this.__isCell(parent)) {
215
+ if (isCell(parent)) {
204
216
  cell = parent;
205
217
  parent = parent.parentElement;
206
218
  }
@@ -263,10 +275,10 @@ export const KeyboardNavigationMixin = (superClass) =>
263
275
  }
264
276
 
265
277
  /** @private */
266
- _ensureScrolledToIndex(index) {
278
+ __ensureFlatIndexInViewport(index) {
267
279
  const targetRowInDom = [...this.$.items.children].find((child) => child.index === index);
268
280
  if (!targetRowInDom) {
269
- this.scrollToIndex(index);
281
+ this._scrollToFlatIndex(index);
270
282
  } else {
271
283
  this.__scrollIntoViewport(index);
272
284
  }
@@ -285,33 +297,13 @@ export const KeyboardNavigationMixin = (superClass) =>
285
297
  return this._isExpanded(row._item);
286
298
  }
287
299
 
288
- /** @private */
289
- __isDetailsCell(element) {
290
- return element.matches('[part~="details-cell"]');
291
- }
292
-
293
- /** @private */
294
- __isCell(element) {
295
- return element instanceof HTMLTableCellElement;
296
- }
297
-
298
- /** @private */
299
- __isRow(element) {
300
- return element instanceof HTMLTableRowElement;
301
- }
302
-
303
- /** @private */
304
- __getIndexOfChildElement(el) {
305
- return Array.prototype.indexOf.call(el.parentNode.children, el);
306
- }
307
-
308
300
  /** @private */
309
301
  _onNavigationKeyDown(e, key) {
310
302
  e.preventDefault();
311
303
 
312
304
  const isRTL = this.__isRTL;
313
- const activeRow = e.composedPath().find((el) => this.__isRow(el));
314
- const activeCell = e.composedPath().find((el) => this.__isCell(el));
305
+ const activeRow = e.composedPath().find(isRow);
306
+ const activeCell = e.composedPath().find(isCell);
315
307
 
316
308
  // Handle keyboard interaction as defined in:
317
309
  // https://w3c.github.io/aria-practices/#keyboard-interaction-24
@@ -406,7 +398,7 @@ export const KeyboardNavigationMixin = (superClass) =>
406
398
  } else {
407
399
  // In cell focus mode
408
400
  const activeRowCells = [...activeRow.children].sort((a, b) => a._order - b._order);
409
- if (activeCell === activeRowCells[0] || this.__isDetailsCell(activeCell)) {
401
+ if (activeCell === activeRowCells[0] || isDetailsCell(activeCell)) {
410
402
  // "If focus is on the first cell in a row and row focus is supported, moves focus to the row."
411
403
  this.__rowFocusMode = true;
412
404
  this._onRowNavigation(activeRow, 0);
@@ -445,7 +437,7 @@ export const KeyboardNavigationMixin = (superClass) =>
445
437
  if (rowGroup === this.$.items) {
446
438
  return bodyFallbackIndex !== undefined ? bodyFallbackIndex : row.index;
447
439
  }
448
- return this.__getIndexOfChildElement(row);
440
+ return [...rowGroup.children].indexOf(row);
449
441
  }
450
442
 
451
443
  /**
@@ -486,7 +478,7 @@ export const KeyboardNavigationMixin = (superClass) =>
486
478
 
487
479
  let dstIsRowDetails = false;
488
480
  if (activeCell) {
489
- const isRowDetails = this.__isDetailsCell(activeCell);
481
+ const isRowDetails = isDetailsCell(activeCell);
490
482
  // Row details navigation logic
491
483
  if (activeRowGroup === this.$.items) {
492
484
  const item = activeRow._item;
@@ -507,15 +499,15 @@ export const KeyboardNavigationMixin = (superClass) =>
507
499
  }
508
500
 
509
501
  // Ensure correct vertical scroll position, destination row is visible
510
- this._ensureScrolledToIndex(dstRowIndex);
502
+ this.__ensureFlatIndexInViewport(dstRowIndex);
511
503
 
512
504
  // When scrolling with repeated keydown, sometimes FocusEvent listeners
513
505
  // are too late to update _focusedItemIndex. Ensure next keydown
514
506
  // listener invocation gets updated _focusedItemIndex value.
515
507
  this._focusedItemIndex = dstRowIndex;
516
508
 
517
- // This has to be set after scrolling, otherwise it can be removed by
518
- // `_preventScrollerRotatingCellFocus(row, index)` during scrolling.
509
+ // Reapply navigating state in case it was removed due to previous item
510
+ // being focused with the mouse.
519
511
  this.toggleAttribute('navigating', true);
520
512
 
521
513
  return {
@@ -536,13 +528,13 @@ export const KeyboardNavigationMixin = (superClass) =>
536
528
  return;
537
529
  }
538
530
 
539
- let columnIndex = this.__getIndexOfChildElement(activeCell);
531
+ let columnIndex = [...activeRow.children].indexOf(activeCell);
540
532
  if (this.$.items.contains(activeCell)) {
541
533
  // lazy column rendering may be enabled, so we need use the always visible sizer cells to find the column index
542
534
  columnIndex = [...this.$.sizer.children].findIndex((sizerCell) => sizerCell._column === activeCell._column);
543
535
  }
544
536
 
545
- const isCurrentCellRowDetails = this.__isDetailsCell(activeCell);
537
+ const isCurrentCellRowDetails = isDetailsCell(activeCell);
546
538
  const activeRowGroup = activeRow.parentNode;
547
539
  const currentRowIndex = this.__getIndexInGroup(activeRow, this._focusedItemIndex);
548
540
 
@@ -560,7 +552,7 @@ export const KeyboardNavigationMixin = (superClass) =>
560
552
 
561
553
  if (dstIsRowDetails) {
562
554
  // Focusing a row details cell on the destination row
563
- const dstCell = [...dstRow.children].find((el) => this.__isDetailsCell(el));
555
+ const dstCell = [...dstRow.children].find(isDetailsCell);
564
556
  dstCell.focus();
565
557
  } else {
566
558
  // Focusing a regular cell on the destination row
@@ -720,7 +712,7 @@ export const KeyboardNavigationMixin = (superClass) =>
720
712
 
721
713
  /** @private */
722
714
  _onTabKeyDown(e) {
723
- const focusTarget = this._predictFocusStepTarget(e.composedPath()[0], e.shiftKey ? -1 : 1);
715
+ let focusTarget = this._predictFocusStepTarget(e.composedPath()[0], e.shiftKey ? -1 : 1);
724
716
 
725
717
  // Can be undefined if grid has tabindex
726
718
  if (!focusTarget) {
@@ -730,33 +722,24 @@ export const KeyboardNavigationMixin = (superClass) =>
730
722
  // Prevent focus-trap logic from intercepting the event.
731
723
  e.stopPropagation();
732
724
 
733
- if (focusTarget === this.$.table) {
734
- // The focus is about to exit the grid to the top.
735
- this.$.table.focus();
736
- } else if (focusTarget === this.$.focusexit) {
737
- // The focus is about to exit the grid to the bottom.
738
- this.$.focusexit.focus();
739
- } else if (focusTarget === this._itemsFocusable) {
740
- let itemsFocusTarget = focusTarget;
741
- const targetRow = this.__isRow(focusTarget) ? focusTarget : focusTarget.parentNode;
742
- this._ensureScrolledToIndex(this._focusedItemIndex);
743
- if (targetRow.index !== this._focusedItemIndex && this.__isCell(focusTarget)) {
744
- // The target row, which is about to be focused next, has been
745
- // assigned with a new index since last focus, probably because of
746
- // scrolling. Focus the row for the stored focused item index instead.
747
- const columnIndex = Array.from(targetRow.children).indexOf(this._itemsFocusable);
748
- const focusedItemRow = Array.from(this.$.items.children).find(
749
- (row) => !row.hidden && row.index === this._focusedItemIndex,
750
- );
751
- if (focusedItemRow) {
752
- itemsFocusTarget = focusedItemRow.children[columnIndex];
753
- }
754
- }
755
- e.preventDefault();
756
- itemsFocusTarget.focus();
757
- } else {
725
+ if (focusTarget === this._itemsFocusable) {
726
+ this.__ensureFlatIndexInViewport(this._focusedItemIndex);
727
+
728
+ // Ensure the correct element is set as focusable after scrolling.
729
+ // The virtualizer may use a different element to render the item.
730
+ this.__updateItemsFocusable();
731
+
732
+ focusTarget = this._itemsFocusable;
733
+ }
734
+
735
+ focusTarget.focus();
736
+
737
+ // If the next element is the table or focusexit, it indicates the user
738
+ // intends to leave the grid. In this case, we move focus to these elements
739
+ // without preventing the default Tab behavior. The default behavior then
740
+ // starts from these elements and moves focus outside the grid.
741
+ if (focusTarget !== this.$.table && focusTarget !== this.$.focusexit) {
758
742
  e.preventDefault();
759
- focusTarget.focus();
760
743
  }
761
744
 
762
745
  this.toggleAttribute('navigating', true);
@@ -767,12 +750,12 @@ export const KeyboardNavigationMixin = (superClass) =>
767
750
  e.preventDefault();
768
751
 
769
752
  const element = e.composedPath()[0];
770
- const isRow = this.__isRow(element);
771
- if (isRow || !element._content || !element._content.firstElementChild) {
753
+ const isElementRow = isRow(element);
754
+ if (isElementRow || !element._content || !element._content.firstElementChild) {
772
755
  this.dispatchEvent(
773
- new CustomEvent(isRow ? 'row-activate' : 'cell-activate', {
756
+ new CustomEvent(isElementRow ? 'row-activate' : 'cell-activate', {
774
757
  detail: {
775
- model: this.__getRowModel(isRow ? element : element.parentElement),
758
+ model: this.__getRowModel(isElementRow ? element : element.parentElement),
776
759
  },
777
760
  }),
778
761
  );
@@ -849,11 +832,13 @@ export const KeyboardNavigationMixin = (superClass) =>
849
832
 
850
833
  if (section && (cell || row)) {
851
834
  this._activeRowGroup = section;
852
- if (this.$.header === section) {
835
+
836
+ if (section === this.$.header) {
853
837
  this._headerFocusable = this.__getFocusable(row, cell);
854
- } else if (this.$.items === section) {
838
+ } else if (section === this.$.items) {
855
839
  this._itemsFocusable = this.__getFocusable(row, cell);
856
- } else if (this.$.footer === section) {
840
+ this._focusedItemIndex = row.index;
841
+ } else if (section === this.$.footer) {
857
842
  this._footerFocusable = this.__getFocusable(row, cell);
858
843
  }
859
844
 
@@ -873,8 +858,6 @@ export const KeyboardNavigationMixin = (superClass) =>
873
858
  this._focusedCell = null;
874
859
  }
875
860
  }
876
-
877
- this._detectFocusedItemIndex(e);
878
861
  }
879
862
 
880
863
  /**
@@ -912,14 +895,6 @@ export const KeyboardNavigationMixin = (superClass) =>
912
895
  this.__updateHorizontalScrollPosition();
913
896
  }
914
897
 
915
- /** @private */
916
- _detectFocusedItemIndex(e) {
917
- const { section, row } = this._getGridEventLocation(e);
918
- if (section === this.$.items) {
919
- this._focusedItemIndex = row.index;
920
- }
921
- }
922
-
923
898
  /**
924
899
  * Enables or disables the focus target of the containing section of the
925
900
  * grid from receiving focus, based on whether the user is interacting with
@@ -938,26 +913,45 @@ export const KeyboardNavigationMixin = (superClass) =>
938
913
  focusTarget.tabIndex = isInteractingWithinActiveSection ? -1 : 0;
939
914
  }
940
915
 
941
- /**
942
- * @param {!HTMLTableRowElement} row
943
- * @param {number} index
944
- * @protected
945
- */
946
- _preventScrollerRotatingCellFocus(row, index) {
947
- if (
948
- row.index === this._focusedItemIndex &&
949
- this.hasAttribute('navigating') &&
950
- this._activeRowGroup === this.$.items
951
- ) {
952
- // Focused item has went, hide navigation mode
953
- this._navigatingIsHidden = true;
954
- this.toggleAttribute('navigating', false);
955
- }
956
- if (index === this._focusedItemIndex && this._navigatingIsHidden) {
957
- // Focused item is back, restore navigation mode
958
- this._navigatingIsHidden = false;
959
- this.toggleAttribute('navigating', true);
916
+ /** @protected */
917
+ _preventScrollerRotatingCellFocus() {
918
+ if (this._activeRowGroup !== this.$.items) {
919
+ return;
960
920
  }
921
+
922
+ this.__preventScrollerRotatingCellFocusDebouncer = Debouncer.debounce(
923
+ this.__preventScrollerRotatingCellFocusDebouncer,
924
+ animationFrame,
925
+ () => {
926
+ const isItemsRowGroupActive = this._activeRowGroup === this.$.items;
927
+ const isFocusedItemRendered = this._getRenderedRows().some((row) => row.index === this._focusedItemIndex);
928
+ if (isFocusedItemRendered) {
929
+ // Ensure the correct element is focused, as the virtualizer
930
+ // may use different elements when re-rendering visible items.
931
+ this.__updateItemsFocusable();
932
+
933
+ // The focused item is visible, so restore the cell focus outline
934
+ // and navigation mode.
935
+ if (isItemsRowGroupActive && !this.__rowFocusMode) {
936
+ this._focusedCell = this._itemsFocusable;
937
+ }
938
+
939
+ if (this._navigatingIsHidden) {
940
+ this.toggleAttribute('navigating', true);
941
+ this._navigatingIsHidden = false;
942
+ }
943
+ } else if (isItemsRowGroupActive) {
944
+ // The focused item was scrolled out of view and focus is still inside body,
945
+ // so remove the cell focus outline and hide navigation mode.
946
+ this._focusedCell = null;
947
+
948
+ if (this.hasAttribute('navigating')) {
949
+ this._navigatingIsHidden = true;
950
+ this.toggleAttribute('navigating', false);
951
+ }
952
+ }
953
+ },
954
+ );
961
955
  }
962
956
 
963
957
  /**
@@ -1017,7 +1011,7 @@ export const KeyboardNavigationMixin = (superClass) =>
1017
1011
  * @protected
1018
1012
  */
1019
1013
  _scrollHorizontallyToCell(dstCell) {
1020
- if (dstCell.hasAttribute('frozen') || dstCell.hasAttribute('frozen-to-end') || this.__isDetailsCell(dstCell)) {
1014
+ if (dstCell.hasAttribute('frozen') || dstCell.hasAttribute('frozen-to-end') || isDetailsCell(dstCell)) {
1021
1015
  // These cells are, by design, always visible, no need to scroll.
1022
1016
  return;
1023
1017
  }
@@ -1030,7 +1024,7 @@ export const KeyboardNavigationMixin = (superClass) =>
1030
1024
  rightBoundary = tableRect.right;
1031
1025
  for (let i = dstCellIndex - 1; i >= 0; i--) {
1032
1026
  const cell = dstRow.children[i];
1033
- if (cell.hasAttribute('hidden') || this.__isDetailsCell(cell)) {
1027
+ if (cell.hasAttribute('hidden') || isDetailsCell(cell)) {
1034
1028
  continue;
1035
1029
  }
1036
1030
  if (cell.hasAttribute('frozen') || cell.hasAttribute('frozen-to-end')) {
@@ -1040,7 +1034,7 @@ export const KeyboardNavigationMixin = (superClass) =>
1040
1034
  }
1041
1035
  for (let i = dstCellIndex + 1; i < dstRow.children.length; i++) {
1042
1036
  const cell = dstRow.children[i];
1043
- if (cell.hasAttribute('hidden') || this.__isDetailsCell(cell)) {
1037
+ if (cell.hasAttribute('hidden') || isDetailsCell(cell)) {
1044
1038
  continue;
1045
1039
  }
1046
1040
  if (cell.hasAttribute('frozen') || cell.hasAttribute('frozen-to-end')) {
@@ -6,7 +6,15 @@
6
6
  import { isElementHidden } from '@vaadin/a11y-base/src/focus-utils.js';
7
7
  import { TabindexMixin } from '@vaadin/a11y-base/src/tabindex-mixin.js';
8
8
  import { animationFrame, microTask } from '@vaadin/component-base/src/async.js';
9
- import { isAndroid, isChrome, isFirefox, isIOS, isSafari, isTouch } from '@vaadin/component-base/src/browser-utils.js';
9
+ import {
10
+ isAndroid,
11
+ isChrome,
12
+ isFirefox,
13
+ isIOS,
14
+ isSafari,
15
+ isTouch,
16
+ supportsAdoptingStyleSheets,
17
+ } from '@vaadin/component-base/src/browser-utils.js';
10
18
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
11
19
  import { getClosestElement } from '@vaadin/component-base/src/dom-utils.js';
12
20
  import { SlotObserver } from '@vaadin/component-base/src/slot-observer.js';
@@ -269,6 +277,16 @@ export const GridMixin = (superClass) =>
269
277
  }),
270
278
  ).observe(this.$.table);
271
279
 
280
+ const minHeightObserver = new ResizeObserver(() =>
281
+ setTimeout(() => {
282
+ this.__updateMinHeight();
283
+ }),
284
+ );
285
+
286
+ minHeightObserver.observe(this.$.header);
287
+ minHeightObserver.observe(this.$.items);
288
+ minHeightObserver.observe(this.$.footer);
289
+
272
290
  processTemplates(this);
273
291
 
274
292
  this._tooltipController = new TooltipController(this);
@@ -873,11 +891,12 @@ export const GridMixin = (superClass) =>
873
891
  }
874
892
 
875
893
  /** @private */
876
- _updateRowStateParts(row, { expanded, selected, detailsOpened }) {
894
+ _updateRowStateParts(row, { item, expanded, selected, detailsOpened }) {
877
895
  updateBooleanRowStates(row, {
878
896
  expanded,
879
897
  collapsed: this.__isRowExpandable(row),
880
898
  selected,
899
+ nonselectable: this.__isItemSelectable(item) === false,
881
900
  'details-opened': detailsOpened,
882
901
  });
883
902
  }
@@ -1116,4 +1135,28 @@ export const GridMixin = (superClass) =>
1116
1135
  this.__virtualizer.update(start, end);
1117
1136
  }
1118
1137
  }
1138
+
1139
+ /** @private */
1140
+ __updateMinHeight() {
1141
+ // Min height is calculated based on the header, footer and a single row
1142
+ // For now use a hard-coded value for the row that matches a single default row in Lumo
1143
+ const rowHeight = 36;
1144
+ const headerHeight = this.$.header.clientHeight;
1145
+ const footerHeight = this.$.footer.clientHeight;
1146
+ const scrollbarHeight = this.$.table.offsetHeight - this.$.table.clientHeight;
1147
+ const minHeight = headerHeight + rowHeight + footerHeight + scrollbarHeight;
1148
+
1149
+ // The style is set to host instead of the scroller so that the value can be overridden by the user with "grid { min-height: 0 }"
1150
+ // Prefer setting style in adopted style sheet to avoid the need to add a confusing inline style on the host element
1151
+ // If adopted style sheets are not supported, the style is set inline
1152
+ if (!this.__minHeightStyleSheet && supportsAdoptingStyleSheets) {
1153
+ this.__minHeightStyleSheet = new CSSStyleSheet();
1154
+ this.shadowRoot.adoptedStyleSheets = [...this.shadowRoot.adoptedStyleSheets, this.__minHeightStyleSheet];
1155
+ }
1156
+ if (this.__minHeightStyleSheet) {
1157
+ this.__minHeightStyleSheet.replaceSync(`:host { --_grid-min-height: ${minHeight}px; }`);
1158
+ } else {
1159
+ this.style.setProperty('--_grid-min-height', `${minHeight}px`);
1160
+ }
1161
+ }
1119
1162
  };
@@ -81,9 +81,6 @@ export const ScrollMixin = (superClass) =>
81
81
  type: Array,
82
82
  value: () => [],
83
83
  },
84
-
85
- /** @private */
86
- _rowWithFocusedElement: Element,
87
84
  };
88
85
  }
89
86
 
@@ -121,28 +118,23 @@ export const ScrollMixin = (superClass) =>
121
118
  this.scrollTarget = this.$.table;
122
119
 
123
120
  this.$.items.addEventListener('focusin', (e) => {
124
- const itemsIndex = e.composedPath().indexOf(this.$.items);
125
- this._rowWithFocusedElement = e.composedPath()[itemsIndex - 1];
121
+ const composedPath = e.composedPath();
122
+ const row = composedPath[composedPath.indexOf(this.$.items) - 1];
126
123
 
127
- if (this._rowWithFocusedElement) {
124
+ if (row) {
128
125
  // Make sure the row with the focused element is fully inside the visible viewport
129
126
  // Don't change scroll position if the user is interacting with the mouse
130
127
  if (!this._isMousedown) {
131
- this.__scrollIntoViewport(this._rowWithFocusedElement.index);
128
+ this.__scrollIntoViewport(row.index);
132
129
  }
133
130
 
134
131
  if (!this.$.table.contains(e.relatedTarget)) {
135
132
  // Virtualizer can't catch the event because if orginates from the light DOM.
136
133
  // Dispatch a virtualizer-element-focused event for virtualizer to catch.
137
- this.$.table.dispatchEvent(
138
- new CustomEvent('virtualizer-element-focused', { detail: { element: this._rowWithFocusedElement } }),
139
- );
134
+ this.$.table.dispatchEvent(new CustomEvent('virtualizer-element-focused', { detail: { element: row } }));
140
135
  }
141
136
  }
142
137
  });
143
- this.$.items.addEventListener('focusout', () => {
144
- this._rowWithFocusedElement = undefined;
145
- });
146
138
 
147
139
  this.$.table.addEventListener('scroll', () => this._afterScroll());
148
140
  }
@@ -145,6 +145,10 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
145
145
  checkbox.__item = item;
146
146
  checkbox.__rendererChecked = selected;
147
147
  checkbox.checked = selected;
148
+
149
+ const isSelectable = this._grid.__isItemSelectable(item);
150
+ checkbox.readonly = !isSelectable;
151
+ checkbox.hidden = !isSelectable && !selected;
148
152
  }
149
153
 
150
154
  /**
@@ -245,9 +249,18 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
245
249
  _onCellKeyDown(e) {
246
250
  const target = e.composedPath()[0];
247
251
  // Toggle on Space without having to enter interaction mode first
248
- if (e.keyCode === 32 && (target === this._headerCell || (this._cells.includes(target) && !this.autoSelect))) {
252
+ if (e.keyCode !== 32) {
253
+ return;
254
+ }
255
+ if (target === this._headerCell) {
256
+ if (this.selectAll) {
257
+ this._deselectAll();
258
+ } else {
259
+ this._selectAll();
260
+ }
261
+ } else if (this._cells.includes(target) && !this.autoSelect) {
249
262
  const checkbox = target._content.firstElementChild;
250
- checkbox.checked = !checkbox.checked;
263
+ this.__toggleItem(checkbox.__item);
251
264
  }
252
265
  }
253
266
 
@@ -358,6 +371,19 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
358
371
  */
359
372
  _deselectItem(_item) {}
360
373
 
374
+ /**
375
+ * Toggles the selected state of the given item.
376
+ * @param item the item to toggle
377
+ * @private
378
+ */
379
+ __toggleItem(item) {
380
+ if (this._grid._isSelected(item)) {
381
+ this._deselectItem(item);
382
+ } else {
383
+ this._selectItem(item);
384
+ }
385
+ }
386
+
361
387
  /**
362
388
  * IOS needs indeterminate + checked at the same time
363
389
  * @private
@@ -30,14 +30,15 @@ export const GridSelectionColumnMixin = (superClass) =>
30
30
  super();
31
31
 
32
32
  this.__boundOnActiveItemChanged = this.__onActiveItemChanged.bind(this);
33
- this.__boundOnDataProviderChanged = this.__onDataProviderChanged.bind(this);
33
+ this.__boundUpdateSelectAllVisibility = this.__updateSelectAllVisibility.bind(this);
34
34
  this.__boundOnSelectedItemsChanged = this.__onSelectedItemsChanged.bind(this);
35
35
  }
36
36
 
37
37
  /** @protected */
38
38
  disconnectedCallback() {
39
39
  this._grid.removeEventListener('active-item-changed', this.__boundOnActiveItemChanged);
40
- this._grid.removeEventListener('data-provider-changed', this.__boundOnDataProviderChanged);
40
+ this._grid.removeEventListener('data-provider-changed', this.__boundUpdateSelectAllVisibility);
41
+ this._grid.removeEventListener('is-item-selectable-changed', this.__boundUpdateSelectAllVisibility);
41
42
  this._grid.removeEventListener('filter-changed', this.__boundOnSelectedItemsChanged);
42
43
  this._grid.removeEventListener('selected-items-changed', this.__boundOnSelectedItemsChanged);
43
44
 
@@ -49,9 +50,11 @@ export const GridSelectionColumnMixin = (superClass) =>
49
50
  super.connectedCallback();
50
51
  if (this._grid) {
51
52
  this._grid.addEventListener('active-item-changed', this.__boundOnActiveItemChanged);
52
- this._grid.addEventListener('data-provider-changed', this.__boundOnDataProviderChanged);
53
+ this._grid.addEventListener('data-provider-changed', this.__boundUpdateSelectAllVisibility);
54
+ this._grid.addEventListener('is-item-selectable-changed', this.__boundUpdateSelectAllVisibility);
53
55
  this._grid.addEventListener('filter-changed', this.__boundOnSelectedItemsChanged);
54
56
  this._grid.addEventListener('selected-items-changed', this.__boundOnSelectedItemsChanged);
57
+ this.__updateSelectAllVisibility();
55
58
  }
56
59
  }
57
60
 
@@ -80,15 +83,6 @@ export const GridSelectionColumnMixin = (superClass) =>
80
83
  }
81
84
  }
82
85
 
83
- /**
84
- * Return true if array `a` contains all the items in `b`
85
- * We need this when sorting or to preserve selection after filtering.
86
- * @private
87
- */
88
- __arrayContains(a, b) {
89
- return Array.isArray(a) && Array.isArray(b) && b.every((i) => a.includes(i));
90
- }
91
-
92
86
  /**
93
87
  * Override a method from `GridSelectionColumnBaseMixin` to handle the user
94
88
  * selecting all items.
@@ -120,7 +114,9 @@ export const GridSelectionColumnMixin = (superClass) =>
120
114
  * @override
121
115
  */
122
116
  _selectItem(item) {
123
- this._grid.selectItem(item);
117
+ if (this._grid.__isItemSelectable(item)) {
118
+ this._grid.selectItem(item);
119
+ }
124
120
  }
125
121
 
126
122
  /**
@@ -132,7 +128,9 @@ export const GridSelectionColumnMixin = (superClass) =>
132
128
  * @override
133
129
  */
134
130
  _deselectItem(item) {
135
- this._grid.deselectItem(item);
131
+ if (this._grid.__isItemSelectable(item)) {
132
+ this._grid.deselectItem(item);
133
+ }
136
134
  }
137
135
 
138
136
  /** @private */
@@ -141,7 +139,7 @@ export const GridSelectionColumnMixin = (superClass) =>
141
139
  if (this.autoSelect) {
142
140
  const item = activeItem || this.__previousActiveItem;
143
141
  if (item) {
144
- this._grid._toggleItem(item);
142
+ this.__toggleItem(item);
145
143
  }
146
144
  }
147
145
  this.__previousActiveItem = activeItem;
@@ -160,7 +158,7 @@ export const GridSelectionColumnMixin = (superClass) =>
160
158
  if (!this._grid.selectedItems.length) {
161
159
  this.selectAll = false;
162
160
  this._indeterminate = false;
163
- } else if (this.__arrayContains(this._grid.selectedItems, items)) {
161
+ } else if (items.every((item) => this._grid._isSelected(item))) {
164
162
  this.selectAll = true;
165
163
  this._indeterminate = false;
166
164
  } else {
@@ -173,8 +171,11 @@ export const GridSelectionColumnMixin = (superClass) =>
173
171
  }
174
172
 
175
173
  /** @private */
176
- __onDataProviderChanged() {
177
- this._selectAllHidden = !Array.isArray(this._grid.items);
174
+ __updateSelectAllVisibility() {
175
+ // Hide select all checkbox when we can not easily determine the select all checkbox state:
176
+ // - When using a custom data provider
177
+ // - When using conditional selection, where users may not select all items
178
+ this._selectAllHidden = !Array.isArray(this._grid.items) || !!this._grid.isItemSelectable;
178
179
  }
179
180
 
180
181
  /**
@@ -28,4 +28,25 @@ export declare class SelectionMixinClass<TItem> {
28
28
  * @param item The item object
29
29
  */
30
30
  deselectItem(item: TItem): void;
31
+
32
+ /**
33
+ * A function to check whether a specific item in the grid may be
34
+ * selected or deselected by the user. Used by the selection column to
35
+ * conditionally enable to disable checkboxes for individual items. This
36
+ * function does not prevent programmatic selection/deselection of
37
+ * items. Changing the function does not modify the currently selected
38
+ * items.
39
+ *
40
+ * Configuring this function hides the select all checkbox of the grid
41
+ * selection column, which means users can not select or deselect all
42
+ * items anymore, nor do they get feedback on whether all items are
43
+ * selected or not.
44
+ *
45
+ * Receives an item instance and should return a boolean indicating
46
+ * whether users may change the selection state of that item.
47
+ *
48
+ * @param item The item object
49
+ * @return Whether the item is selectable
50
+ */
51
+ isItemSelectable: (item: TItem) => boolean;
31
52
  }
@@ -22,6 +22,29 @@ export const SelectionMixin = (superClass) =>
22
22
  sync: true,
23
23
  },
24
24
 
25
+ /**
26
+ * A function to check whether a specific item in the grid may be
27
+ * selected or deselected by the user. Used by the selection column to
28
+ * conditionally enable to disable checkboxes for individual items. This
29
+ * function does not prevent programmatic selection/deselection of
30
+ * items. Changing the function does not modify the currently selected
31
+ * items.
32
+ *
33
+ * Configuring this function hides the select all checkbox of the grid
34
+ * selection column, which means users can not select or deselect all
35
+ * items anymore, nor do they get feedback on whether all items are
36
+ * selected or not.
37
+ *
38
+ * Receives an item instance and should return a boolean indicating
39
+ * whether users may change the selection state of that item.
40
+ *
41
+ * @type {(item: !GridItem) => boolean}
42
+ */
43
+ isItemSelectable: {
44
+ type: Function,
45
+ notify: (() => true)(), // prevent Polymer analyzer from documenting a changed event
46
+ },
47
+
25
48
  /**
26
49
  * Set of selected item ids
27
50
  * @private
@@ -34,7 +57,7 @@ export const SelectionMixin = (superClass) =>
34
57
  }
35
58
 
36
59
  static get observers() {
37
- return ['__selectedItemsChanged(itemIdPath, selectedItems)'];
60
+ return ['__selectedItemsChanged(itemIdPath, selectedItems, isItemSelectable)'];
38
61
  }
39
62
 
40
63
  /**
@@ -46,6 +69,22 @@ export const SelectionMixin = (superClass) =>
46
69
  return this.__selectedKeys.has(this.getItemId(item));
47
70
  }
48
71
 
72
+ /**
73
+ * Determines whether the selection state of an item may be changed by the
74
+ * user.
75
+ *
76
+ * @private
77
+ */
78
+ __isItemSelectable(item) {
79
+ // Item is selectable by default if isItemSelectable is not configured
80
+ if (!this.isItemSelectable || !item) {
81
+ return true;
82
+ }
83
+
84
+ // Otherwise, check isItemSelectable function
85
+ return this.isItemSelectable(item);
86
+ }
87
+
49
88
  /**
50
89
  * Selects the given item.
51
90
  *
@@ -70,21 +109,6 @@ export const SelectionMixin = (superClass) =>
70
109
  }
71
110
  }
72
111
 
73
- /**
74
- * Toggles the selected state of the given item.
75
- *
76
- * @method toggle
77
- * @param {!GridItem} item The item object
78
- * @protected
79
- */
80
- _toggleItem(item) {
81
- if (!this._isSelected(item)) {
82
- this.selectItem(item);
83
- } else {
84
- this.deselectItem(item);
85
- }
86
- }
87
-
88
112
  /** @private */
89
113
  __selectedItemsChanged() {
90
114
  this.requestContentUpdate();
@@ -17,6 +17,7 @@ export const gridStyles = css`
17
17
  flex-direction: column;
18
18
  animation: 1ms vaadin-grid-appear;
19
19
  height: 400px;
20
+ min-height: var(--_grid-min-height, 0);
20
21
  flex: 1 1 auto;
21
22
  align-self: stretch;
22
23
  position: relative;
@@ -144,6 +145,10 @@ export const gridStyles = css`
144
145
  white-space: nowrap;
145
146
  }
146
147
 
148
+ [part~='cell'] {
149
+ outline: none;
150
+ }
151
+
147
152
  [part~='cell'] > [tabindex] {
148
153
  display: flex;
149
154
  align-items: inherit;
@@ -160,6 +160,7 @@ export type GridDefaultItem = any;
160
160
  * `collapsed-row` | Collapsed row
161
161
  * `expanded-row` | Expanded row
162
162
  * `selected-row` | Selected row
163
+ * `nonselectable-row` | Row that the user may not select or deselect
163
164
  * `details-opened-row` | Row with details open
164
165
  * `odd-row` | Odd row
165
166
  * `even-row` | Even row
@@ -187,6 +188,7 @@ export type GridDefaultItem = any;
187
188
  * `last-footer-row-cell` | Cell in the last footer row
188
189
  * `loading-row-cell` | Cell in a row that is waiting for data from data provider
189
190
  * `selected-row-cell` | Cell in a selected row
191
+ * `nonselectable-row-cell` | Cell in a row that the user may not select or deselect
190
192
  * `collapsed-row-cell` | Cell in a collapsed row
191
193
  * `expanded-row-cell` | Cell in an expanded row
192
194
  * `details-opened-row-cell` | Cell in an row with details open
@@ -160,6 +160,7 @@ registerStyles('vaadin-grid', gridStyles, { moduleId: 'vaadin-grid-styles' });
160
160
  * `collapsed-row` | Collapsed row
161
161
  * `expanded-row` | Expanded row
162
162
  * `selected-row` | Selected row
163
+ * `nonselectable-row` | Row that the user may not select or deselect
163
164
  * `details-opened-row` | Row with details open
164
165
  * `odd-row` | Odd row
165
166
  * `even-row` | Even row
@@ -187,6 +188,7 @@ registerStyles('vaadin-grid', gridStyles, { moduleId: 'vaadin-grid-styles' });
187
188
  * `last-footer-row-cell` | Cell in the last footer row
188
189
  * `loading-row-cell` | Cell in a row that is waiting for data from data provider
189
190
  * `selected-row-cell` | Cell in a selected row
191
+ * `nonselectable-row-cell` | Cell in a row that the user may not select or deselect
190
192
  * `collapsed-row-cell` | Cell in a collapsed row
191
193
  * `expanded-row-cell` | Cell in an expanded row
192
194
  * `details-opened-row-cell` | Cell in an row with details open
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/grid",
4
- "version": "24.6.0-alpha2",
4
+ "version": "24.6.0-alpha4",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -238,7 +238,7 @@
238
238
  },
239
239
  {
240
240
  "name": "vaadin-grid-column",
241
- "description": "A `<vaadin-grid-column>` is used to configure how a column in `<vaadin-grid>`\nshould look like.\n\nSee [`<vaadin-grid>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid) documentation for instructions on how\nto configure the `<vaadin-grid-column>`.",
241
+ "description": "A `<vaadin-grid-column>` is used to configure how a column in `<vaadin-grid>`\nshould look like.\n\nSee [`<vaadin-grid>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid) documentation for instructions on how\nto configure the `<vaadin-grid-column>`.",
242
242
  "attributes": [
243
243
  {
244
244
  "name": "resizable",
@@ -951,7 +951,7 @@
951
951
  },
952
952
  {
953
953
  "name": "vaadin-grid-selection-column",
954
- "description": "`<vaadin-grid-selection-column>` is a helper element for the `<vaadin-grid>`\nthat provides default renderers and functionality for item selection.\n\n#### Example:\n```html\n<vaadin-grid items=\"[[items]]\">\n <vaadin-grid-selection-column frozen auto-select></vaadin-grid-selection-column>\n\n <vaadin-grid-column>\n ...\n```\n\nBy default the selection column displays `<vaadin-checkbox>` elements in the\ncolumn cells. The checkboxes in the body rows toggle selection of the corresponding row items.\n\nWhen the grid data is provided as an array of [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid#property-items),\nthe column header gets an additional checkbox that can be used for toggling\nselection for all the items at once.\n\n__The default content can also be overridden__",
954
+ "description": "`<vaadin-grid-selection-column>` is a helper element for the `<vaadin-grid>`\nthat provides default renderers and functionality for item selection.\n\n#### Example:\n```html\n<vaadin-grid items=\"[[items]]\">\n <vaadin-grid-selection-column frozen auto-select></vaadin-grid-selection-column>\n\n <vaadin-grid-column>\n ...\n```\n\nBy default the selection column displays `<vaadin-checkbox>` elements in the\ncolumn cells. The checkboxes in the body rows toggle selection of the corresponding row items.\n\nWhen the grid data is provided as an array of [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid#property-items),\nthe column header gets an additional checkbox that can be used for toggling\nselection for all the items at once.\n\n__The default content can also be overridden__",
955
955
  "attributes": [
956
956
  {
957
957
  "name": "resizable",
@@ -2152,7 +2152,7 @@
2152
2152
  },
2153
2153
  {
2154
2154
  "name": "vaadin-grid",
2155
- "description": "`<vaadin-grid>` is a free, high quality data grid / data table Web Component. The content of the\nthe grid can be populated by using renderer callback function.\n\n### Quick Start\n\nStart with an assigning an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid#property-items) property to visualize your data.\n\nUse the [`<vaadin-grid-column>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-column) element to configure the grid columns. Set `path` and `header`\nshorthand properties for the columns to define what gets rendered in the cells of the column.\n\n#### Example:\n```html\n<vaadin-grid>\n <vaadin-grid-column path=\"name.first\" header=\"First name\"></vaadin-grid-column>\n <vaadin-grid-column path=\"name.last\" header=\"Last name\"></vaadin-grid-column>\n <vaadin-grid-column path=\"email\"></vaadin-grid-column>\n</vaadin-grid>\n```\n\nFor custom content `vaadin-grid-column` element provides you with three types of `renderer` callback functions: `headerRenderer`,\n`renderer` and `footerRenderer`.\n\nEach of those renderer functions provides `root`, `column`, `model` arguments when applicable.\nGenerate DOM content, append it to the `root` element and control the state\nof the host element by accessing `column`. Before generating new content,\nusers are able to check if there is already content in `root` for reusing it.\n\nRenderers are called on initialization of new column cells and each time the\nrelated row model is updated. DOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n#### Example:\n```html\n<vaadin-grid>\n <vaadin-grid-column></vaadin-grid-column>\n <vaadin-grid-column></vaadin-grid-column>\n <vaadin-grid-column></vaadin-grid-column>\n</vaadin-grid>\n```\n```js\nconst grid = document.querySelector('vaadin-grid');\ngrid.items = [{'name': 'John', 'surname': 'Lennon', 'role': 'singer'},\n {'name': 'Ringo', 'surname': 'Starr', 'role': 'drums'}];\n\nconst columns = grid.querySelectorAll('vaadin-grid-column');\n\ncolumns[0].headerRenderer = function(root) {\n root.textContent = 'Name';\n};\ncolumns[0].renderer = function(root, column, model) {\n root.textContent = model.item.name;\n};\n\ncolumns[1].headerRenderer = function(root) {\n root.textContent = 'Surname';\n};\ncolumns[1].renderer = function(root, column, model) {\n root.textContent = model.item.surname;\n};\n\ncolumns[2].headerRenderer = function(root) {\n root.textContent = 'Role';\n};\ncolumns[2].renderer = function(root, column, model) {\n root.textContent = model.item.role;\n};\n```\n\nThe following properties are available in the `model` argument:\n\nProperty name | Type | Description\n--------------|------|------------\n`index`| Number | The index of the item.\n`item` | String or Object | The item.\n`level` | Number | Number of the item's tree sublevel, starts from 0.\n`expanded` | Boolean | True if the item's tree sublevel is expanded.\n`selected` | Boolean | True if the item is selected.\n`detailsOpened` | Boolean | True if the item's row details are open.\n\nThe following helper elements can be used for further customization:\n- [`<vaadin-grid-column-group>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-column-group)\n- [`<vaadin-grid-filter>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-filter)\n- [`<vaadin-grid-sorter>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-sorter)\n- [`<vaadin-grid-selection-column>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-selection-column)\n- [`<vaadin-grid-tree-toggle>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-tree-toggle)\n\n__Note that the helper elements must be explicitly imported.__\nIf you want to import everything at once you can use the `all-imports.html` bundle.\n\n### Lazy Loading with Function Data Provider\n\nIn addition to assigning an array to the items property, you can alternatively\nprovide the `<vaadin-grid>` data through the\n[`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid#property-dataProvider) function property.\nThe `<vaadin-grid>` calls this function lazily, only when it needs more data\nto be displayed.\n\nSee the [`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid#property-dataProvider) property\ndocumentation for the detailed data provider arguments description.\n\n__Note that expanding the tree grid's item will trigger a call to the `dataProvider`.__\n\n__Also, note that when using function data providers, the total number of items\nneeds to be set manually. The total number of items can be returned\nin the second argument of the data provider callback:__\n\n```javascript\ngrid.dataProvider = ({page, pageSize}, callback) => {\n // page: the requested page index\n // pageSize: number of items on one page\n const url = `https://api.example/data?page=${page}&per_page=${pageSize}`;\n\n fetch(url)\n .then((res) => res.json())\n .then(({ employees, totalSize }) => {\n callback(employees, totalSize);\n });\n};\n```\n\n__Alternatively, you can use the `size` property to set the total number of items:__\n\n```javascript\ngrid.size = 200; // The total number of items\ngrid.dataProvider = ({page, pageSize}, callback) => {\n const url = `https://api.example/data?page=${page}&per_page=${pageSize}`;\n\n fetch(url)\n .then((res) => res.json())\n .then((resJson) => callback(resJson.employees));\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------------|----------------\n`row` | Row in the internal table\n`body-row` | Body row in the internal table\n`collapsed-row` | Collapsed row\n`expanded-row` | Expanded row\n`selected-row` | Selected row\n`details-opened-row` | Row with details open\n`odd-row` | Odd row\n`even-row` | Even row\n`first-row` | The first body row\n`last-row` | The last body row\n`dragstart-row` | Set on the row for one frame when drag is starting.\n`dragover-above-row` | Set on the row when the a row is dragged over above\n`dragover-below-row` | Set on the row when the a row is dragged over below\n`dragover-on-top-row` | Set on the row when the a row is dragged over on top\n`drag-disabled-row` | Set to a row that isn't available for dragging\n`drop-disabled-row` | Set to a row that can't be dropped on top of\n`cell` | Cell in the internal table\n`header-cell` | Header cell in the internal table\n`body-cell` | Body cell in the internal table\n`footer-cell` | Footer cell in the internal table\n`details-cell` | Row details cell in the internal table\n`focused-cell` | Focused cell in the internal table\n`odd-row-cell` | Cell in an odd row\n`even-row-cell` | Cell in an even row\n`first-row-cell` | Cell in the first body row\n`last-row-cell` | Cell in the last body row\n`first-header-row-cell` | Cell in the first header row\n`first-footer-row-cell` | Cell in the first footer row\n`last-header-row-cell` | Cell in the last header row\n`last-footer-row-cell` | Cell in the last footer row\n`loading-row-cell` | Cell in a row that is waiting for data from data provider\n`selected-row-cell` | Cell in a selected row\n`collapsed-row-cell` | Cell in a collapsed row\n`expanded-row-cell` | Cell in an expanded row\n`details-opened-row-cell` | Cell in an row with details open\n`dragstart-row-cell` | Cell in the ghost image row, but not in a source row\n`drag-source-row-cell` | Cell in a source row, but not in the ghost image\n`dragover-above-row-cell` | Cell in a row that has another row dragged over above\n`dragover-below-row-cell` | Cell in a row that has another row dragged over below\n`dragover-on-top-row-cell` | Cell in a row that has another row dragged over on top\n`drag-disabled-row-cell` | Cell in a row that isn't available for dragging\n`drop-disabled-row-cell` | Cell in a row that can't be dropped on top of\n`frozen-cell` | Frozen cell in the internal table\n`frozen-to-end-cell` | Frozen to end cell in the internal table\n`last-frozen-cell` | Last frozen cell\n`first-frozen-to-end-cell` | First cell frozen to end\n`first-column-cell` | First visible cell on a row\n`last-column-cell` | Last visible cell on a row\n`reorder-allowed-cell` | Cell in a column where another column can be reordered\n`reorder-dragging-cell` | Cell in a column currently being reordered\n`resize-handle` | Handle for resizing the columns\n`empty-state` | The container for the content to be displayed when there are no body rows to show\n`reorder-ghost` | Ghost element of the header cell being dragged\n\nThe following state attributes are available for styling:\n\nAttribute | Description | Part name\n----------------------|---------------------------------------------------------------------------------------------------|-----------\n`loading` | Set when the grid is loading data from data provider | :host\n`interacting` | Keyboard navigation in interaction mode | :host\n`navigating` | Keyboard navigation in navigation mode | :host\n`overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host\n`reordering` | Set when the grid's columns are being reordered | :host\n`dragover` | Set when the grid (not a specific row) is dragged over | :host\n`dragging-rows` | Set when grid rows are dragged | :host\n`reorder-status` | Reflects the status of a cell while columns are being reordered | cell\n`frozen` | Frozen cell | cell\n`frozen-to-end` | Cell frozen to end | cell\n`last-frozen` | Last frozen cell | cell\n`first-frozen-to-end` | First cell frozen to end | cell\n`first-column` | First visible cell on a row | cell\n`last-column` | Last visible cell on a row | cell\n`selected` | Selected row | row\n`expanded` | Expanded row | row\n`details-opened` | Row with details open | row\n`loading` | Row that is waiting for data from data provider | row\n`odd` | Odd row | row\n`first` | The first body row | row\n`last` | The last body row | row\n`dragstart` | Set for one frame when starting to drag a row. The value is a number when dragging multiple rows | row\n`dragover` | Set when the row is dragged over | row\n`drag-disabled` | Set to a row that isn't available for dragging | row\n`drop-disabled` | Set to a row that can't be dropped on top of | row\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
2155
+ "description": "`<vaadin-grid>` is a free, high quality data grid / data table Web Component. The content of the\nthe grid can be populated by using renderer callback function.\n\n### Quick Start\n\nStart with an assigning an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid#property-items) property to visualize your data.\n\nUse the [`<vaadin-grid-column>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-column) element to configure the grid columns. Set `path` and `header`\nshorthand properties for the columns to define what gets rendered in the cells of the column.\n\n#### Example:\n```html\n<vaadin-grid>\n <vaadin-grid-column path=\"name.first\" header=\"First name\"></vaadin-grid-column>\n <vaadin-grid-column path=\"name.last\" header=\"Last name\"></vaadin-grid-column>\n <vaadin-grid-column path=\"email\"></vaadin-grid-column>\n</vaadin-grid>\n```\n\nFor custom content `vaadin-grid-column` element provides you with three types of `renderer` callback functions: `headerRenderer`,\n`renderer` and `footerRenderer`.\n\nEach of those renderer functions provides `root`, `column`, `model` arguments when applicable.\nGenerate DOM content, append it to the `root` element and control the state\nof the host element by accessing `column`. Before generating new content,\nusers are able to check if there is already content in `root` for reusing it.\n\nRenderers are called on initialization of new column cells and each time the\nrelated row model is updated. DOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n#### Example:\n```html\n<vaadin-grid>\n <vaadin-grid-column></vaadin-grid-column>\n <vaadin-grid-column></vaadin-grid-column>\n <vaadin-grid-column></vaadin-grid-column>\n</vaadin-grid>\n```\n```js\nconst grid = document.querySelector('vaadin-grid');\ngrid.items = [{'name': 'John', 'surname': 'Lennon', 'role': 'singer'},\n {'name': 'Ringo', 'surname': 'Starr', 'role': 'drums'}];\n\nconst columns = grid.querySelectorAll('vaadin-grid-column');\n\ncolumns[0].headerRenderer = function(root) {\n root.textContent = 'Name';\n};\ncolumns[0].renderer = function(root, column, model) {\n root.textContent = model.item.name;\n};\n\ncolumns[1].headerRenderer = function(root) {\n root.textContent = 'Surname';\n};\ncolumns[1].renderer = function(root, column, model) {\n root.textContent = model.item.surname;\n};\n\ncolumns[2].headerRenderer = function(root) {\n root.textContent = 'Role';\n};\ncolumns[2].renderer = function(root, column, model) {\n root.textContent = model.item.role;\n};\n```\n\nThe following properties are available in the `model` argument:\n\nProperty name | Type | Description\n--------------|------|------------\n`index`| Number | The index of the item.\n`item` | String or Object | The item.\n`level` | Number | Number of the item's tree sublevel, starts from 0.\n`expanded` | Boolean | True if the item's tree sublevel is expanded.\n`selected` | Boolean | True if the item is selected.\n`detailsOpened` | Boolean | True if the item's row details are open.\n\nThe following helper elements can be used for further customization:\n- [`<vaadin-grid-column-group>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-column-group)\n- [`<vaadin-grid-filter>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-filter)\n- [`<vaadin-grid-sorter>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-sorter)\n- [`<vaadin-grid-selection-column>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-selection-column)\n- [`<vaadin-grid-tree-toggle>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-tree-toggle)\n\n__Note that the helper elements must be explicitly imported.__\nIf you want to import everything at once you can use the `all-imports.html` bundle.\n\n### Lazy Loading with Function Data Provider\n\nIn addition to assigning an array to the items property, you can alternatively\nprovide the `<vaadin-grid>` data through the\n[`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid#property-dataProvider) function property.\nThe `<vaadin-grid>` calls this function lazily, only when it needs more data\nto be displayed.\n\nSee the [`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid#property-dataProvider) property\ndocumentation for the detailed data provider arguments description.\n\n__Note that expanding the tree grid's item will trigger a call to the `dataProvider`.__\n\n__Also, note that when using function data providers, the total number of items\nneeds to be set manually. The total number of items can be returned\nin the second argument of the data provider callback:__\n\n```javascript\ngrid.dataProvider = ({page, pageSize}, callback) => {\n // page: the requested page index\n // pageSize: number of items on one page\n const url = `https://api.example/data?page=${page}&per_page=${pageSize}`;\n\n fetch(url)\n .then((res) => res.json())\n .then(({ employees, totalSize }) => {\n callback(employees, totalSize);\n });\n};\n```\n\n__Alternatively, you can use the `size` property to set the total number of items:__\n\n```javascript\ngrid.size = 200; // The total number of items\ngrid.dataProvider = ({page, pageSize}, callback) => {\n const url = `https://api.example/data?page=${page}&per_page=${pageSize}`;\n\n fetch(url)\n .then((res) => res.json())\n .then((resJson) => callback(resJson.employees));\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------------|----------------\n`row` | Row in the internal table\n`body-row` | Body row in the internal table\n`collapsed-row` | Collapsed row\n`expanded-row` | Expanded row\n`selected-row` | Selected row\n`nonselectable-row` | Row that the user may not select or deselect\n`details-opened-row` | Row with details open\n`odd-row` | Odd row\n`even-row` | Even row\n`first-row` | The first body row\n`last-row` | The last body row\n`dragstart-row` | Set on the row for one frame when drag is starting.\n`dragover-above-row` | Set on the row when the a row is dragged over above\n`dragover-below-row` | Set on the row when the a row is dragged over below\n`dragover-on-top-row` | Set on the row when the a row is dragged over on top\n`drag-disabled-row` | Set to a row that isn't available for dragging\n`drop-disabled-row` | Set to a row that can't be dropped on top of\n`cell` | Cell in the internal table\n`header-cell` | Header cell in the internal table\n`body-cell` | Body cell in the internal table\n`footer-cell` | Footer cell in the internal table\n`details-cell` | Row details cell in the internal table\n`focused-cell` | Focused cell in the internal table\n`odd-row-cell` | Cell in an odd row\n`even-row-cell` | Cell in an even row\n`first-row-cell` | Cell in the first body row\n`last-row-cell` | Cell in the last body row\n`first-header-row-cell` | Cell in the first header row\n`first-footer-row-cell` | Cell in the first footer row\n`last-header-row-cell` | Cell in the last header row\n`last-footer-row-cell` | Cell in the last footer row\n`loading-row-cell` | Cell in a row that is waiting for data from data provider\n`selected-row-cell` | Cell in a selected row\n`nonselectable-row-cell` | Cell in a row that the user may not select or deselect\n`collapsed-row-cell` | Cell in a collapsed row\n`expanded-row-cell` | Cell in an expanded row\n`details-opened-row-cell` | Cell in an row with details open\n`dragstart-row-cell` | Cell in the ghost image row, but not in a source row\n`drag-source-row-cell` | Cell in a source row, but not in the ghost image\n`dragover-above-row-cell` | Cell in a row that has another row dragged over above\n`dragover-below-row-cell` | Cell in a row that has another row dragged over below\n`dragover-on-top-row-cell` | Cell in a row that has another row dragged over on top\n`drag-disabled-row-cell` | Cell in a row that isn't available for dragging\n`drop-disabled-row-cell` | Cell in a row that can't be dropped on top of\n`frozen-cell` | Frozen cell in the internal table\n`frozen-to-end-cell` | Frozen to end cell in the internal table\n`last-frozen-cell` | Last frozen cell\n`first-frozen-to-end-cell` | First cell frozen to end\n`first-column-cell` | First visible cell on a row\n`last-column-cell` | Last visible cell on a row\n`reorder-allowed-cell` | Cell in a column where another column can be reordered\n`reorder-dragging-cell` | Cell in a column currently being reordered\n`resize-handle` | Handle for resizing the columns\n`empty-state` | The container for the content to be displayed when there are no body rows to show\n`reorder-ghost` | Ghost element of the header cell being dragged\n\nThe following state attributes are available for styling:\n\nAttribute | Description | Part name\n----------------------|---------------------------------------------------------------------------------------------------|-----------\n`loading` | Set when the grid is loading data from data provider | :host\n`interacting` | Keyboard navigation in interaction mode | :host\n`navigating` | Keyboard navigation in navigation mode | :host\n`overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host\n`reordering` | Set when the grid's columns are being reordered | :host\n`dragover` | Set when the grid (not a specific row) is dragged over | :host\n`dragging-rows` | Set when grid rows are dragged | :host\n`reorder-status` | Reflects the status of a cell while columns are being reordered | cell\n`frozen` | Frozen cell | cell\n`frozen-to-end` | Cell frozen to end | cell\n`last-frozen` | Last frozen cell | cell\n`first-frozen-to-end` | First cell frozen to end | cell\n`first-column` | First visible cell on a row | cell\n`last-column` | Last visible cell on a row | cell\n`selected` | Selected row | row\n`expanded` | Expanded row | row\n`details-opened` | Row with details open | row\n`loading` | Row that is waiting for data from data provider | row\n`odd` | Odd row | row\n`first` | The first body row | row\n`last` | The last body row | row\n`dragstart` | Set for one frame when starting to drag a row. The value is a number when dragging multiple rows | row\n`dragover` | Set when the row is dragged over | row\n`drag-disabled` | Set to a row that isn't available for dragging | row\n`drop-disabled` | Set to a row that can't be dropped on top of | row\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
2156
2156
  "attributes": [
2157
2157
  {
2158
2158
  "name": "size",
@@ -2403,6 +2403,17 @@
2403
2403
  ]
2404
2404
  }
2405
2405
  },
2406
+ {
2407
+ "name": "isItemSelectable",
2408
+ "description": "A function to check whether a specific item in the grid may be\nselected or deselected by the user. Used by the selection column to\nconditionally enable to disable checkboxes for individual items. This\nfunction does not prevent programmatic selection/deselection of\nitems. Changing the function does not modify the currently selected\nitems.\n\nConfiguring this function hides the select all checkbox of the grid\nselection column, which means users can not select or deselect all\nitems anymore, nor do they get feedback on whether all items are\nselected or not.\n\nReceives an item instance and should return a boolean indicating\nwhether users may change the selection state of that item.",
2409
+ "value": {
2410
+ "type": [
2411
+ "Function",
2412
+ "null",
2413
+ "undefined"
2414
+ ]
2415
+ }
2416
+ },
2406
2417
  {
2407
2418
  "name": "multiSort",
2408
2419
  "description": "When `true`, all `<vaadin-grid-sorter>` are applied for sorting.",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/grid",
4
- "version": "24.6.0-alpha2",
4
+ "version": "24.6.0-alpha4",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -100,7 +100,7 @@
100
100
  },
101
101
  {
102
102
  "name": "vaadin-grid-column",
103
- "description": "A `<vaadin-grid-column>` is used to configure how a column in `<vaadin-grid>`\nshould look like.\n\nSee [`<vaadin-grid>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid) documentation for instructions on how\nto configure the `<vaadin-grid-column>`.",
103
+ "description": "A `<vaadin-grid-column>` is used to configure how a column in `<vaadin-grid>`\nshould look like.\n\nSee [`<vaadin-grid>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid) documentation for instructions on how\nto configure the `<vaadin-grid-column>`.",
104
104
  "extension": true,
105
105
  "attributes": [
106
106
  {
@@ -366,7 +366,7 @@
366
366
  },
367
367
  {
368
368
  "name": "vaadin-grid-selection-column",
369
- "description": "`<vaadin-grid-selection-column>` is a helper element for the `<vaadin-grid>`\nthat provides default renderers and functionality for item selection.\n\n#### Example:\n```html\n<vaadin-grid items=\"[[items]]\">\n <vaadin-grid-selection-column frozen auto-select></vaadin-grid-selection-column>\n\n <vaadin-grid-column>\n ...\n```\n\nBy default the selection column displays `<vaadin-checkbox>` elements in the\ncolumn cells. The checkboxes in the body rows toggle selection of the corresponding row items.\n\nWhen the grid data is provided as an array of [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid#property-items),\nthe column header gets an additional checkbox that can be used for toggling\nselection for all the items at once.\n\n__The default content can also be overridden__",
369
+ "description": "`<vaadin-grid-selection-column>` is a helper element for the `<vaadin-grid>`\nthat provides default renderers and functionality for item selection.\n\n#### Example:\n```html\n<vaadin-grid items=\"[[items]]\">\n <vaadin-grid-selection-column frozen auto-select></vaadin-grid-selection-column>\n\n <vaadin-grid-column>\n ...\n```\n\nBy default the selection column displays `<vaadin-checkbox>` elements in the\ncolumn cells. The checkboxes in the body rows toggle selection of the corresponding row items.\n\nWhen the grid data is provided as an array of [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid#property-items),\nthe column header gets an additional checkbox that can be used for toggling\nselection for all the items at once.\n\n__The default content can also be overridden__",
370
370
  "extension": true,
371
371
  "attributes": [
372
372
  {
@@ -828,7 +828,7 @@
828
828
  },
829
829
  {
830
830
  "name": "vaadin-grid",
831
- "description": "`<vaadin-grid>` is a free, high quality data grid / data table Web Component. The content of the\nthe grid can be populated by using renderer callback function.\n\n### Quick Start\n\nStart with an assigning an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid#property-items) property to visualize your data.\n\nUse the [`<vaadin-grid-column>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-column) element to configure the grid columns. Set `path` and `header`\nshorthand properties for the columns to define what gets rendered in the cells of the column.\n\n#### Example:\n```html\n<vaadin-grid>\n <vaadin-grid-column path=\"name.first\" header=\"First name\"></vaadin-grid-column>\n <vaadin-grid-column path=\"name.last\" header=\"Last name\"></vaadin-grid-column>\n <vaadin-grid-column path=\"email\"></vaadin-grid-column>\n</vaadin-grid>\n```\n\nFor custom content `vaadin-grid-column` element provides you with three types of `renderer` callback functions: `headerRenderer`,\n`renderer` and `footerRenderer`.\n\nEach of those renderer functions provides `root`, `column`, `model` arguments when applicable.\nGenerate DOM content, append it to the `root` element and control the state\nof the host element by accessing `column`. Before generating new content,\nusers are able to check if there is already content in `root` for reusing it.\n\nRenderers are called on initialization of new column cells and each time the\nrelated row model is updated. DOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n#### Example:\n```html\n<vaadin-grid>\n <vaadin-grid-column></vaadin-grid-column>\n <vaadin-grid-column></vaadin-grid-column>\n <vaadin-grid-column></vaadin-grid-column>\n</vaadin-grid>\n```\n```js\nconst grid = document.querySelector('vaadin-grid');\ngrid.items = [{'name': 'John', 'surname': 'Lennon', 'role': 'singer'},\n {'name': 'Ringo', 'surname': 'Starr', 'role': 'drums'}];\n\nconst columns = grid.querySelectorAll('vaadin-grid-column');\n\ncolumns[0].headerRenderer = function(root) {\n root.textContent = 'Name';\n};\ncolumns[0].renderer = function(root, column, model) {\n root.textContent = model.item.name;\n};\n\ncolumns[1].headerRenderer = function(root) {\n root.textContent = 'Surname';\n};\ncolumns[1].renderer = function(root, column, model) {\n root.textContent = model.item.surname;\n};\n\ncolumns[2].headerRenderer = function(root) {\n root.textContent = 'Role';\n};\ncolumns[2].renderer = function(root, column, model) {\n root.textContent = model.item.role;\n};\n```\n\nThe following properties are available in the `model` argument:\n\nProperty name | Type | Description\n--------------|------|------------\n`index`| Number | The index of the item.\n`item` | String or Object | The item.\n`level` | Number | Number of the item's tree sublevel, starts from 0.\n`expanded` | Boolean | True if the item's tree sublevel is expanded.\n`selected` | Boolean | True if the item is selected.\n`detailsOpened` | Boolean | True if the item's row details are open.\n\nThe following helper elements can be used for further customization:\n- [`<vaadin-grid-column-group>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-column-group)\n- [`<vaadin-grid-filter>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-filter)\n- [`<vaadin-grid-sorter>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-sorter)\n- [`<vaadin-grid-selection-column>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-selection-column)\n- [`<vaadin-grid-tree-toggle>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid-tree-toggle)\n\n__Note that the helper elements must be explicitly imported.__\nIf you want to import everything at once you can use the `all-imports.html` bundle.\n\n### Lazy Loading with Function Data Provider\n\nIn addition to assigning an array to the items property, you can alternatively\nprovide the `<vaadin-grid>` data through the\n[`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid#property-dataProvider) function property.\nThe `<vaadin-grid>` calls this function lazily, only when it needs more data\nto be displayed.\n\nSee the [`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha2/#/elements/vaadin-grid#property-dataProvider) property\ndocumentation for the detailed data provider arguments description.\n\n__Note that expanding the tree grid's item will trigger a call to the `dataProvider`.__\n\n__Also, note that when using function data providers, the total number of items\nneeds to be set manually. The total number of items can be returned\nin the second argument of the data provider callback:__\n\n```javascript\ngrid.dataProvider = ({page, pageSize}, callback) => {\n // page: the requested page index\n // pageSize: number of items on one page\n const url = `https://api.example/data?page=${page}&per_page=${pageSize}`;\n\n fetch(url)\n .then((res) => res.json())\n .then(({ employees, totalSize }) => {\n callback(employees, totalSize);\n });\n};\n```\n\n__Alternatively, you can use the `size` property to set the total number of items:__\n\n```javascript\ngrid.size = 200; // The total number of items\ngrid.dataProvider = ({page, pageSize}, callback) => {\n const url = `https://api.example/data?page=${page}&per_page=${pageSize}`;\n\n fetch(url)\n .then((res) => res.json())\n .then((resJson) => callback(resJson.employees));\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------------|----------------\n`row` | Row in the internal table\n`body-row` | Body row in the internal table\n`collapsed-row` | Collapsed row\n`expanded-row` | Expanded row\n`selected-row` | Selected row\n`details-opened-row` | Row with details open\n`odd-row` | Odd row\n`even-row` | Even row\n`first-row` | The first body row\n`last-row` | The last body row\n`dragstart-row` | Set on the row for one frame when drag is starting.\n`dragover-above-row` | Set on the row when the a row is dragged over above\n`dragover-below-row` | Set on the row when the a row is dragged over below\n`dragover-on-top-row` | Set on the row when the a row is dragged over on top\n`drag-disabled-row` | Set to a row that isn't available for dragging\n`drop-disabled-row` | Set to a row that can't be dropped on top of\n`cell` | Cell in the internal table\n`header-cell` | Header cell in the internal table\n`body-cell` | Body cell in the internal table\n`footer-cell` | Footer cell in the internal table\n`details-cell` | Row details cell in the internal table\n`focused-cell` | Focused cell in the internal table\n`odd-row-cell` | Cell in an odd row\n`even-row-cell` | Cell in an even row\n`first-row-cell` | Cell in the first body row\n`last-row-cell` | Cell in the last body row\n`first-header-row-cell` | Cell in the first header row\n`first-footer-row-cell` | Cell in the first footer row\n`last-header-row-cell` | Cell in the last header row\n`last-footer-row-cell` | Cell in the last footer row\n`loading-row-cell` | Cell in a row that is waiting for data from data provider\n`selected-row-cell` | Cell in a selected row\n`collapsed-row-cell` | Cell in a collapsed row\n`expanded-row-cell` | Cell in an expanded row\n`details-opened-row-cell` | Cell in an row with details open\n`dragstart-row-cell` | Cell in the ghost image row, but not in a source row\n`drag-source-row-cell` | Cell in a source row, but not in the ghost image\n`dragover-above-row-cell` | Cell in a row that has another row dragged over above\n`dragover-below-row-cell` | Cell in a row that has another row dragged over below\n`dragover-on-top-row-cell` | Cell in a row that has another row dragged over on top\n`drag-disabled-row-cell` | Cell in a row that isn't available for dragging\n`drop-disabled-row-cell` | Cell in a row that can't be dropped on top of\n`frozen-cell` | Frozen cell in the internal table\n`frozen-to-end-cell` | Frozen to end cell in the internal table\n`last-frozen-cell` | Last frozen cell\n`first-frozen-to-end-cell` | First cell frozen to end\n`first-column-cell` | First visible cell on a row\n`last-column-cell` | Last visible cell on a row\n`reorder-allowed-cell` | Cell in a column where another column can be reordered\n`reorder-dragging-cell` | Cell in a column currently being reordered\n`resize-handle` | Handle for resizing the columns\n`empty-state` | The container for the content to be displayed when there are no body rows to show\n`reorder-ghost` | Ghost element of the header cell being dragged\n\nThe following state attributes are available for styling:\n\nAttribute | Description | Part name\n----------------------|---------------------------------------------------------------------------------------------------|-----------\n`loading` | Set when the grid is loading data from data provider | :host\n`interacting` | Keyboard navigation in interaction mode | :host\n`navigating` | Keyboard navigation in navigation mode | :host\n`overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host\n`reordering` | Set when the grid's columns are being reordered | :host\n`dragover` | Set when the grid (not a specific row) is dragged over | :host\n`dragging-rows` | Set when grid rows are dragged | :host\n`reorder-status` | Reflects the status of a cell while columns are being reordered | cell\n`frozen` | Frozen cell | cell\n`frozen-to-end` | Cell frozen to end | cell\n`last-frozen` | Last frozen cell | cell\n`first-frozen-to-end` | First cell frozen to end | cell\n`first-column` | First visible cell on a row | cell\n`last-column` | Last visible cell on a row | cell\n`selected` | Selected row | row\n`expanded` | Expanded row | row\n`details-opened` | Row with details open | row\n`loading` | Row that is waiting for data from data provider | row\n`odd` | Odd row | row\n`first` | The first body row | row\n`last` | The last body row | row\n`dragstart` | Set for one frame when starting to drag a row. The value is a number when dragging multiple rows | row\n`dragover` | Set when the row is dragged over | row\n`drag-disabled` | Set to a row that isn't available for dragging | row\n`drop-disabled` | Set to a row that can't be dropped on top of | row\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
831
+ "description": "`<vaadin-grid>` is a free, high quality data grid / data table Web Component. The content of the\nthe grid can be populated by using renderer callback function.\n\n### Quick Start\n\nStart with an assigning an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid#property-items) property to visualize your data.\n\nUse the [`<vaadin-grid-column>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-column) element to configure the grid columns. Set `path` and `header`\nshorthand properties for the columns to define what gets rendered in the cells of the column.\n\n#### Example:\n```html\n<vaadin-grid>\n <vaadin-grid-column path=\"name.first\" header=\"First name\"></vaadin-grid-column>\n <vaadin-grid-column path=\"name.last\" header=\"Last name\"></vaadin-grid-column>\n <vaadin-grid-column path=\"email\"></vaadin-grid-column>\n</vaadin-grid>\n```\n\nFor custom content `vaadin-grid-column` element provides you with three types of `renderer` callback functions: `headerRenderer`,\n`renderer` and `footerRenderer`.\n\nEach of those renderer functions provides `root`, `column`, `model` arguments when applicable.\nGenerate DOM content, append it to the `root` element and control the state\nof the host element by accessing `column`. Before generating new content,\nusers are able to check if there is already content in `root` for reusing it.\n\nRenderers are called on initialization of new column cells and each time the\nrelated row model is updated. DOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n#### Example:\n```html\n<vaadin-grid>\n <vaadin-grid-column></vaadin-grid-column>\n <vaadin-grid-column></vaadin-grid-column>\n <vaadin-grid-column></vaadin-grid-column>\n</vaadin-grid>\n```\n```js\nconst grid = document.querySelector('vaadin-grid');\ngrid.items = [{'name': 'John', 'surname': 'Lennon', 'role': 'singer'},\n {'name': 'Ringo', 'surname': 'Starr', 'role': 'drums'}];\n\nconst columns = grid.querySelectorAll('vaadin-grid-column');\n\ncolumns[0].headerRenderer = function(root) {\n root.textContent = 'Name';\n};\ncolumns[0].renderer = function(root, column, model) {\n root.textContent = model.item.name;\n};\n\ncolumns[1].headerRenderer = function(root) {\n root.textContent = 'Surname';\n};\ncolumns[1].renderer = function(root, column, model) {\n root.textContent = model.item.surname;\n};\n\ncolumns[2].headerRenderer = function(root) {\n root.textContent = 'Role';\n};\ncolumns[2].renderer = function(root, column, model) {\n root.textContent = model.item.role;\n};\n```\n\nThe following properties are available in the `model` argument:\n\nProperty name | Type | Description\n--------------|------|------------\n`index`| Number | The index of the item.\n`item` | String or Object | The item.\n`level` | Number | Number of the item's tree sublevel, starts from 0.\n`expanded` | Boolean | True if the item's tree sublevel is expanded.\n`selected` | Boolean | True if the item is selected.\n`detailsOpened` | Boolean | True if the item's row details are open.\n\nThe following helper elements can be used for further customization:\n- [`<vaadin-grid-column-group>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-column-group)\n- [`<vaadin-grid-filter>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-filter)\n- [`<vaadin-grid-sorter>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-sorter)\n- [`<vaadin-grid-selection-column>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-selection-column)\n- [`<vaadin-grid-tree-toggle>`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid-tree-toggle)\n\n__Note that the helper elements must be explicitly imported.__\nIf you want to import everything at once you can use the `all-imports.html` bundle.\n\n### Lazy Loading with Function Data Provider\n\nIn addition to assigning an array to the items property, you can alternatively\nprovide the `<vaadin-grid>` data through the\n[`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid#property-dataProvider) function property.\nThe `<vaadin-grid>` calls this function lazily, only when it needs more data\nto be displayed.\n\nSee the [`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-alpha4/#/elements/vaadin-grid#property-dataProvider) property\ndocumentation for the detailed data provider arguments description.\n\n__Note that expanding the tree grid's item will trigger a call to the `dataProvider`.__\n\n__Also, note that when using function data providers, the total number of items\nneeds to be set manually. The total number of items can be returned\nin the second argument of the data provider callback:__\n\n```javascript\ngrid.dataProvider = ({page, pageSize}, callback) => {\n // page: the requested page index\n // pageSize: number of items on one page\n const url = `https://api.example/data?page=${page}&per_page=${pageSize}`;\n\n fetch(url)\n .then((res) => res.json())\n .then(({ employees, totalSize }) => {\n callback(employees, totalSize);\n });\n};\n```\n\n__Alternatively, you can use the `size` property to set the total number of items:__\n\n```javascript\ngrid.size = 200; // The total number of items\ngrid.dataProvider = ({page, pageSize}, callback) => {\n const url = `https://api.example/data?page=${page}&per_page=${pageSize}`;\n\n fetch(url)\n .then((res) => res.json())\n .then((resJson) => callback(resJson.employees));\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------------|----------------\n`row` | Row in the internal table\n`body-row` | Body row in the internal table\n`collapsed-row` | Collapsed row\n`expanded-row` | Expanded row\n`selected-row` | Selected row\n`nonselectable-row` | Row that the user may not select or deselect\n`details-opened-row` | Row with details open\n`odd-row` | Odd row\n`even-row` | Even row\n`first-row` | The first body row\n`last-row` | The last body row\n`dragstart-row` | Set on the row for one frame when drag is starting.\n`dragover-above-row` | Set on the row when the a row is dragged over above\n`dragover-below-row` | Set on the row when the a row is dragged over below\n`dragover-on-top-row` | Set on the row when the a row is dragged over on top\n`drag-disabled-row` | Set to a row that isn't available for dragging\n`drop-disabled-row` | Set to a row that can't be dropped on top of\n`cell` | Cell in the internal table\n`header-cell` | Header cell in the internal table\n`body-cell` | Body cell in the internal table\n`footer-cell` | Footer cell in the internal table\n`details-cell` | Row details cell in the internal table\n`focused-cell` | Focused cell in the internal table\n`odd-row-cell` | Cell in an odd row\n`even-row-cell` | Cell in an even row\n`first-row-cell` | Cell in the first body row\n`last-row-cell` | Cell in the last body row\n`first-header-row-cell` | Cell in the first header row\n`first-footer-row-cell` | Cell in the first footer row\n`last-header-row-cell` | Cell in the last header row\n`last-footer-row-cell` | Cell in the last footer row\n`loading-row-cell` | Cell in a row that is waiting for data from data provider\n`selected-row-cell` | Cell in a selected row\n`nonselectable-row-cell` | Cell in a row that the user may not select or deselect\n`collapsed-row-cell` | Cell in a collapsed row\n`expanded-row-cell` | Cell in an expanded row\n`details-opened-row-cell` | Cell in an row with details open\n`dragstart-row-cell` | Cell in the ghost image row, but not in a source row\n`drag-source-row-cell` | Cell in a source row, but not in the ghost image\n`dragover-above-row-cell` | Cell in a row that has another row dragged over above\n`dragover-below-row-cell` | Cell in a row that has another row dragged over below\n`dragover-on-top-row-cell` | Cell in a row that has another row dragged over on top\n`drag-disabled-row-cell` | Cell in a row that isn't available for dragging\n`drop-disabled-row-cell` | Cell in a row that can't be dropped on top of\n`frozen-cell` | Frozen cell in the internal table\n`frozen-to-end-cell` | Frozen to end cell in the internal table\n`last-frozen-cell` | Last frozen cell\n`first-frozen-to-end-cell` | First cell frozen to end\n`first-column-cell` | First visible cell on a row\n`last-column-cell` | Last visible cell on a row\n`reorder-allowed-cell` | Cell in a column where another column can be reordered\n`reorder-dragging-cell` | Cell in a column currently being reordered\n`resize-handle` | Handle for resizing the columns\n`empty-state` | The container for the content to be displayed when there are no body rows to show\n`reorder-ghost` | Ghost element of the header cell being dragged\n\nThe following state attributes are available for styling:\n\nAttribute | Description | Part name\n----------------------|---------------------------------------------------------------------------------------------------|-----------\n`loading` | Set when the grid is loading data from data provider | :host\n`interacting` | Keyboard navigation in interaction mode | :host\n`navigating` | Keyboard navigation in navigation mode | :host\n`overflow` | Set when rows are overflowing the grid viewport. Possible values: `top`, `bottom`, `start`, `end` | :host\n`reordering` | Set when the grid's columns are being reordered | :host\n`dragover` | Set when the grid (not a specific row) is dragged over | :host\n`dragging-rows` | Set when grid rows are dragged | :host\n`reorder-status` | Reflects the status of a cell while columns are being reordered | cell\n`frozen` | Frozen cell | cell\n`frozen-to-end` | Cell frozen to end | cell\n`last-frozen` | Last frozen cell | cell\n`first-frozen-to-end` | First cell frozen to end | cell\n`first-column` | First visible cell on a row | cell\n`last-column` | Last visible cell on a row | cell\n`selected` | Selected row | row\n`expanded` | Expanded row | row\n`details-opened` | Row with details open | row\n`loading` | Row that is waiting for data from data provider | row\n`odd` | Odd row | row\n`first` | The first body row | row\n`last` | The last body row | row\n`dragstart` | Set for one frame when starting to drag a row. The value is a number when dragging multiple rows | row\n`dragover` | Set when the row is dragged over | row\n`drag-disabled` | Set to a row that isn't available for dragging | row\n`drop-disabled` | Set to a row that can't be dropped on top of | row\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
832
832
  "extension": true,
833
833
  "attributes": [
834
834
  {
@@ -950,6 +950,13 @@
950
950
  "kind": "expression"
951
951
  }
952
952
  },
953
+ {
954
+ "name": ".isItemSelectable",
955
+ "description": "A function to check whether a specific item in the grid may be\nselected or deselected by the user. Used by the selection column to\nconditionally enable to disable checkboxes for individual items. This\nfunction does not prevent programmatic selection/deselection of\nitems. Changing the function does not modify the currently selected\nitems.\n\nConfiguring this function hides the select all checkbox of the grid\nselection column, which means users can not select or deselect all\nitems anymore, nor do they get feedback on whether all items are\nselected or not.\n\nReceives an item instance and should return a boolean indicating\nwhether users may change the selection state of that item.",
956
+ "value": {
957
+ "kind": "expression"
958
+ }
959
+ },
953
960
  {
954
961
  "name": ".multiSortPriority",
955
962
  "description": "Controls how columns are added to the sort order when using multi-sort.\nThe sort order is visually indicated by numbers in grid sorters placed in column headers.\n\nBy default, whenever an unsorted column is sorted, or the sort-direction of a column is\nchanged, that column gets sort priority 1, thus affecting the priority for all the other\nsorted columns. This is identical to using `multi-sort-priority=\"prepend\"`.\n\nUsing this property allows to change this behavior so that sorting an unsorted column\nwould add it to the \"end\" of the sort, and changing column's sort direction would retain\nit's previous priority. To set this, use `multi-sort-priority=\"append\"`.",