apex-grid 3.2.0 → 3.4.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.
- package/CHANGELOG.md +120 -0
- package/README.md +229 -52
- package/components/cell.d.ts +16 -3
- package/components/cell.js +78 -8
- package/components/cell.js.map +1 -1
- package/components/filter-row.d.ts +3 -6
- package/components/filter-row.js +144 -115
- package/components/filter-row.js.map +1 -1
- package/components/grid.d.ts +421 -77
- package/components/grid.js +432 -13
- package/components/grid.js.map +1 -1
- package/components/group-header-row.d.ts +34 -0
- package/components/group-header-row.js +125 -0
- package/components/group-header-row.js.map +1 -0
- package/components/header-row.d.ts +13 -2
- package/components/header-row.js +33 -18
- package/components/header-row.js.map +1 -1
- package/components/header.d.ts +11 -0
- package/components/header.js +209 -8
- package/components/header.js.map +1 -1
- package/components/paginator.d.ts +6 -1
- package/components/paginator.js +17 -11
- package/components/paginator.js.map +1 -1
- package/components/row.d.ts +28 -0
- package/components/row.js +100 -3
- package/components/row.js.map +1 -1
- package/components/toolbar.d.ts +8 -1
- package/components/toolbar.js +25 -7
- package/components/toolbar.js.map +1 -1
- package/controllers/data-operation.js +1 -0
- package/controllers/data-operation.js.map +1 -1
- package/controllers/dom.d.ts +24 -6
- package/controllers/dom.js +62 -5
- package/controllers/dom.js.map +1 -1
- package/controllers/editing.d.ts +68 -1
- package/controllers/editing.js +129 -44
- package/controllers/editing.js.map +1 -1
- package/controllers/expansion.js +4 -4
- package/controllers/expansion.js.map +1 -1
- package/controllers/filter.d.ts +1 -1
- package/controllers/filter.js +27 -5
- package/controllers/filter.js.map +1 -1
- package/controllers/history.d.ts +86 -0
- package/controllers/history.js +125 -0
- package/controllers/history.js.map +1 -0
- package/controllers/navigation.d.ts +49 -2
- package/controllers/navigation.js +145 -3
- package/controllers/navigation.js.map +1 -1
- package/controllers/pagination.js +1 -1
- package/controllers/pagination.js.map +1 -1
- package/controllers/reorder.js +3 -1
- package/controllers/reorder.js.map +1 -1
- package/controllers/row-pin.d.ts +59 -0
- package/controllers/row-pin.js +75 -0
- package/controllers/row-pin.js.map +1 -0
- package/controllers/row-reorder.d.ts +161 -0
- package/controllers/row-reorder.js +332 -0
- package/controllers/row-reorder.js.map +1 -0
- package/controllers/selection.js +3 -3
- package/controllers/selection.js.map +1 -1
- package/controllers/sort.js +13 -3
- package/controllers/sort.js.map +1 -1
- package/controllers/state.d.ts +33 -0
- package/controllers/state.js +37 -2
- package/controllers/state.js.map +1 -1
- package/controllers/tree.d.ts +8 -0
- package/controllers/tree.js +0 -0
- package/controllers/tree.js.map +1 -1
- package/custom-elements.json +4667 -926
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/highlight.css +28 -0
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/functions/custom.html +3 -0
- package/docs/functions/interpolate.html +4 -0
- package/docs/functions/localize.html +8 -0
- package/docs/functions/max.html +3 -0
- package/docs/functions/min.html +3 -0
- package/docs/functions/pattern.html +3 -0
- package/docs/functions/required.html +3 -0
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +245 -54
- package/docs/interfaces/ApexCellValidationFailedEvent.html +13 -0
- package/docs/interfaces/ApexCellValueChangedEvent.html +1 -1
- package/docs/interfaces/ApexCellValueChangingEvent.html +2 -2
- package/docs/interfaces/ApexColumnGroupContext.html +6 -0
- package/docs/interfaces/ApexColumnMovedEvent.html +2 -2
- package/docs/interfaces/ApexColumnMovingEvent.html +1 -1
- package/docs/interfaces/ApexDetailContext.html +2 -2
- package/docs/interfaces/ApexGridEventMap.html +37 -9
- package/docs/interfaces/ApexHistoryChangedEvent.html +6 -0
- package/docs/interfaces/ApexPageChangedEvent.html +1 -1
- package/docs/interfaces/ApexRowMovingEvent.html +9 -0
- package/docs/interfaces/ApexRowPinningEvent.html +8 -0
- package/docs/interfaces/ApexStateChangedEvent.html +4 -0
- package/docs/interfaces/BaseApexCellContext.html +1 -1
- package/docs/interfaces/BaseApexEditorContext.html +1 -1
- package/docs/interfaces/BaseColumnConfiguration.html +42 -17
- package/docs/interfaces/CSVExportOptions.html +2 -2
- package/docs/interfaces/ColumnGroupConfiguration.html +12 -0
- package/docs/interfaces/ColumnLayoutState.html +2 -0
- package/docs/interfaces/ColumnSchema.html +22 -0
- package/docs/interfaces/DataPipelineConfiguration.html +2 -2
- package/docs/interfaces/EditingHistoryConfiguration.html +10 -0
- package/docs/interfaces/ExportFormat.html +2 -2
- package/docs/interfaces/ExportOptions.html +1 -1
- package/docs/interfaces/FilterStateSnapshot.html +4 -0
- package/docs/interfaces/GetStateOptions.html +4 -0
- package/docs/interfaces/GridCapabilities.html +8 -0
- package/docs/interfaces/GridEditingConfiguration.html +4 -2
- package/docs/interfaces/GridRowPinningConfiguration.html +5 -0
- package/docs/interfaces/GridRowReorderingConfiguration.html +22 -0
- package/docs/interfaces/GridSchema.html +19 -0
- package/docs/interfaces/GridState.html +41 -0
- package/docs/interfaces/GridTreeConfiguration.html +2 -2
- package/docs/interfaces/PaginationConfiguration.html +1 -1
- package/docs/interfaces/PaginationState.html +1 -1
- package/docs/interfaces/SetStateOptions.html +9 -0
- package/docs/interfaces/SetStateResult.html +11 -0
- package/docs/interfaces/SortStateSnapshot.html +2 -0
- package/docs/interfaces/ValidatorContext.html +8 -0
- package/docs/media/_tokens.scss +70 -81
- package/docs/media/package.json +2 -2
- package/docs/media/state-persistence.html +189 -0
- package/docs/modules.html +1 -1
- package/docs/types/DataPipelineParams.html +2 -2
- package/docs/types/EditMode.html +2 -2
- package/docs/types/GridLocaleKey.html +3 -0
- package/docs/types/GridLocaleText.html +5 -0
- package/docs/types/LocaleParams.html +2 -0
- package/docs/types/PaginationMode.html +1 -1
- package/docs/types/RowDropPosition.html +2 -0
- package/docs/types/RowPinPosition.html +2 -0
- package/docs/types/RowRef.html +3 -0
- package/docs/types/Validator.html +4 -0
- package/docs/variables/EN_LOCALE.html +9 -0
- package/docs/variables/esLocale.html +8 -0
- package/i18n/en.d.ts +245 -0
- package/i18n/en.js +219 -0
- package/i18n/en.js.map +1 -0
- package/i18n/es.d.ts +18 -0
- package/i18n/es.js +219 -0
- package/i18n/es.js.map +1 -0
- package/i18n/index.d.ts +3 -0
- package/i18n/index.js +4 -0
- package/i18n/index.js.map +1 -0
- package/i18n/localize.d.ts +23 -0
- package/i18n/localize.js +15 -0
- package/i18n/localize.js.map +1 -0
- package/index.d.ts +8 -2
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/internal/column-types.js +1 -1
- package/internal/column-types.js.map +1 -1
- package/internal/feature-module.d.ts +46 -0
- package/internal/feature-module.js +11 -0
- package/internal/feature-module.js.map +1 -1
- package/internal/flip.js +1 -1
- package/internal/flip.js.map +1 -1
- package/internal/icons.d.ts +9 -7
- package/internal/icons.js +75 -35
- package/internal/icons.js.map +1 -1
- package/internal/index.d.ts +5 -3
- package/internal/index.js +2 -1
- package/internal/index.js.map +1 -1
- package/internal/state-schema.d.ts +85 -0
- package/internal/state-schema.js +27 -0
- package/internal/state-schema.js.map +1 -0
- package/internal/state-snapshot.d.ts +152 -0
- package/internal/state-snapshot.js +115 -0
- package/internal/state-snapshot.js.map +1 -0
- package/internal/tags.d.ts +1 -0
- package/internal/tags.js +1 -0
- package/internal/tags.js.map +1 -1
- package/internal/types.d.ts +162 -2
- package/internal/types.js.map +1 -1
- package/internal/utils.d.ts +12 -0
- package/internal/utils.js +17 -0
- package/internal/utils.js.map +1 -1
- package/internal/validators.d.ts +31 -0
- package/internal/validators.js +44 -0
- package/internal/validators.js.map +1 -0
- package/package.json +1 -1
- package/styles/_tokens.css.js +1 -1
- package/styles/_tokens.css.js.map +1 -1
- package/styles/body-cell/body-cell.css.js +1 -1
- package/styles/body-cell/body-cell.css.js.map +1 -1
- package/styles/body-row/body-row.css.js +1 -1
- package/styles/body-row/body-row.css.js.map +1 -1
- package/styles/filter-row/filter-row.css.js +1 -1
- package/styles/filter-row/filter-row.css.js.map +1 -1
- package/styles/grid/_grid.base.css.js +1 -1
- package/styles/grid/_grid.base.css.js.map +1 -1
- package/styles/grid/grid.css.js +1 -1
- package/styles/grid/grid.css.js.map +1 -1
- package/styles/group-header-row/group-header-row.css.d.ts +1 -0
- package/styles/group-header-row/group-header-row.css.js +3 -0
- package/styles/group-header-row/group-header-row.css.js.map +1 -0
- package/styles/header-cell/header-cell.css.js +1 -1
- package/styles/header-cell/header-cell.css.js.map +1 -1
- package/styles/header-row/header-row.base.css.js +1 -1
- package/styles/header-row/header-row.base.css.js.map +1 -1
- package/styles/toolbar/toolbar.css.js +1 -1
- package/styles/toolbar/toolbar.css.js.map +1 -1
- package/docs/classes/ApexGrid.html +0 -399
package/components/grid.js
CHANGED
|
@@ -11,21 +11,38 @@ import { styleMap } from 'lit/directives/style-map.js';
|
|
|
11
11
|
import { DataOperationsController } from '../controllers/data-operation.js';
|
|
12
12
|
import { GridDOMController } from '../controllers/dom.js';
|
|
13
13
|
import { gridStateContext, StateController } from '../controllers/state.js';
|
|
14
|
-
import {
|
|
14
|
+
import { localize as resolveLocaleText, } from '../i18n/index.js';
|
|
15
|
+
import { DEFAULT_COLUMN_CONFIG, PIPELINE, SENTINEL_NODE } from '../internal/constants.js';
|
|
15
16
|
import { buildCSV, downloadBlob, } from '../internal/export.js';
|
|
16
17
|
import { EventEmitterBase } from '../internal/mixins/event-emitter.js';
|
|
17
18
|
import { registerComponent } from '../internal/register.js';
|
|
19
|
+
import { columnSchema, operandsByType } from '../internal/state-schema.js';
|
|
20
|
+
import { applyColumnLayout, deserializeFilter, resolveRowRefs, serializeColumnLayout, serializeFilter, serializeRowRefs, serializeSort, } from '../internal/state-snapshot.js';
|
|
18
21
|
import { GRID_TAG } from '../internal/tags.js';
|
|
19
22
|
import { asArray, autoGenerateColumns, getDisplayColumns, getFilterOperandsFor, } from '../internal/utils.js';
|
|
20
23
|
import { watch } from '../internal/watch.js';
|
|
21
24
|
import { styles as gridStyles } from '../styles/grid/grid.css.js';
|
|
22
25
|
import ApexGridCell from './cell.js';
|
|
23
26
|
import ApexFilterRow from './filter-row.js';
|
|
27
|
+
import ApexGridGroupHeaderRow from './group-header-row.js';
|
|
24
28
|
import ApexGridHeaderRow from './header-row.js';
|
|
25
29
|
import ApexGridPaginator from './paginator.js';
|
|
26
30
|
import ApexGridRow from './row.js';
|
|
27
31
|
import ApexGridToolbar from './toolbar.js';
|
|
28
32
|
import ApexVirtualizer from './virtualizer.js';
|
|
33
|
+
const SET_STATE_SLICES = [
|
|
34
|
+
'columns',
|
|
35
|
+
'sort',
|
|
36
|
+
'filter',
|
|
37
|
+
'quickFilter',
|
|
38
|
+
'modules',
|
|
39
|
+
'rowOrder',
|
|
40
|
+
'tree',
|
|
41
|
+
'expansion',
|
|
42
|
+
'rowPinning',
|
|
43
|
+
'selection',
|
|
44
|
+
'pagination',
|
|
45
|
+
];
|
|
29
46
|
export class ApexGrid extends EventEmitterBase {
|
|
30
47
|
constructor() {
|
|
31
48
|
super(...arguments);
|
|
@@ -48,17 +65,26 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
48
65
|
this.showQuickFilter = false;
|
|
49
66
|
this.showExport = false;
|
|
50
67
|
this.columnReordering = false;
|
|
68
|
+
this.columnSeparator = true;
|
|
69
|
+
this.coordinateHints = false;
|
|
70
|
+
this.columnMenu = true;
|
|
71
|
+
this.#autoAriaLabel = null;
|
|
72
|
+
this.#stateChangedListeners = 0;
|
|
73
|
+
this.#lastStateJson = null;
|
|
51
74
|
}
|
|
52
75
|
static get tagName() {
|
|
53
76
|
return GRID_TAG;
|
|
54
77
|
}
|
|
55
78
|
static { this.styles = gridStyles; }
|
|
56
79
|
static register() {
|
|
57
|
-
registerComponent(ApexGrid, ApexVirtualizer, ApexGridRow, ApexGridHeaderRow, ApexFilterRow, ApexGridPaginator, ApexGridToolbar);
|
|
80
|
+
registerComponent(ApexGrid, ApexVirtualizer, ApexGridRow, ApexGridGroupHeaderRow, ApexGridHeaderRow, ApexFilterRow, ApexGridPaginator, ApexGridToolbar);
|
|
58
81
|
}
|
|
59
82
|
createStateController() {
|
|
60
83
|
return new StateController(this);
|
|
61
84
|
}
|
|
85
|
+
localize(key, params, fallback) {
|
|
86
|
+
return resolveLocaleText(this.localeText, key, params, fallback);
|
|
87
|
+
}
|
|
62
88
|
get selectedRows() {
|
|
63
89
|
return this.stateController.selection.selectedRows();
|
|
64
90
|
}
|
|
@@ -83,6 +109,15 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
83
109
|
isRowSelected(row) {
|
|
84
110
|
return this.stateController.selection.isSelected(row);
|
|
85
111
|
}
|
|
112
|
+
get hasColumnGroups() {
|
|
113
|
+
if (!this.columnGroups?.length)
|
|
114
|
+
return false;
|
|
115
|
+
const ids = new Set(this.columnGroups.map((group) => group.id));
|
|
116
|
+
return this.columns.some((column) => !column.hidden && column.group && ids.has(column.group));
|
|
117
|
+
}
|
|
118
|
+
get columnGroupDepth() {
|
|
119
|
+
return this.hasColumnGroups ? 1 : 0;
|
|
120
|
+
}
|
|
86
121
|
get expandedRows() {
|
|
87
122
|
return this.stateController.expansion.expandedRows();
|
|
88
123
|
}
|
|
@@ -161,15 +196,19 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
161
196
|
return this.dataState.length;
|
|
162
197
|
}
|
|
163
198
|
get pageItems() {
|
|
199
|
+
const rowPin = this.stateController.rowPin;
|
|
200
|
+
const base = rowPin?.enabled && rowPin.hasPinnedRows
|
|
201
|
+
? this.dataState.filter((row) => !rowPin.isPinned(row))
|
|
202
|
+
: this.dataState;
|
|
164
203
|
if (!this.stateController.pagination.enabled)
|
|
165
|
-
return
|
|
204
|
+
return base;
|
|
166
205
|
if (this.pagination?.mode === 'remote')
|
|
167
|
-
return
|
|
206
|
+
return base;
|
|
168
207
|
const { page, pageSize } = this.stateController.pagination;
|
|
169
208
|
if (!pageSize)
|
|
170
|
-
return
|
|
209
|
+
return base;
|
|
171
210
|
const start = page * pageSize;
|
|
172
|
-
return
|
|
211
|
+
return base.slice(start, start + pageSize);
|
|
173
212
|
}
|
|
174
213
|
get page() {
|
|
175
214
|
return this.stateController.pagination.page;
|
|
@@ -227,13 +266,58 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
227
266
|
}
|
|
228
267
|
updated() {
|
|
229
268
|
this.setAttribute('role', this.stateController.tree.enabled ? 'treegrid' : 'grid');
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
this.setAttribute('aria-rowcount', String(headerRows + this.pageItems.length));
|
|
269
|
+
const pinned = this.stateController.rowPin.pinnedRows;
|
|
270
|
+
this.setAttribute('aria-rowcount', String(this.headerRowCount + pinned.top.length + this.pageItems.length + pinned.bottom.length));
|
|
233
271
|
const visibleColumns = this.columns.filter((column) => !column.hidden).length;
|
|
234
272
|
const extras = (this.stateController.selection.showCheckboxColumn ? 1 : 0) +
|
|
235
273
|
(this.stateController.expansion.showToggleColumn ? 1 : 0);
|
|
236
274
|
this.setAttribute('aria-colcount', String(visibleColumns + extras));
|
|
275
|
+
const selection = this.stateController.selection;
|
|
276
|
+
if (selection.enabled && selection.mode === 'multiple') {
|
|
277
|
+
this.setAttribute('aria-multiselectable', 'true');
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
this.removeAttribute('aria-multiselectable');
|
|
281
|
+
}
|
|
282
|
+
if (this.scrollContainer) {
|
|
283
|
+
this.scrollContainer.tabIndex = this.stateController.active === SENTINEL_NODE ? 0 : -1;
|
|
284
|
+
}
|
|
285
|
+
const currentLabel = this.getAttribute('aria-label');
|
|
286
|
+
const authorLabeled = this.hasAttribute('aria-labelledby') ||
|
|
287
|
+
(currentLabel !== null && currentLabel !== this.#autoAriaLabel);
|
|
288
|
+
if (!authorLabeled) {
|
|
289
|
+
const label = this.localize('grid.label');
|
|
290
|
+
if (currentLabel !== label)
|
|
291
|
+
this.setAttribute('aria-label', label);
|
|
292
|
+
this.#autoAriaLabel = label;
|
|
293
|
+
}
|
|
294
|
+
this.#emitStateChangedIfNeeded();
|
|
295
|
+
}
|
|
296
|
+
#autoAriaLabel;
|
|
297
|
+
#stateChangedListeners;
|
|
298
|
+
#lastStateJson;
|
|
299
|
+
addEventListener(type, listener, options) {
|
|
300
|
+
if (type === 'stateChanged') {
|
|
301
|
+
this.#stateChangedListeners += 1;
|
|
302
|
+
this.#lastStateJson = this.hasUpdated ? JSON.stringify(this.getState()) : null;
|
|
303
|
+
}
|
|
304
|
+
super.addEventListener(type, listener, options);
|
|
305
|
+
}
|
|
306
|
+
removeEventListener(type, listener, options) {
|
|
307
|
+
if (type === 'stateChanged') {
|
|
308
|
+
this.#stateChangedListeners = Math.max(0, this.#stateChangedListeners - 1);
|
|
309
|
+
}
|
|
310
|
+
super.removeEventListener(type, listener, options);
|
|
311
|
+
}
|
|
312
|
+
#emitStateChangedIfNeeded() {
|
|
313
|
+
if (this.#stateChangedListeners === 0)
|
|
314
|
+
return;
|
|
315
|
+
const snapshot = this.getState();
|
|
316
|
+
const json = JSON.stringify(snapshot);
|
|
317
|
+
if (json === this.#lastStateJson)
|
|
318
|
+
return;
|
|
319
|
+
this.#lastStateJson = json;
|
|
320
|
+
this.emitEvent('stateChanged', { detail: { state: snapshot } });
|
|
237
321
|
}
|
|
238
322
|
firstUpdated() {
|
|
239
323
|
if (typeof getComputedStyle === 'function' && getComputedStyle(this).display !== 'grid') {
|
|
@@ -254,6 +338,201 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
254
338
|
sort(expressions) {
|
|
255
339
|
this.stateController.sorting.sort(expressions);
|
|
256
340
|
}
|
|
341
|
+
getState(options) {
|
|
342
|
+
const rowId = options?.rowId ?? this.rowId;
|
|
343
|
+
const pinned = this.stateController.rowPin.pinnedRows;
|
|
344
|
+
const manualOrder = this.stateController.rowReorder.getManualOrder();
|
|
345
|
+
return {
|
|
346
|
+
version: 1,
|
|
347
|
+
columns: serializeColumnLayout(this.columns),
|
|
348
|
+
sort: serializeSort(this.sortExpressions),
|
|
349
|
+
filter: serializeFilter(this.filterExpressions),
|
|
350
|
+
quickFilter: this.quickFilter,
|
|
351
|
+
pagination: { page: this.page, pageSize: this.pageSize },
|
|
352
|
+
selection: serializeRowRefs(this.selectedRows, this.data, rowId),
|
|
353
|
+
expansion: serializeRowRefs(this.expandedRows, this.data, rowId),
|
|
354
|
+
treeExpanded: serializeRowRefs([...this.stateController.tree.expanded], this.data, rowId),
|
|
355
|
+
treeExpandedKeys: [...this.stateController.tree.expandedKeys],
|
|
356
|
+
rowPinning: {
|
|
357
|
+
top: serializeRowRefs(pinned.top, this.data, rowId),
|
|
358
|
+
bottom: serializeRowRefs(pinned.bottom, this.data, rowId),
|
|
359
|
+
},
|
|
360
|
+
rowOrder: manualOrder ? serializeRowRefs(manualOrder, this.data, rowId) : null,
|
|
361
|
+
modules: this.stateController.serializeModuleState(),
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
getSchema() {
|
|
365
|
+
return {
|
|
366
|
+
version: 1,
|
|
367
|
+
columns: this.columns.map((column) => columnSchema(column)),
|
|
368
|
+
capabilities: {
|
|
369
|
+
sort: {
|
|
370
|
+
directions: ['ascending', 'descending'],
|
|
371
|
+
multi: Boolean(this.sortConfiguration?.multiple),
|
|
372
|
+
},
|
|
373
|
+
filter: { operandsByType: operandsByType(this.columns) },
|
|
374
|
+
pagination: Boolean(this.pagination?.enabled),
|
|
375
|
+
selection: this.selection?.enabled ? (this.selection.mode ?? 'multiple') : false,
|
|
376
|
+
rowPinning: Boolean(this.rowPinning?.enabled),
|
|
377
|
+
rowReordering: Boolean(this.rowReordering?.enabled),
|
|
378
|
+
},
|
|
379
|
+
state: this.getState(),
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
setState(state, options) {
|
|
383
|
+
const rowId = options?.rowId ?? this.rowId;
|
|
384
|
+
const strict = options?.strict ?? false;
|
|
385
|
+
const applied = [];
|
|
386
|
+
const warnings = [];
|
|
387
|
+
const warn = (message) => {
|
|
388
|
+
if (strict)
|
|
389
|
+
throw new Error(`[apex-grid] setState: ${message}`);
|
|
390
|
+
warnings.push(message);
|
|
391
|
+
};
|
|
392
|
+
const asArray = (value, label) => {
|
|
393
|
+
if (value === undefined)
|
|
394
|
+
return null;
|
|
395
|
+
if (!Array.isArray(value)) {
|
|
396
|
+
warn(`${label}: expected an array, got ${typeof value}; skipped`);
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
return value;
|
|
400
|
+
};
|
|
401
|
+
const resolveCounted = (refs, label) => {
|
|
402
|
+
const rows = resolveRowRefs(refs, this.data, rowId);
|
|
403
|
+
if (rows.length < refs.length) {
|
|
404
|
+
warn(`${label}: ${refs.length - rows.length} of ${refs.length} row(s) could not be resolved`);
|
|
405
|
+
}
|
|
406
|
+
return rows;
|
|
407
|
+
};
|
|
408
|
+
if (state.version !== undefined && state.version !== 1) {
|
|
409
|
+
warn(`unsupported snapshot version ${String(state.version)}; applying recognized slices best-effort`);
|
|
410
|
+
}
|
|
411
|
+
const columns = asArray(state.columns, 'columns');
|
|
412
|
+
if (columns) {
|
|
413
|
+
this.columns = applyColumnLayout(this.columns, columns);
|
|
414
|
+
applied.push('columns');
|
|
415
|
+
}
|
|
416
|
+
const sort = asArray(state.sort, 'sort');
|
|
417
|
+
if (sort) {
|
|
418
|
+
this.stateController.sorting.reset();
|
|
419
|
+
const valid = [];
|
|
420
|
+
for (const entry of sort) {
|
|
421
|
+
if (this.getColumn(entry.key)) {
|
|
422
|
+
valid.push(entry);
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
warn(`sort: unknown column "${entry.key}"; dropped`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (valid.length)
|
|
429
|
+
this.sort(valid);
|
|
430
|
+
applied.push('sort');
|
|
431
|
+
}
|
|
432
|
+
const filter = asArray(state.filter, 'filter');
|
|
433
|
+
if (filter) {
|
|
434
|
+
this.stateController.filtering.reset();
|
|
435
|
+
const expressions = deserializeFilter(filter, (key) => this.getColumn(key), (snapshot, reason) => warn(`filter: "${snapshot.key}" dropped (${reason})`));
|
|
436
|
+
if (expressions.length)
|
|
437
|
+
this.filter(expressions);
|
|
438
|
+
applied.push('filter');
|
|
439
|
+
}
|
|
440
|
+
if (state.quickFilter !== undefined) {
|
|
441
|
+
if (typeof state.quickFilter === 'string') {
|
|
442
|
+
this.quickFilter = state.quickFilter;
|
|
443
|
+
applied.push('quickFilter');
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
warn(`quickFilter: expected a string, got ${typeof state.quickFilter}; skipped`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (state.modules !== undefined) {
|
|
450
|
+
if (state.modules && typeof state.modules === 'object') {
|
|
451
|
+
this.stateController.restoreModuleState(state.modules);
|
|
452
|
+
applied.push('modules');
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
warn(`modules: expected an object, got ${typeof state.modules}; skipped`);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (state.rowOrder !== undefined) {
|
|
459
|
+
if (state.rowOrder === null) {
|
|
460
|
+
this.stateController.rowReorder.restoreManualOrder(null);
|
|
461
|
+
applied.push('rowOrder');
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
const order = asArray(state.rowOrder, 'rowOrder');
|
|
465
|
+
if (order) {
|
|
466
|
+
if (this.sortExpressions.length) {
|
|
467
|
+
warn('rowOrder dropped: a manual order is mutually exclusive with an active sort');
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
this.stateController.rowReorder.restoreManualOrder(resolveCounted(order, 'rowOrder'));
|
|
471
|
+
}
|
|
472
|
+
applied.push('rowOrder');
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (state.treeExpanded !== undefined || state.treeExpandedKeys !== undefined) {
|
|
477
|
+
const refs = asArray(state.treeExpanded, 'treeExpanded') ?? [];
|
|
478
|
+
const keys = asArray(state.treeExpandedKeys, 'treeExpandedKeys') ?? [];
|
|
479
|
+
this.stateController.tree.restoreExpansion(resolveCounted(refs, 'treeExpanded'), keys);
|
|
480
|
+
applied.push('tree');
|
|
481
|
+
}
|
|
482
|
+
const expansion = asArray(state.expansion, 'expansion');
|
|
483
|
+
if (expansion) {
|
|
484
|
+
this.expandedRows = resolveCounted(expansion, 'expansion');
|
|
485
|
+
applied.push('expansion');
|
|
486
|
+
}
|
|
487
|
+
if (state.rowPinning !== undefined) {
|
|
488
|
+
const pinning = state.rowPinning;
|
|
489
|
+
if (pinning && typeof pinning === 'object') {
|
|
490
|
+
this.stateController.rowPin.restore(resolveCounted(asArray(pinning.top, 'rowPinning.top') ?? [], 'rowPinning.top'), resolveCounted(asArray(pinning.bottom, 'rowPinning.bottom') ?? [], 'rowPinning.bottom'));
|
|
491
|
+
applied.push('rowPinning');
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
warn(`rowPinning: expected an object, got ${typeof pinning}; skipped`);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
const selection = asArray(state.selection, 'selection');
|
|
498
|
+
if (selection) {
|
|
499
|
+
this.selectedRows = resolveCounted(selection, 'selection');
|
|
500
|
+
applied.push('selection');
|
|
501
|
+
}
|
|
502
|
+
if (state.pagination !== undefined) {
|
|
503
|
+
const pagination = state.pagination;
|
|
504
|
+
if (pagination && typeof pagination === 'object') {
|
|
505
|
+
const { page, pageSize } = pagination;
|
|
506
|
+
if (pageSize !== undefined) {
|
|
507
|
+
if (typeof pageSize === 'number' && Number.isFinite(pageSize) && pageSize > 0) {
|
|
508
|
+
this.pageSize = pageSize;
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
warn(`pagination: invalid pageSize ${String(pageSize)}; ignored`);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (page !== undefined) {
|
|
515
|
+
if (typeof page === 'number' && Number.isFinite(page)) {
|
|
516
|
+
const requested = Math.trunc(page);
|
|
517
|
+
this.page = requested;
|
|
518
|
+
if (this.page !== requested) {
|
|
519
|
+
warn(`pagination: page ${requested} out of range; clamped to ${this.page}`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
warn(`pagination: invalid page ${String(page)}; ignored`);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
applied.push('pagination');
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
warn(`pagination: expected an object, got ${typeof pagination}; skipped`);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
this.requestUpdate(PIPELINE);
|
|
533
|
+
const skipped = SET_STATE_SLICES.filter((slice) => !applied.includes(slice));
|
|
534
|
+
return { applied, skipped, warnings };
|
|
535
|
+
}
|
|
257
536
|
clearSort(key) {
|
|
258
537
|
this.stateController.sorting.reset(key);
|
|
259
538
|
this.requestUpdate(PIPELINE);
|
|
@@ -367,6 +646,33 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
367
646
|
editing.cancelCell();
|
|
368
647
|
}
|
|
369
648
|
}
|
|
649
|
+
get canUndo() {
|
|
650
|
+
return this.stateController.history.canUndo;
|
|
651
|
+
}
|
|
652
|
+
get canRedo() {
|
|
653
|
+
return this.stateController.history.canRedo;
|
|
654
|
+
}
|
|
655
|
+
undo() {
|
|
656
|
+
this.stateController.history.undo();
|
|
657
|
+
}
|
|
658
|
+
redo() {
|
|
659
|
+
this.stateController.history.redo();
|
|
660
|
+
}
|
|
661
|
+
clearHistory() {
|
|
662
|
+
this.stateController.history.clear();
|
|
663
|
+
}
|
|
664
|
+
pinRow(row, position = 'top') {
|
|
665
|
+
return this.stateController.rowPin.pinRow(row, position);
|
|
666
|
+
}
|
|
667
|
+
unpinRow(row) {
|
|
668
|
+
return this.stateController.rowPin.unpinRow(row);
|
|
669
|
+
}
|
|
670
|
+
get pinnedRows() {
|
|
671
|
+
return this.stateController.rowPin.pinnedRows;
|
|
672
|
+
}
|
|
673
|
+
moveRow(from, to, position = 'before') {
|
|
674
|
+
return this.stateController.rowReorder.moveRow(from, to, position);
|
|
675
|
+
}
|
|
370
676
|
exportToCSV(options = {}) {
|
|
371
677
|
const csv = buildCSV(this, options);
|
|
372
678
|
const filename = options.filename;
|
|
@@ -381,6 +687,9 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
381
687
|
get exportFormats() {
|
|
382
688
|
return [{ id: 'csv', label: 'Export CSV' }];
|
|
383
689
|
}
|
|
690
|
+
get toolbarActions() {
|
|
691
|
+
return [];
|
|
692
|
+
}
|
|
384
693
|
exportAs(formatId, options = {}) {
|
|
385
694
|
if (formatId === 'csv') {
|
|
386
695
|
this.exportToCSV(options);
|
|
@@ -428,16 +737,28 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
428
737
|
column: target.column.key,
|
|
429
738
|
row: target.row.index,
|
|
430
739
|
};
|
|
740
|
+
if (!target.editing)
|
|
741
|
+
target.focus({ preventScroll: true });
|
|
431
742
|
}
|
|
432
743
|
}
|
|
433
744
|
bodyKeydownHandler(event) {
|
|
434
|
-
|
|
745
|
+
const origin = event.composedPath()[0];
|
|
746
|
+
const fromBody = this.scrollContainer.isSameNode(event.target);
|
|
747
|
+
const fromCell = origin instanceof ApexGridCell && !origin.editing;
|
|
748
|
+
if (fromBody || fromCell) {
|
|
435
749
|
this.stateController.navigation.navigate(event);
|
|
436
750
|
}
|
|
437
751
|
}
|
|
752
|
+
bodyFocusHandler(event) {
|
|
753
|
+
if (this.scrollContainer.isSameNode(event.target)) {
|
|
754
|
+
this.stateController.navigation.focusActiveCell();
|
|
755
|
+
}
|
|
756
|
+
}
|
|
438
757
|
bodyPointerHandler(event) {
|
|
439
758
|
if (this.stateController.modules.size === 0)
|
|
440
759
|
return;
|
|
760
|
+
if (event.type === 'pointermove' && event.buttons === 0)
|
|
761
|
+
return;
|
|
441
762
|
const target = event.composedPath().find((el) => el instanceof ApexGridCell);
|
|
442
763
|
if (!target?.row)
|
|
443
764
|
return;
|
|
@@ -453,12 +774,25 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
453
774
|
originalEvent: event,
|
|
454
775
|
});
|
|
455
776
|
}
|
|
777
|
+
renderGroupHeaderRow() {
|
|
778
|
+
if (!this.hasColumnGroups)
|
|
779
|
+
return nothing;
|
|
780
|
+
return html `
|
|
781
|
+
<apex-grid-group-header-row
|
|
782
|
+
style=${styleMap(this.DOM.columnSizes)}
|
|
783
|
+
.columns=${this.DOM.displayColumns}
|
|
784
|
+
.pinOffsets=${this.DOM.pinOffsets}
|
|
785
|
+
.groups=${this.columnGroups ?? []}
|
|
786
|
+
></apex-grid-group-header-row>
|
|
787
|
+
`;
|
|
788
|
+
}
|
|
456
789
|
renderHeaderRow() {
|
|
457
790
|
return html `
|
|
458
791
|
<apex-grid-header-row
|
|
459
792
|
style=${styleMap(this.DOM.columnSizes)}
|
|
460
793
|
.columns=${this.DOM.displayColumns}
|
|
461
794
|
.pinOffsets=${this.DOM.pinOffsets}
|
|
795
|
+
.coordinateHints=${this.coordinateHints}
|
|
462
796
|
></apex-grid-header-row>
|
|
463
797
|
`;
|
|
464
798
|
}
|
|
@@ -469,20 +803,48 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
469
803
|
.renderItem=${this.DOM.rowRenderer}
|
|
470
804
|
@click=${this.bodyClickHandler}
|
|
471
805
|
@keydown=${this.bodyKeydownHandler}
|
|
806
|
+
@focusin=${this.bodyFocusHandler}
|
|
472
807
|
@pointerdown=${this.bodyPointerHandler}
|
|
473
|
-
@
|
|
808
|
+
@pointermove=${this.bodyPointerHandler}
|
|
474
809
|
@pointerup=${this.bodyPointerHandler}
|
|
475
810
|
></apex-virtualizer>
|
|
476
811
|
`;
|
|
477
812
|
}
|
|
813
|
+
get headerRowCount() {
|
|
814
|
+
return this.columnGroupDepth + 1 + (this.columns.some((column) => column.filter) ? 1 : 0);
|
|
815
|
+
}
|
|
816
|
+
renderPinnedTop() {
|
|
817
|
+
const rowPin = this.stateController.rowPin;
|
|
818
|
+
if (!rowPin.enabled)
|
|
819
|
+
return nothing;
|
|
820
|
+
const rows = rowPin.pinnedRows.top;
|
|
821
|
+
if (rows.length === 0)
|
|
822
|
+
return nothing;
|
|
823
|
+
return html `<div part="pinned-rows pinned-top">
|
|
824
|
+
${rows.map((data, i) => this.DOM.pinnedRowRenderer(data, i, this.headerRowCount))}
|
|
825
|
+
</div>`;
|
|
826
|
+
}
|
|
827
|
+
renderPinnedBottom() {
|
|
828
|
+
const rowPin = this.stateController.rowPin;
|
|
829
|
+
if (!rowPin.enabled)
|
|
830
|
+
return nothing;
|
|
831
|
+
const rows = rowPin.pinnedRows.bottom;
|
|
832
|
+
if (rows.length === 0)
|
|
833
|
+
return nothing;
|
|
834
|
+
const offset = this.headerRowCount + rowPin.pinnedRows.top.length + this.pageItems.length;
|
|
835
|
+
return html `<div part="pinned-rows pinned-bottom">
|
|
836
|
+
${rows.map((data, i) => this.DOM.pinnedRowRenderer(data, i, offset))}
|
|
837
|
+
</div>`;
|
|
838
|
+
}
|
|
478
839
|
renderFilterRow() {
|
|
479
840
|
return this.columns.some((column) => column.filter)
|
|
480
|
-
? html `<apex-filter-row
|
|
841
|
+
? html `<apex-filter-row></apex-filter-row>`
|
|
481
842
|
: nothing;
|
|
482
843
|
}
|
|
483
844
|
renderToolbar() {
|
|
484
|
-
if (!this.showQuickFilter && !this.showExport)
|
|
845
|
+
if (!this.showQuickFilter && !this.showExport && this.toolbarActions.length === 0) {
|
|
485
846
|
return nothing;
|
|
847
|
+
}
|
|
486
848
|
return html `<apex-grid-toolbar
|
|
487
849
|
.value=${this.quickFilter}
|
|
488
850
|
.showQuickFilter=${this.showQuickFilter}
|
|
@@ -512,15 +874,48 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
512
874
|
${this.stateController.announcement}
|
|
513
875
|
</div>`;
|
|
514
876
|
}
|
|
877
|
+
renderRowDragGhost() {
|
|
878
|
+
const ghost = this.stateController.rowReorder.ghost;
|
|
879
|
+
if (!ghost)
|
|
880
|
+
return nothing;
|
|
881
|
+
return html `<div
|
|
882
|
+
part="row-drag-ghost"
|
|
883
|
+
style=${styleMap({
|
|
884
|
+
left: `${ghost.x}px`,
|
|
885
|
+
top: `${ghost.y}px`,
|
|
886
|
+
height: `${ghost.height}px`,
|
|
887
|
+
})}
|
|
888
|
+
>
|
|
889
|
+
<span part="row-drag-ghost-grip" aria-hidden="true">
|
|
890
|
+
<svg viewBox="0 0 16 16" width="16" height="16">
|
|
891
|
+
<circle cx="6" cy="3.5" r="1.25" />
|
|
892
|
+
<circle cx="10" cy="3.5" r="1.25" />
|
|
893
|
+
<circle cx="6" cy="8" r="1.25" />
|
|
894
|
+
<circle cx="10" cy="8" r="1.25" />
|
|
895
|
+
<circle cx="6" cy="12.5" r="1.25" />
|
|
896
|
+
<circle cx="10" cy="12.5" r="1.25" />
|
|
897
|
+
</svg>
|
|
898
|
+
</span>
|
|
899
|
+
${ghost.cells.map((cell) => html `<span
|
|
900
|
+
part="row-drag-ghost-cell"
|
|
901
|
+
style=${styleMap({ width: `${cell.width}px`, textAlign: cell.align })}
|
|
902
|
+
>${cell.text}</span
|
|
903
|
+
>`)}
|
|
904
|
+
</div>`;
|
|
905
|
+
}
|
|
515
906
|
render() {
|
|
516
907
|
return html `
|
|
517
908
|
${this.stateController.resizing.renderIndicator()}
|
|
518
909
|
${this.renderToolbar()}
|
|
910
|
+
${this.renderGroupHeaderRow()}
|
|
519
911
|
${this.renderHeaderRow()}
|
|
520
912
|
${this.renderFilterRow()}
|
|
913
|
+
${this.renderPinnedTop()}
|
|
521
914
|
${this.renderBody()}
|
|
915
|
+
${this.renderPinnedBottom()}
|
|
522
916
|
${this.renderPaginator()}
|
|
523
917
|
${this.renderLiveRegion()}
|
|
918
|
+
${this.renderRowDragGhost()}
|
|
524
919
|
`;
|
|
525
920
|
}
|
|
526
921
|
announce(message) {
|
|
@@ -554,6 +949,9 @@ __decorate([
|
|
|
554
949
|
__decorate([
|
|
555
950
|
property({ attribute: false })
|
|
556
951
|
], ApexGrid.prototype, "data", void 0);
|
|
952
|
+
__decorate([
|
|
953
|
+
property({ attribute: false })
|
|
954
|
+
], ApexGrid.prototype, "rowId", void 0);
|
|
557
955
|
__decorate([
|
|
558
956
|
property({ type: Boolean, attribute: 'auto-generate' })
|
|
559
957
|
], ApexGrid.prototype, "autoGenerate", void 0);
|
|
@@ -575,9 +973,15 @@ __decorate([
|
|
|
575
973
|
__decorate([
|
|
576
974
|
property({ type: Boolean, attribute: 'show-export' })
|
|
577
975
|
], ApexGrid.prototype, "showExport", void 0);
|
|
976
|
+
__decorate([
|
|
977
|
+
property({ attribute: false })
|
|
978
|
+
], ApexGrid.prototype, "localeText", void 0);
|
|
578
979
|
__decorate([
|
|
579
980
|
property({ type: Boolean, attribute: 'column-reordering' })
|
|
580
981
|
], ApexGrid.prototype, "columnReordering", void 0);
|
|
982
|
+
__decorate([
|
|
983
|
+
property({ type: Boolean, attribute: 'column-separator', reflect: true })
|
|
984
|
+
], ApexGrid.prototype, "columnSeparator", void 0);
|
|
581
985
|
__decorate([
|
|
582
986
|
property({ attribute: false })
|
|
583
987
|
], ApexGrid.prototype, "editing", void 0);
|
|
@@ -587,6 +991,21 @@ __decorate([
|
|
|
587
991
|
__decorate([
|
|
588
992
|
property({ attribute: false })
|
|
589
993
|
], ApexGrid.prototype, "expansion", void 0);
|
|
994
|
+
__decorate([
|
|
995
|
+
property({ attribute: false })
|
|
996
|
+
], ApexGrid.prototype, "rowPinning", void 0);
|
|
997
|
+
__decorate([
|
|
998
|
+
property({ attribute: false })
|
|
999
|
+
], ApexGrid.prototype, "rowReordering", void 0);
|
|
1000
|
+
__decorate([
|
|
1001
|
+
property({ type: Boolean, reflect: true, attribute: 'coordinate-hints' })
|
|
1002
|
+
], ApexGrid.prototype, "coordinateHints", void 0);
|
|
1003
|
+
__decorate([
|
|
1004
|
+
property({ attribute: false })
|
|
1005
|
+
], ApexGrid.prototype, "columnMenu", void 0);
|
|
1006
|
+
__decorate([
|
|
1007
|
+
property({ attribute: false })
|
|
1008
|
+
], ApexGrid.prototype, "columnGroups", void 0);
|
|
590
1009
|
__decorate([
|
|
591
1010
|
property({ attribute: false })
|
|
592
1011
|
], ApexGrid.prototype, "tree", void 0);
|