@vaadin/grid 24.2.0-dev.f254716fe → 24.2.0

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.
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
7
7
  import { addValueToAttribute, removeValueFromAttribute } from '@vaadin/component-base/src/dom-utils.js';
8
+ import { get } from '@vaadin/component-base/src/path-utils.js';
8
9
 
9
10
  /**
10
11
  * @polymerMixin
@@ -266,7 +267,7 @@ export const KeyboardNavigationMixin = (superClass) =>
266
267
  __isRowExpandable(row) {
267
268
  if (this.itemHasChildrenPath) {
268
269
  const item = row._item;
269
- return item && this.get(this.itemHasChildrenPath, item) && !this._isExpanded(item);
270
+ return item && get(this.itemHasChildrenPath, item) && !this._isExpanded(item);
270
271
  }
271
272
  }
272
273
 
@@ -475,7 +476,7 @@ export const KeyboardNavigationMixin = (superClass) =>
475
476
  // Row details navigation logic
476
477
  if (activeRowGroup === this.$.items) {
477
478
  const item = activeRow._item;
478
- const { item: dstItem } = this._dataProviderController.getFlatIndexInfo(dstRowIndex);
479
+ const dstItem = this._cache.getItemForIndex(dstRowIndex);
479
480
  // Should we navigate to row details?
480
481
  if (isRowDetails) {
481
482
  dstIsRowDetails = dy === 0;
@@ -681,7 +682,26 @@ export const KeyboardNavigationMixin = (superClass) =>
681
682
  }
682
683
  }
683
684
 
684
- return tabOrder[index];
685
+ let focusStepTarget = tabOrder[index];
686
+
687
+ // If the target focusable is tied to a column that is not visible,
688
+ // find the first visible column and update the target in order to
689
+ // prevent scrolling to the start of the row.
690
+ if (focusStepTarget && focusStepTarget._column && !this.__isColumnInViewport(focusStepTarget._column)) {
691
+ const firstVisibleColumn = this._getColumnsInOrder().find((column) => this.__isColumnInViewport(column));
692
+ if (firstVisibleColumn) {
693
+ if (focusStepTarget === this._headerFocusable) {
694
+ focusStepTarget = firstVisibleColumn._headerCell;
695
+ } else if (focusStepTarget === this._itemsFocusable) {
696
+ const rowIndex = focusStepTarget._column._cells.indexOf(focusStepTarget);
697
+ focusStepTarget = firstVisibleColumn._cells[rowIndex];
698
+ } else if (focusStepTarget === this._footerFocusable) {
699
+ focusStepTarget = firstVisibleColumn._footerCell;
700
+ }
701
+ }
702
+ }
703
+
704
+ return focusStepTarget;
685
705
  }
686
706
 
687
707
  /** @private */
@@ -822,9 +842,12 @@ export const KeyboardNavigationMixin = (superClass) =>
822
842
  }
823
843
 
