@vaadin/grid 25.1.0-beta1 → 25.1.0-beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,7 +39,6 @@ export const ColumnBaseMixin = (superClass) =>
39
39
  /**
40
40
  * When true, the column is frozen. When a column inside of a column group is frozen,
41
41
  * all of the sibling columns inside the group will get frozen also.
42
- * @type {boolean}
43
42
  */
44
43
  frozen: {
45
44
  type: Boolean,
@@ -55,7 +54,6 @@ export const ColumnBaseMixin = (superClass) =>
55
54
  *
56
55
  * Column can not be set as `frozen` and `frozenToEnd` at the same time.
57
56
  * @attr {boolean} frozen-to-end
58
- * @type {boolean}
59
57
  */
60
58
  frozenToEnd: {
61
59
  type: Boolean,
@@ -71,7 +69,6 @@ export const ColumnBaseMixin = (superClass) =>
71
69
  * while navigating to help user identify the current row as uniquely as possible.
72
70
  *
73
71
  * @attr {boolean} row-header
74
- * @type {boolean}
75
72
  */
76
73
  rowHeader: {
77
74
  type: Boolean,
@@ -100,7 +97,6 @@ export const ColumnBaseMixin = (superClass) =>
100
97
  * Aligns the columns cell content horizontally.
101
98
  * Supported values: "start", "center" and "end".
102
99
  * @attr {start|center|end} text-align
103
- * @type {GridColumnTextAlign | null | undefined}
104
100
  */
105
101
  textAlign: {
106
102
  type: String,
@@ -128,7 +124,6 @@ export const ColumnBaseMixin = (superClass) =>
128
124
  },
129
125
 
130
126
  /**
131
- * @type {boolean}
132
127
  * @protected
133
128
  */
134
129
  _lastFrozen: {
@@ -138,7 +133,6 @@ export const ColumnBaseMixin = (superClass) =>
138
133
  },
139
134
 
140
135
  /**
141
- * @type {boolean}
142
136
  * @protected
143
137
  */
144
138
  _bodyContentHidden: {
@@ -148,7 +142,6 @@ export const ColumnBaseMixin = (superClass) =>
148
142
  },
149
143
 
150
144
  /**
151
- * @type {boolean}
152
145
  * @protected
153
146
  */
154
147
  _firstFrozenToEnd: {
@@ -275,7 +268,6 @@ export const ColumnBaseMixin = (superClass) =>
275
268
  '_frozenToEndChanged(frozenToEnd, _headerCell, _footerCell, _cells)',
276
269
  '_flexGrowChanged(flexGrow, _headerCell, _footerCell, _cells)',
277
270
  '_textAlignChanged(textAlign, _cells, _headerCell, _footerCell)',
278
- '_orderChanged(_order, _headerCell, _footerCell, _cells)',
279
271
  '_lastFrozenChanged(_lastFrozen)',
280
272
  '_firstFrozenToEndChanged(_firstFrozenToEnd)',
281
273
  '_onRendererOrBindingChanged(_renderer, _cells, _bodyContentHidden, path)',
@@ -384,13 +376,6 @@ export const ColumnBaseMixin = (superClass) =>
384
376
  });
385
377
  }
386
378
 
387
- /** @private */
388
- _orderChanged(order) {
389
- this._allCells.forEach((cell) => {
390
- cell.style.order = order;
391
- });
392
- }
393
-
394
379
  /** @private */
395
380
  _widthChanged(width) {
396
381
  if (this.parentElement && this.parentElement._columnPropChanged) {
@@ -847,7 +832,6 @@ export const GridColumnMixin = (superClass) =>
847
832
  /**
848
833
  * Flex grow ratio for the cell widths. When set to 0, cell width is fixed.
849
834
  * @attr {number} flex-grow
850
- * @type {number}
851
835
  */
852
836
  flexGrow: {
853
837
  type: Number,
@@ -914,7 +898,6 @@ export const GridColumnMixin = (superClass) =>
914
898
  *
915
899
  * The column width may still grow larger when `flexGrow` is not 0.
916
900
  * @attr {boolean} auto-width
917
- * @type {boolean}
918
901
  */
919
902
  autoWidth: {
920
903
  type: Boolean,
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { isTouch } from '@vaadin/component-base/src/browser-utils.js';
7
7
  import { addListener } from '@vaadin/component-base/src/gestures.js';
8
- import { iterateChildren, updateColumnOrders } from './vaadin-grid-helpers.js';
8
+ import { getBodyRowCells, iterateChildren, updateColumnOrders } from './vaadin-grid-helpers.js';
9
9
 
10
10
  /**
11
11
  * @polymerMixin
@@ -17,7 +17,6 @@ export const ColumnReorderingMixin = (superClass) =>
17
17
  /**
18
18
  * Set to true to allow column reordering.
19
19
  * @attr {boolean} column-reordering-allowed
20
- * @type {boolean}
21
20
  */
22
21
  columnReorderingAllowed: {
23
22
  type: Boolean,
@@ -63,8 +62,24 @@ export const ColumnReorderingMixin = (superClass) =>
63
62
  }
64
63
  }
65
64
 
65
+ /** @private */
66
+ _cancelReorderForMultiTouch(e) {
67
+ if (e.touches.length > 1) {
68
+ clearTimeout(this._startTouchReorderTimeout);
69
+ if (this._draggedColumn) {
70
+ this._onTrackEnd();
71
+ }
72
+ return true;
73
+ }
74
+ return false;
75
+ }
76
+
66
77
  /** @private */
67
78
  _onTouchStart(e) {
79
+ if (this._cancelReorderForMultiTouch(e)) {
80
+ return;
81
+ }
82
+
68
83
  // Touch event, delay activation by 100ms
69
84
  this._startTouchReorderTimeout = setTimeout(() => {
70
85
  this._onTrackStart({
@@ -78,6 +93,10 @@ export const ColumnReorderingMixin = (superClass) =>
78
93
 
79
94
  /** @private */
80
95
  _onTouchMove(e) {
96
+ if (this._cancelReorderForMultiTouch(e)) {
97
+ return;
98
+ }
99
+
81
100
  if (this._draggedColumn) {
82
101
  e.preventDefault();
83
102
  }
@@ -388,12 +407,28 @@ export const ColumnReorderingMixin = (superClass) =>
388
407
  }
389
408
 
390
409
  /**
410
+ * Swaps column orders and physically reorders cells in all rows.
391
411
  * @param {!GridColumn} column1
392
412
  * @param {!GridColumn} column2
393
413
  * @protected
394
414
  */
395
415
  _swapColumnOrders(column1, column2) {
416
+ // Swap order values and determine which column should come first
396
417
  [column1._order, column2._order] = [column2._order, column1._order];
418
+ const [firstColumn, secondColumn] = column1._order < column2._order ? [column1, column2] : [column2, column1];
419
+
420
+ // Reorder cells in all rows (header, footer, body, sizer)
421
+ [...this.$.header.children, ...this.$.footer.children, ...this.$.items.children, this.$.sizer].forEach((row) => {
422
+ const cells = getBodyRowCells(row);
423
+ const firstColumnCells = cells.filter((cell) => firstColumn.contains(cell._column));
424
+ const secondColumnFirstCell = cells.find((cell) => secondColumn.contains(cell._column));
425
+ firstColumnCells.forEach((cell) => secondColumnFirstCell.before(cell));
426
+ // row.__cells are out of sync with the actual cell order after the move, and must be updated
427
+ if (row.__cells) {
428
+ row.__cells = row.__cells.toSorted((a, b) => a._column._order - b._column._order);
429
+ }
430
+ });
431
+
397
432
  this._debounceUpdateFrozenColumn();
398
433
  this._updateFirstAndLastColumn();
399
434
  }
@@ -16,8 +16,23 @@ export const ColumnResizingMixin = (superClass) =>
16
16
  const scroller = this.$.scroller;
17
17
  addListener(scroller, 'track', this._onHeaderTrack.bind(this));
18
18
 
19
- // Disallow scrolling while resizing
20
- scroller.addEventListener('touchmove', (e) => scroller.hasAttribute('column-resizing') && e.preventDefault());
19
+ // Cancel resizing on multi-touch (e.g. pinch-zoom)
20
+ scroller.addEventListener('touchstart', (e) => {
21
+ if (e.touches.length > 1) {
22
+ scroller.removeAttribute('column-resizing');
23
+ }
24
+ });
25
+
26
+ // Disallow scrolling while resizing, but allow multi-touch gestures
27
+ scroller.addEventListener('touchmove', (e) => {
28
+ if (e.touches.length > 1) {
29
+ scroller.removeAttribute('column-resizing');
30
+ return;
31
+ }
32
+ if (scroller.hasAttribute('column-resizing')) {
33
+ e.preventDefault();
34
+ }
35
+ });
21
36
 
22
37
  // Disable contextmenu on any resize separator.
23
38
  scroller.addEventListener('contextmenu', (e) => e.target.part.contains('resize-handle') && e.preventDefault());
@@ -30,6 +45,11 @@ export const ColumnResizingMixin = (superClass) =>
30
45
  _onHeaderTrack(e) {
31
46
  const handle = e.target;
32
47
  if (handle.part.contains('resize-handle')) {
48
+ // Ignore track events after multi-touch cancelled resizing
49
+ if (e.detail.state !== 'start' && !this.$.scroller.hasAttribute('column-resizing')) {
50
+ return;
51
+ }
52
+
33
53
  const cell = handle.parentElement;
34
54
  let column = cell._column;
35
55
 
@@ -76,14 +96,10 @@ export const ColumnResizingMixin = (superClass) =>
76
96
  column.flexGrow = 0;
77
97
  }
78
98
  // Fix width and flex-grow for all preceding columns
79
- columnRowCells
80
- .sort((a, b) => a._column._order - b._column._order)
81
- .forEach((cell, index, array) => {
82
- if (index < array.indexOf(targetCell)) {
83
- cell._column.width = `${cell.offsetWidth}px`;
84
- cell._column.flexGrow = 0;
85
- }
86
- });
99
+ columnRowCells.slice(0, columnRowCells.indexOf(targetCell)).forEach((cell) => {
100
+ cell._column.width = `${cell.offsetWidth}px`;
101
+ cell._column.flexGrow = 0;
102
+ });
87
103
 
88
104
  const cellFrozenToEnd = this._frozenToEndCells[0];
89
105
 
@@ -18,7 +18,6 @@ export const DataProviderMixin = (superClass) =>
18
18
  /**
19
19
  * The number of root-level items in the grid.
20
20
  * @attr {number} size
21
- * @type {number}
22
21
  */
23
22
  size: {
24
23
  type: Number,
@@ -38,7 +37,6 @@ export const DataProviderMixin = (superClass) =>
38
37
  /**
39
38
  * Number of items fetched at a time from the dataprovider.
40
39
  * @attr {number} page-size
41
- * @type {number}
42
40
  */
43
41
  pageSize: {
44
42
  type: Number,
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { isChrome, isSafari } from '@vaadin/component-base/src/browser-utils.js';
7
7
  import {
8
+ getBodyRowCells,
8
9
  iterateChildren,
9
10
  iterateRowCells,
10
11
  updateBooleanRowStates,
@@ -41,7 +42,6 @@ export const DragAndDropMixin = (superClass) =>
41
42
  * - `on-top-or-between`: The drop event can happen either on top of or between Grid rows.
42
43
  * - `on-grid`: The drop event will not happen on any specific row, it will show the drop target outline around the whole grid.
43
44
  * @attr {between|on-top|on-top-or-between|on-grid} drop-mode
44
- * @type {GridDropMode | null | undefined}
45
45
  */
46
46
  dropMode: {
47
47
  type: String,
@@ -446,11 +446,8 @@ export const DragAndDropMixin = (superClass) =>
446
446
  __formatDefaultTransferData(rows) {
447
447
  return rows
448
448
  .map((row) => {
449
- return Array.from(row.children)
450
- .filter((cell) => !cell.hidden && !cell.part.contains('details-cell'))
451
- .sort((a, b) => {
452
- return a._column._order > b._column._order ? 1 : -1;
453
- })
449
+ return getBodyRowCells(row)
450
+ .filter((cell) => !cell.hidden)
454
451
  .map((cell) => cell._content.textContent.trim())
455
452
  .filter((content) => content)
456
453
  .join('\t');
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { microTask, timeOut } from '@vaadin/component-base/src/async.js';
7
7
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
8
- import { ColumnObserver, updateCellState } from './vaadin-grid-helpers.js';
8
+ import { ColumnObserver, getBodyRowCells, updateCellState } from './vaadin-grid-helpers.js';
9
9
 
10
10
  function arrayEquals(arr1, arr2) {
11
11
  if (!arr1 || !arr2 || arr1.length !== arr2.length) {
@@ -156,14 +156,10 @@ export const DynamicColumnsMixin = (superClass) =>
156
156
  * @protected
157
157
  */
158
158
  _updateFirstAndLastColumnForRow(row) {
159
- Array.from(row.querySelectorAll('[part~="cell"]:not([part~="details-cell"])'))
160
- .sort((a, b) => {
161
- return a._column._order - b._column._order;
162
- })
163
- .forEach((cell, cellIndex, children) => {
164
- updateCellState(cell, 'first-column', cellIndex === 0);
165
- updateCellState(cell, 'last-column', cellIndex === children.length - 1);
166
- });
159
+ getBodyRowCells(row).forEach((cell, cellIndex, cells) => {
160
+ updateCellState(cell, 'first-column', cellIndex === 0);
161
+ updateCellState(cell, 'last-column', cellIndex === cells.length - 1);
162
+ });
167
163
  }
168
164
 
169
165
  /**
@@ -82,7 +82,6 @@ export const KeyboardNavigationMixin = (superClass) =>
82
82
  * the grid from receiving focus, allowing the user to switch focus to
83
83
  * controls in adjacent cells, rather than focussing the outer cell
84
84
  * itself.
85
- * @type {boolean}
86
85
  * @private
87
86
  */
88
87
  interacting: {
@@ -391,15 +390,13 @@ export const KeyboardNavigationMixin = (superClass) =>
391
390
  this.collapseItem(activeRow._item);
392
391
  return;
393
392
  }
394
- } else {
393
+ } else if (activeCell === activeRow.firstElementChild || isDetailsCell(activeCell)) {
395
394
  // In cell focus mode
396
- const activeRowCells = [...activeRow.children].sort((a, b) => a._order - b._order);
397
- if (activeCell === activeRowCells[0] || isDetailsCell(activeCell)) {
398
- // "If focus is on the first cell in a row and row focus is supported, moves focus to the row."
399
- this.__rowFocusMode = true;
400
- this._onRowNavigation(activeRow, 0);
401
- return;
402
- }
395
+
396
+ // "If focus is on the first cell in a row and row focus is supported, moves focus to the row."
397
+ this.__rowFocusMode = true;
398
+ this._onRowNavigation(activeRow, 0);
399
+ return;
403
400
  }
404
401
  }
405
402
 
@@ -524,15 +521,8 @@ export const KeyboardNavigationMixin = (superClass) =>
524
521
  return;
525
522
  }
526
523
 
527
- let columnIndex = [...activeRow.children].indexOf(activeCell);
528
- if (this.$.items.contains(activeCell)) {
529
- // lazy column rendering may be enabled, so we need use the always visible sizer cells to find the column index
530
- columnIndex = [...this.$.sizer.children].findIndex((sizerCell) => sizerCell._column === activeCell._column);
531
- }
532
-
533
524
  const isCurrentCellRowDetails = isDetailsCell(activeCell);
534
525
  const activeRowGroup = activeRow.parentNode;
535
- const currentRowIndex = this.__getIndexInGroup(activeRow, this._focusedItemIndex);
536
526
 
537
527
  // _focusedColumnOrder is memoized - this is to ensure predictable
538
528
  // navigation when entering and leaving detail and column group cells.
@@ -540,9 +530,9 @@ export const KeyboardNavigationMixin = (superClass) =>
540
530
  if (isCurrentCellRowDetails) {
541
531
  this._focusedColumnOrder = 0;
542
532
  } else {
543
- this._focusedColumnOrder = this._getColumns(activeRowGroup, currentRowIndex).filter((c) => !c.hidden)[
544
- columnIndex
545
- ]._order;
533
+ // Use the cell's column order directly instead of indexing into _getColumns,
534
+ // since cells may be physically reordered and DOM order doesn't match _columnTree order
535
+ this._focusedColumnOrder = activeCell._column._order;
546
536
  }
547
537
  }
548
538
 
@@ -577,15 +567,12 @@ export const KeyboardNavigationMixin = (superClass) =>
577
567
  this._focusedColumnOrder = undefined;
578
568
  }
579
569
 
580
- const columnIndexByOrder = dstColumns.reduce((acc, col, i) => {
581
- acc[col._order] = i;
582
- return acc;
583
- }, {});
584
- const dstColumnIndex = columnIndexByOrder[dstSortedColumnOrders[dstOrderedColumnIndex]];
570
+ // Get the target column from the sorted column orders
571
+ const dstColumn = dstColumns.find((col) => col._order === dstSortedColumnOrders[dstOrderedColumnIndex]);
585
572
 
586
573
  let dstCell;
587
574
  if (this.$.items.contains(activeCell)) {
588
- const dstSizerCell = this.$.sizer.children[dstColumnIndex];
575
+ const dstSizerCell = [...this.$.sizer.children].find((cell) => cell._column === dstColumn);
589
576
  if (this._lazyColumns) {
590
577
  // If the column is not in the viewport, scroll it into view.
591
578
  if (!this.__isColumnInViewport(dstSizerCell._column)) {
@@ -599,7 +586,8 @@ export const KeyboardNavigationMixin = (superClass) =>
599
586
  // Ensure correct horizontal scroll position once the destination cell is available.
600
587
  this._scrollHorizontallyToCell(dstCell);
601
588
  } else {
602
- dstCell = dstRow.children[dstColumnIndex];
589
+ // For header/footer, find the cell whose column contains the target column
590
+ dstCell = [...dstRow.children].find((cell) => cell._column.contains(dstColumn));
603
591
  this._scrollHorizontallyToCell(dstCell);
604
592
  }
605
593
 
@@ -8,6 +8,7 @@ import { animationFrame, microTask } from '@vaadin/component-base/src/async.js';
8
8
  import { isAndroid, isChrome, isFirefox, isIOS, isSafari, isTouch } from '@vaadin/component-base/src/browser-utils.js';
9
9
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
10
10
  import { getClosestElement } from '@vaadin/component-base/src/dom-utils.js';
11
+ import { setTouchAction } from '@vaadin/component-base/src/gestures.js';
11
12
  import { SlotObserver } from '@vaadin/component-base/src/slot-observer.js';
12
13
  import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
13
14
  import { Virtualizer } from '@vaadin/component-base/src/virtualizer.js';
@@ -133,7 +134,6 @@ export const GridMixin = (superClass) =>
133
134
  * Effectively, this disables the grid's virtual scrolling so that all the rows are rendered in the DOM at once.
134
135
  * If the grid has a large number of items, using the feature is discouraged to avoid performance issues.
135
136
  * @attr {boolean} all-rows-visible
136
- * @type {boolean}
137
137
  */
138
138
  allRowsVisible: {
139
139
  type: Boolean,
@@ -248,6 +248,9 @@ export const GridMixin = (superClass) =>
248
248
  ready() {
249
249
  super.ready();
250
250
 
251
+ setTouchAction(this, '');
252
+ setTouchAction(this.$.scroller, '');
253
+
251
254
  this.__virtualizer = new Virtualizer({
252
255
  createElements: this._createScrollerRows.bind(this),
253
256
  updateElement: this._updateScrollerItem.bind(this),
@@ -488,6 +491,7 @@ export const GridMixin = (superClass) =>
488
491
 
489
492
  columns
490
493
  .filter((column) => !column.hidden)
494
+ .toSorted((a, b) => a._order - b._order)
491
495
  .forEach((column, index, cols) => {
492
496
  let cell;
493
497
 
@@ -55,7 +55,6 @@ export const ScrollMixin = (superClass) =>
55
55
  * and thus not rendered.
56
56
  *
57
57
  * @attr {eager|lazy} column-rendering
58
- * @type {!ColumnRendering}
59
58
  */
60
59
  columnRendering: {
61
60
  type: String,
@@ -207,6 +206,8 @@ export const ScrollMixin = (superClass) =>
207
206
  }
208
207
 
209
208
  this._scrollHorizontallyToCell(column._headerCell);
209
+ // Update cell position synchronously
210
+ this.__updateHorizontalScrollPosition();
210
211
  // Synchronously update cells when using lazy column rendering
211
212
  this.__updateColumnsBodyContentHidden();
212
213
  }
@@ -3,7 +3,7 @@
3
3
  * Copyright (c) 2016 - 2026 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { addListener } from '@vaadin/component-base/src/gestures.js';
6
+ import { addListener, setTouchAction } from '@vaadin/component-base/src/gestures.js';
7
7
 
8
8
  /**
9
9
  * A mixin that provides basic functionality for the
@@ -42,7 +42,6 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
42
42
  /**
43
43
  * Flex grow ratio for the cell widths. When set to 0, cell width is fixed.
44
44
  * @attr {number} flex-grow
45
- * @type {number}
46
45
  */
47
46
  flexGrow: {
48
47
  type: Number,
@@ -53,7 +52,6 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
53
52
  /**
54
53
  * When true, all the items are selected.
55
54
  * @attr {boolean} select-all
56
- * @type {boolean}
57
55
  */
58
56
  selectAll: {
59
57
  type: Boolean,
@@ -65,7 +63,6 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
65
63
  /**
66
64
  * When true, the active item gets automatically selected.
67
65
  * @attr {boolean} auto-select
68
- * @type {boolean}
69
66
  */
70
67
  autoSelect: {
71
68
  type: Boolean,
@@ -76,7 +73,6 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
76
73
  /**
77
74
  * When true, rows can be selected by dragging over the selection column.
78
75
  * @attr {boolean} drag-select
79
- * @type {boolean}
80
76
  */
81
77
  dragSelect: {
82
78
  type: Boolean,
@@ -118,6 +114,7 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
118
114
  this.__onCellMouseDown = this.__onCellMouseDown.bind(this);
119
115
  this.__onGridInteraction = this.__onGridInteraction.bind(this);
120
116
  this.__onActiveItemChanged = this.__onActiveItemChanged.bind(this);
117
+ this.__onTouchStart = this.__onTouchStart.bind(this);
121
118
  this.__onSelectRowCheckboxChange = this.__onSelectRowCheckboxChange.bind(this);
122
119
  this.__onSelectAllCheckboxChange = this.__onSelectAllCheckboxChange.bind(this);
123
120
  }
@@ -130,6 +127,7 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
130
127
  this._grid.addEventListener('keydown', this.__onGridInteraction, { capture: true });
131
128
  this._grid.addEventListener('mousedown', this.__onGridInteraction);
132
129
  this._grid.addEventListener('active-item-changed', this.__onActiveItemChanged);
130
+ this._grid.addEventListener('touchstart', this.__onTouchStart);
133
131
  }
134
132
  }
135
133
 
@@ -141,6 +139,7 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
141
139
  this._grid.removeEventListener('keydown', this.__onGridInteraction, { capture: true });
142
140
  this._grid.removeEventListener('mousedown', this.__onGridInteraction);
143
141
  this._grid.removeEventListener('active-item-changed', this.__onActiveItemChanged);
142
+ this._grid.removeEventListener('touchstart', this.__onTouchStart);
144
143
  }
145
144
  }
146
145
 
@@ -178,6 +177,7 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
178
177
  checkbox.addEventListener('change', this.__onSelectRowCheckboxChange);
179
178
  root.appendChild(checkbox);
180
179
  addListener(root, 'track', this.__onCellTrack);
180
+ setTouchAction(root, 'pinch-zoom');
181
181
  root.addEventListener('mousedown', this.__onCellMouseDown);
182
182
  root.addEventListener('click', this.__onCellClick);
183
183
  }
@@ -234,6 +234,10 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
234
234
  this.__dragCurrentY = event.detail.y;
235
235
  this.__dragDy = event.detail.dy;
236
236
  if (event.detail.state === 'start') {
237
+ // Don't start drag-select during multi-touch (e.g. pinch-zoom)
238
+ if (this.__multiTouchActive) {
239
+ return;
240
+ }
237
241
  const renderedRows = this._grid._getRenderedRows();
238
242
  // Get the row where the drag started
239
243
  const dragStartRow = renderedRows.find((row) => row.contains(event.currentTarget.assignedSlot));
@@ -266,6 +270,18 @@ export const GridSelectionColumnBaseMixin = (superClass) =>
266
270
  }
267
271
  }
268
272
 
273
+ /** @private */
274
+ __onTouchStart(e) {
275
+ if (e.touches.length > 1) {
276
+ this.__multiTouchActive = true;
277
+ // Cancel in-progress drag-select on multi-touch (e.g. pinch-zoom)
278
+ this.__dragStartIndex = undefined;
279
+ this.__dragStartItem = undefined;
280
+ } else {
281
+ this.__multiTouchActive = false;
282
+ }
283
+ }
284
+
269
285
  /** @private */
270
286
  __onCellClick(e) {
271
287
  if (this.__dragStartIndex !== undefined) {
@@ -23,7 +23,6 @@ export const GridSortColumnMixin = (superClass) =>
23
23
  * How to sort the data.
24
24
  * Possible values are `asc` to use an ascending algorithm, `desc` to sort the data in
25
25
  * descending direction, or `null` for not sorting the data.
26
- * @type {GridSorterDirection | undefined}
27
26
  */
28
27
  direction: {
29
28
  type: String,
@@ -16,7 +16,6 @@ export const SortMixin = (superClass) =>
16
16
  /**
17
17
  * When `true`, all `<vaadin-grid-sorter>` are applied for sorting.
18
18
  * @attr {boolean} multi-sort
19
- * @type {boolean}
20
19
  */
21
20
  multiSort: {
22
21
  type: Boolean,
@@ -48,7 +47,6 @@ export const SortMixin = (superClass) =>
48
47
  * `multiSort` property. If `multiSortOnShiftClick` is true, the multiSort property is effectively ignored.
49
48
  *
50
49
  * @attr {boolean} multi-sort-on-shift-click
51
- * @type {boolean}
52
50
  */
53
51
  multiSortOnShiftClick: {
54
52
  type: Boolean,
@@ -16,13 +16,14 @@ export const GridSorterMixin = (superClass) =>
16
16
  /**
17
17
  * JS Path of the property in the item used for sorting the data.
18
18
  */
19
- path: String,
19
+ path: {
20
+ type: String,
21
+ },
20
22
 
21
23
  /**
22
24
  * How to sort the data.
23
25
  * Possible values are `asc` to use an ascending algorithm, `desc` to sort the data in
24
26
  * descending direction, or `null` for not sorting the data.
25
- * @type {GridSorterDirection | undefined}
26
27
  */
27
28
  direction: {
28
29
  type: String,
@@ -15,7 +15,6 @@ export const GridTreeToggleMixin = (superClass) =>
15
15
  /**
16
16
  * Current level of the tree represented with a horizontal offset
17
17
  * of the toggle button.
18
- * @type {number}
19
18
  */
20
19
  level: {
21
20
  type: Number,
@@ -26,7 +25,6 @@ export const GridTreeToggleMixin = (superClass) =>
26
25
 
27
26
  /**
28
27
  * Hides the toggle icon and disables toggling a tree sublevel.
29
- * @type {boolean}
30
28
  */
31
29
  leaf: {
32
30
  type: Boolean,
@@ -36,7 +34,6 @@ export const GridTreeToggleMixin = (superClass) =>
36
34
 
37
35
  /**
38
36
  * Sublevel toggle state.
39
- * @type {boolean}
40
37
  */
41
38
  expanded: {
42
39
  type: Boolean,