824
844
  if (cell) {
825
- // Fire a public event for cell.
826
845
  const context = this.getEventContext(e);
827
- cell.dispatchEvent(new CustomEvent('cell-focus', { bubbles: true, composed: true, detail: { context } }));
846
+ this.__pendingBodyCellFocus = this.loading && context.section === 'body';
847
+ if (!this.__pendingBodyCellFocus) {
848
+ // Fire a cell-focus event for the cell
849
+ cell.dispatchEvent(new CustomEvent('cell-focus', { bubbles: true, composed: true, detail: { context } }));
850
+ }
828
851
  this._focusedCell = cell._focusButton || cell;
829
852
 
830
853
  if (isKeyboardActive() && e.target === cell) {
@@ -838,6 +861,16 @@ export const KeyboardNavigationMixin = (superClass) =>
838
861
  this._detectFocusedItemIndex(e);
839
862
  }
840
863
 
864
+ /**
865
+ * @private
866
+ */
867
+ __dispatchPendingBodyCellFocus() {
868
+ // If the body cell focus was pending, dispatch the event once loading is done
869
+ if (this.__pendingBodyCellFocus && this.shadowRoot.activeElement === this._itemsFocusable) {
870
+ this._itemsFocusable.dispatchEvent(new Event('focusin', { bubbles: true, composed: true }));
871
+ }
872
+ }
873
+
841
874
  /**
842
875
  * Get the focusable element depending on the current focus mode.
843
876
  * It can be a row, a cell, or a focusable div inside a cell.
@@ -0,0 +1,218 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { DisabledMixinClass } from '@vaadin/a11y-base/src/disabled-mixin.js';
8
+ import type { ActiveItemMixinClass } from './vaadin-grid-active-item-mixin.js';
9
+ import type { ArrayDataProviderMixinClass } from './vaadin-grid-array-data-provider-mixin.js';
10
+ import type { GridColumn } from './vaadin-grid-column.js';
11
+ import { GridBodyRenderer, GridHeaderFooterRenderer } from './vaadin-grid-column.js';
12
+ import type { ColumnReorderingMixinClass } from './vaadin-grid-column-reordering-mixin.js';
13
+ import type { DataProviderMixinClass } from './vaadin-grid-data-provider-mixin.js';
14
+ import {
15
+ GridDataProvider,
16
+ GridDataProviderCallback,
17
+ GridDataProviderParams,
18
+ GridFilterDefinition,
19
+ GridSorterDefinition,
20
+ GridSorterDirection,
21
+ } from './vaadin-grid-data-provider-mixin.js';
22
+ import type { DragAndDropMixinClass } from './vaadin-grid-drag-and-drop-mixin.js';
23
+ import { GridDragAndDropFilter, GridDropLocation, GridDropMode } from './vaadin-grid-drag-and-drop-mixin.js';
24
+ import type { EventContextMixinClass } from './vaadin-grid-event-context-mixin.js';
25
+ import { GridEventContext } from './vaadin-grid-event-context-mixin.js';
26
+ import type { RowDetailsMixinClass } from './vaadin-grid-row-details-mixin.js';
27
+ import { GridRowDetailsRenderer } from './vaadin-grid-row-details-mixin.js';
28
+ import type { ScrollMixinClass } from './vaadin-grid-scroll-mixin.js';
29
+ import type { SelectionMixinClass } from './vaadin-grid-selection-mixin.js';
30
+ import type { SortMixinClass } from './vaadin-grid-sort-mixin.js';
31
+ import type {
32
+ GridCellClassNameGenerator,
33
+ GridCellPartNameGenerator,
34
+ StylingMixinClass,
35
+ } from './vaadin-grid-styling-mixin.js';
36
+
37
+ export {
38
+ GridBodyRenderer,
39
+ GridCellClassNameGenerator,
40
+ GridCellPartNameGenerator,
41
+ GridDataProvider,
42
+ GridDataProviderCallback,
43
+ GridDataProviderParams,
44
+ GridDragAndDropFilter,
45
+ GridDropLocation,
46
+ GridDropMode,
47
+ GridEventContext,
48
+ GridFilterDefinition,
49
+ GridHeaderFooterRenderer,
50
+ GridRowDetailsRenderer,
51
+ GridSorterDefinition,
52
+ GridSorterDirection,
53
+ };
54
+
55
+ export interface GridItemModel<TItem> {
56
+ index: number;
57
+ item: TItem;
58
+ selected?: boolean;
59
+ expanded?: boolean;
60
+ level?: number;
61
+ detailsOpened?: boolean;
62
+ }
63
+
64
+ /**
65
+ * Fired when the `activeItem` property changes.
66
+ */
67
+ export type GridActiveItemChangedEvent<TItem> = CustomEvent<{ value: TItem | null | undefined }>;
68
+
69
+ /**
70
+ * Fired when the cell is activated with click or keyboard.
71
+ */
72
+ export type GridCellActivateEvent<TItem> = CustomEvent<{ model: GridItemModel<TItem> }>;
73
+
74
+ /**
75
+ * Fired when a cell is focused with click or keyboard navigation.
76
+ */
77
+ export type GridCellFocusEvent<TItem> = CustomEvent<{ context: GridEventContext<TItem> }>;
78
+
79
+ /**
80
+ * Fired when the columns in the grid are reordered.
81
+ */
82
+ export type GridColumnReorderEvent<TItem> = CustomEvent<{ columns: Array<GridColumn<TItem>> }>;
83
+
84
+ /**
85
+ * Fired when the grid column resize is finished.
86
+ */
87
+ export type GridColumnResizeEvent<TItem> = CustomEvent<{ resizedColumn: GridColumn<TItem> }>;
88
+
89
+ /**
90
+ * Fired when the `dataProvider` property changes.
91
+ */
92
+ export type GridDataProviderChangedEvent<TItem> = CustomEvent<{ value: GridDataProvider<TItem> }>;
93
+
94
+ /**
95
+ * Fired when the `expandedItems` property changes.
96
+ */
97
+ export type GridExpandedItemsChangedEvent<TItem> = CustomEvent<{ value: TItem[] }>;
98
+
99
+ /**
100
+ * Fired when starting to drag grid rows.
101
+ */
102
+ export type GridDragStartEvent<TItem> = CustomEvent<{
103
+ draggedItems: TItem[];
104
+ setDraggedItemsCount(count: number): void;
105
+ setDragData(type: string, data: string): void;
106
+ }>;
107
+
108
+ /**
109
+ * Fired when a drop occurs on top of the grid.
110
+ */
111
+ export type GridDropEvent<TItem> = CustomEvent<{
112
+ dropTargetItem: TItem;
113
+ dropLocation: GridDropLocation;
114
+ dragData: Array<{ type: string; data: string }>;
115
+ }>;
116
+
117
+ /**
118
+ * Fired when the `loading` property changes.
119
+ */
120
+ export type GridLoadingChangedEvent = CustomEvent<{ value: boolean }>;
121
+
122
+ /**
123
+ * Fired when the `selectedItems` property changes.
124
+ */
125
+ export type GridSelectedItemsChangedEvent<TItem> = CustomEvent<{ value: TItem[] }>;
126
+
127
+ /**
128
+ * Fired when the `size` property changes.
129
+ */
130
+ export type GridSizeChangedEvent = CustomEvent<{ value: number }>;
131
+
132
+ export interface GridCustomEventMap<TItem> {
133
+ 'active-item-changed': GridActiveItemChangedEvent<TItem>;
134
+
135
+ 'cell-activate': GridCellActivateEvent<TItem>;
136
+
137
+ 'cell-focus': GridCellFocusEvent<TItem>;
138
+
139
+ 'column-reorder': GridColumnReorderEvent<TItem>;
140
+
141
+ 'column-resize': GridColumnResizeEvent<TItem>;
142
+
143
+ 'data-provider-changed': GridDataProviderChangedEvent<TItem>;
144
+
145
+ 'expanded-items-changed': GridExpandedItemsChangedEvent<TItem>;
146
+
147
+ 'grid-dragstart': GridDragStartEvent<TItem>;
148
+
149
+ 'grid-dragend': Event;
150
+
151
+ 'grid-drop': GridDropEvent<TItem>;
152
+
153
+ 'loading-changed': GridLoadingChangedEvent;
154
+
155
+ 'selected-items-changed': GridSelectedItemsChangedEvent<TItem>;
156
+
157
+ 'size-changed': GridSizeChangedEvent;
158
+ }
159
+
160
+ export interface GridEventMap<TItem> extends HTMLElementEventMap, GridCustomEventMap<TItem> {}
161
+
162
+ export declare function GridMixin<TItem, T extends Constructor<HTMLElement>>(
163
+ base: T,
164
+ ): Constructor<ActiveItemMixinClass<TItem>> &
165
+ Constructor<ArrayDataProviderMixinClass<TItem>> &
166
+ Constructor<ColumnReorderingMixinClass> &
167
+ Constructor<DataProviderMixinClass<TItem>> &
168
+ Constructor<DisabledMixinClass> &
169
+ Constructor<DragAndDropMixinClass<TItem>> &
170
+ Constructor<EventContextMixinClass<TItem>> &
171
+ Constructor<GridMixinClass<TItem>> &
172
+ Constructor<RowDetailsMixinClass<TItem>> &
173
+ Constructor<ScrollMixinClass> &
174
+ Constructor<SelectionMixinClass<TItem>> &
175
+ Constructor<SortMixinClass> &
176
+ Constructor<StylingMixinClass<TItem>> &
177
+ T;
178
+
179
+ export interface GridMixinClass<TItem>
180
+ extends DisabledMixinClass,
181
+ ActiveItemMixinClass<TItem>,
182
+ ArrayDataProviderMixinClass<TItem>,
183
+ DataProviderMixinClass<TItem>,
184
+ RowDetailsMixinClass<TItem>,
185
+ ScrollMixinClass,
186
+ SelectionMixinClass<TItem>,
187
+ SortMixinClass,
188
+ ColumnReorderingMixinClass,
189
+ EventContextMixinClass<TItem>,
190
+ StylingMixinClass<TItem>,
191
+ DragAndDropMixinClass<TItem> {
192
+ /**
193
+ * If true, the grid's height is defined by its rows.
194
+ *
195
+ * Effectively, this disables the grid's virtual scrolling so that all the rows are rendered in the DOM at once.
196
+ * If the grid has a large number of items, using the feature is discouraged to avoid performance issues.
197
+ * @attr {boolean} all-rows-visible
198
+ */
199
+ allRowsVisible: boolean;
200
+
201
+ /**
202
+ * Updates the `width` of all columns which have `autoWidth` set to `true`.
203
+ */
204
+ recalculateColumnWidths(): void;
205
+
206
+ /**
207
+ * Requests an update for the content of cells.
208
+ *
209
+ * While performing the update, the following renderers are invoked:
210
+ * - `Grid.rowDetailsRenderer`
211
+ * - `GridColumn.renderer`
212
+ * - `GridColumn.headerRenderer`
213
+ * - `GridColumn.footerRenderer`
214
+ *
215
+ * It is not guaranteed that the update happens immediately (synchronously) after it is requested.
216
+ */
217
+ requestContentUpdate(): void;
218
+ }