apex-grid 3.2.0 → 3.3.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 +78 -0
- package/README.md +200 -52
- package/components/cell.d.ts +14 -1
- package/components/cell.js +48 -6
- package/components/cell.js.map +1 -1
- package/components/filter-row.d.ts +3 -6
- package/components/filter-row.js +79 -109
- package/components/filter-row.js.map +1 -1
- package/components/grid.d.ts +416 -77
- package/components/grid.js +398 -11
- 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 +135 -5
- 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/filter.d.ts +1 -1
- package/controllers/filter.js +16 -5
- package/controllers/filter.js.map +1 -1
- package/controllers/history.d.ts +86 -0
- package/controllers/history.js +118 -0
- package/controllers/history.js.map +1 -0
- package/controllers/navigation.d.ts +15 -0
- package/controllers/navigation.js +53 -0
- package/controllers/navigation.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/sort.js +9 -1
- 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 +4411 -886
- 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 +184 -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 +1 -1
- 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 +151 -0
- package/i18n/en.js +125 -0
- package/i18n/en.js.map +1 -0
- package/i18n/es.d.ts +18 -0
- package/i18n/es.js +125 -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/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 { localize as resolveLocaleText, } from '../i18n/index.js';
|
|
14
15
|
import { DEFAULT_COLUMN_CONFIG, PIPELINE } 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,25 @@ 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.#stateChangedListeners = 0;
|
|
72
|
+
this.#lastStateJson = null;
|
|
51
73
|
}
|
|
52
74
|
static get tagName() {
|
|
53
75
|
return GRID_TAG;
|
|
54
76
|
}
|
|
55
77
|
static { this.styles = gridStyles; }
|
|
56
78
|
static register() {
|
|
57
|
-
registerComponent(ApexGrid, ApexVirtualizer, ApexGridRow, ApexGridHeaderRow, ApexFilterRow, ApexGridPaginator, ApexGridToolbar);
|
|
79
|
+
registerComponent(ApexGrid, ApexVirtualizer, ApexGridRow, ApexGridGroupHeaderRow, ApexGridHeaderRow, ApexFilterRow, ApexGridPaginator, ApexGridToolbar);
|
|
58
80
|
}
|
|
59
81
|
createStateController() {
|
|
60
82
|
return new StateController(this);
|
|
61
83
|
}
|
|
84
|
+
localize(key, params, fallback) {
|
|
85
|
+
return resolveLocaleText(this.localeText, key, params, fallback);
|
|
86
|
+
}
|
|
62
87
|
get selectedRows() {
|
|
63
88
|
return this.stateController.selection.selectedRows();
|
|
64
89
|
}
|
|
@@ -83,6 +108,15 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
83
108
|
isRowSelected(row) {
|
|
84
109
|
return this.stateController.selection.isSelected(row);
|
|
85
110
|
}
|
|
111
|
+
get hasColumnGroups() {
|
|
112
|
+
if (!this.columnGroups?.length)
|
|
113
|
+
return false;
|
|
114
|
+
const ids = new Set(this.columnGroups.map((group) => group.id));
|
|
115
|
+
return this.columns.some((column) => !column.hidden && column.group && ids.has(column.group));
|
|
116
|
+
}
|
|
117
|
+
get columnGroupDepth() {
|
|
118
|
+
return this.hasColumnGroups ? 1 : 0;
|
|
119
|
+
}
|
|
86
120
|
get expandedRows() {
|
|
87
121
|
return this.stateController.expansion.expandedRows();
|
|
88
122
|
}
|
|
@@ -161,15 +195,19 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
161
195
|
return this.dataState.length;
|
|
162
196
|
}
|
|
163
197
|
get pageItems() {
|
|
198
|
+
const rowPin = this.stateController.rowPin;
|
|
199
|
+
const base = rowPin?.enabled && rowPin.hasPinnedRows
|
|
200
|
+
? this.dataState.filter((row) => !rowPin.isPinned(row))
|
|
201
|
+
: this.dataState;
|
|
164
202
|
if (!this.stateController.pagination.enabled)
|
|
165
|
-
return
|
|
203
|
+
return base;
|
|
166
204
|
if (this.pagination?.mode === 'remote')
|
|
167
|
-
return
|
|
205
|
+
return base;
|
|
168
206
|
const { page, pageSize } = this.stateController.pagination;
|
|
169
207
|
if (!pageSize)
|
|
170
|
-
return
|
|
208
|
+
return base;
|
|
171
209
|
const start = page * pageSize;
|
|
172
|
-
return
|
|
210
|
+
return base.slice(start, start + pageSize);
|
|
173
211
|
}
|
|
174
212
|
get page() {
|
|
175
213
|
return this.stateController.pagination.page;
|
|
@@ -227,13 +265,38 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
227
265
|
}
|
|
228
266
|
updated() {
|
|
229
267
|
this.setAttribute('role', this.stateController.tree.enabled ? 'treegrid' : 'grid');
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
this.setAttribute('aria-rowcount', String(headerRows + this.pageItems.length));
|
|
268
|
+
const pinned = this.stateController.rowPin.pinnedRows;
|
|
269
|
+
this.setAttribute('aria-rowcount', String(this.headerRowCount + pinned.top.length + this.pageItems.length + pinned.bottom.length));
|
|
233
270
|
const visibleColumns = this.columns.filter((column) => !column.hidden).length;
|
|
234
271
|
const extras = (this.stateController.selection.showCheckboxColumn ? 1 : 0) +
|
|
235
272
|
(this.stateController.expansion.showToggleColumn ? 1 : 0);
|
|
236
273
|
this.setAttribute('aria-colcount', String(visibleColumns + extras));
|
|
274
|
+
this.#emitStateChangedIfNeeded();
|
|
275
|
+
}
|
|
276
|
+
#stateChangedListeners;
|
|
277
|
+
#lastStateJson;
|
|
278
|
+
addEventListener(type, listener, options) {
|
|
279
|
+
if (type === 'stateChanged') {
|
|
280
|
+
this.#stateChangedListeners += 1;
|
|
281
|
+
this.#lastStateJson = this.hasUpdated ? JSON.stringify(this.getState()) : null;
|
|
282
|
+
}
|
|
283
|
+
super.addEventListener(type, listener, options);
|
|
284
|
+
}
|
|
285
|
+
removeEventListener(type, listener, options) {
|
|
286
|
+
if (type === 'stateChanged') {
|
|
287
|
+
this.#stateChangedListeners = Math.max(0, this.#stateChangedListeners - 1);
|
|
288
|
+
}
|
|
289
|
+
super.removeEventListener(type, listener, options);
|
|
290
|
+
}
|
|
291
|
+
#emitStateChangedIfNeeded() {
|
|
292
|
+
if (this.#stateChangedListeners === 0)
|
|
293
|
+
return;
|
|
294
|
+
const snapshot = this.getState();
|
|
295
|
+
const json = JSON.stringify(snapshot);
|
|
296
|
+
if (json === this.#lastStateJson)
|
|
297
|
+
return;
|
|
298
|
+
this.#lastStateJson = json;
|
|
299
|
+
this.emitEvent('stateChanged', { detail: { state: snapshot } });
|
|
237
300
|
}
|
|
238
301
|
firstUpdated() {
|
|
239
302
|
if (typeof getComputedStyle === 'function' && getComputedStyle(this).display !== 'grid') {
|
|
@@ -254,6 +317,201 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
254
317
|
sort(expressions) {
|
|
255
318
|
this.stateController.sorting.sort(expressions);
|
|
256
319
|
}
|
|
320
|
+
getState(options) {
|
|
321
|
+
const rowId = options?.rowId ?? this.rowId;
|
|
322
|
+
const pinned = this.stateController.rowPin.pinnedRows;
|
|
323
|
+
const manualOrder = this.stateController.rowReorder.getManualOrder();
|
|
324
|
+
return {
|
|
325
|
+
version: 1,
|
|
326
|
+
columns: serializeColumnLayout(this.columns),
|
|
327
|
+
sort: serializeSort(this.sortExpressions),
|
|
328
|
+
filter: serializeFilter(this.filterExpressions),
|
|
329
|
+
quickFilter: this.quickFilter,
|
|
330
|
+
pagination: { page: this.page, pageSize: this.pageSize },
|
|
331
|
+
selection: serializeRowRefs(this.selectedRows, this.data, rowId),
|
|
332
|
+
expansion: serializeRowRefs(this.expandedRows, this.data, rowId),
|
|
333
|
+
treeExpanded: serializeRowRefs([...this.stateController.tree.expanded], this.data, rowId),
|
|
334
|
+
treeExpandedKeys: [...this.stateController.tree.expandedKeys],
|
|
335
|
+
rowPinning: {
|
|
336
|
+
top: serializeRowRefs(pinned.top, this.data, rowId),
|
|
337
|
+
bottom: serializeRowRefs(pinned.bottom, this.data, rowId),
|
|
338
|
+
},
|
|
339
|
+
rowOrder: manualOrder ? serializeRowRefs(manualOrder, this.data, rowId) : null,
|
|
340
|
+
modules: this.stateController.serializeModuleState(),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
getSchema() {
|
|
344
|
+
return {
|
|
345
|
+
version: 1,
|
|
346
|
+
columns: this.columns.map((column) => columnSchema(column)),
|
|
347
|
+
capabilities: {
|
|
348
|
+
sort: {
|
|
349
|
+
directions: ['ascending', 'descending'],
|
|
350
|
+
multi: Boolean(this.sortConfiguration?.multiple),
|
|
351
|
+
},
|
|
352
|
+
filter: { operandsByType: operandsByType(this.columns) },
|
|
353
|
+
pagination: Boolean(this.pagination?.enabled),
|
|
354
|
+
selection: this.selection?.enabled ? (this.selection.mode ?? 'multiple') : false,
|
|
355
|
+
rowPinning: Boolean(this.rowPinning?.enabled),
|
|
356
|
+
rowReordering: Boolean(this.rowReordering?.enabled),
|
|
357
|
+
},
|
|
358
|
+
state: this.getState(),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
setState(state, options) {
|
|
362
|
+
const rowId = options?.rowId ?? this.rowId;
|
|
363
|
+
const strict = options?.strict ?? false;
|
|
364
|
+
const applied = [];
|
|
365
|
+
const warnings = [];
|
|
366
|
+
const warn = (message) => {
|
|
367
|
+
if (strict)
|
|
368
|
+
throw new Error(`[apex-grid] setState: ${message}`);
|
|
369
|
+
warnings.push(message);
|
|
370
|
+
};
|
|
371
|
+
const asArray = (value, label) => {
|
|
372
|
+
if (value === undefined)
|
|
373
|
+
return null;
|
|
374
|
+
if (!Array.isArray(value)) {
|
|
375
|
+
warn(`${label}: expected an array, got ${typeof value}; skipped`);
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
return value;
|
|
379
|
+
};
|
|
380
|
+
const resolveCounted = (refs, label) => {
|
|
381
|
+
const rows = resolveRowRefs(refs, this.data, rowId);
|
|
382
|
+
if (rows.length < refs.length) {
|
|
383
|
+
warn(`${label}: ${refs.length - rows.length} of ${refs.length} row(s) could not be resolved`);
|
|
384
|
+
}
|
|
385
|
+
return rows;
|
|
386
|
+
};
|
|
387
|
+
if (state.version !== undefined && state.version !== 1) {
|
|
388
|
+
warn(`unsupported snapshot version ${String(state.version)}; applying recognized slices best-effort`);
|
|
389
|
+
}
|
|
390
|
+
const columns = asArray(state.columns, 'columns');
|
|
391
|
+
if (columns) {
|
|
392
|
+
this.columns = applyColumnLayout(this.columns, columns);
|
|
393
|
+
applied.push('columns');
|
|
394
|
+
}
|
|
395
|
+
const sort = asArray(state.sort, 'sort');
|
|
396
|
+
if (sort) {
|
|
397
|
+
this.stateController.sorting.reset();
|
|
398
|
+
const valid = [];
|
|
399
|
+
for (const entry of sort) {
|
|
400
|
+
if (this.getColumn(entry.key)) {
|
|
401
|
+
valid.push(entry);
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
warn(`sort: unknown column "${entry.key}"; dropped`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (valid.length)
|
|
408
|
+
this.sort(valid);
|
|
409
|
+
applied.push('sort');
|
|
410
|
+
}
|
|
411
|
+
const filter = asArray(state.filter, 'filter');
|
|
412
|
+
if (filter) {
|
|
413
|
+
this.stateController.filtering.reset();
|
|
414
|
+
const expressions = deserializeFilter(filter, (key) => this.getColumn(key), (snapshot, reason) => warn(`filter: "${snapshot.key}" dropped (${reason})`));
|
|
415
|
+
if (expressions.length)
|
|
416
|
+
this.filter(expressions);
|
|
417
|
+
applied.push('filter');
|
|
418
|
+
}
|
|
419
|
+
if (state.quickFilter !== undefined) {
|
|
420
|
+
if (typeof state.quickFilter === 'string') {
|
|
421
|
+
this.quickFilter = state.quickFilter;
|
|
422
|
+
applied.push('quickFilter');
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
warn(`quickFilter: expected a string, got ${typeof state.quickFilter}; skipped`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (state.modules !== undefined) {
|
|
429
|
+
if (state.modules && typeof state.modules === 'object') {
|
|
430
|
+
this.stateController.restoreModuleState(state.modules);
|
|
431
|
+
applied.push('modules');
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
warn(`modules: expected an object, got ${typeof state.modules}; skipped`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (state.rowOrder !== undefined) {
|
|
438
|
+
if (state.rowOrder === null) {
|
|
439
|
+
this.stateController.rowReorder.restoreManualOrder(null);
|
|
440
|
+
applied.push('rowOrder');
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
const order = asArray(state.rowOrder, 'rowOrder');
|
|
444
|
+
if (order) {
|
|
445
|
+
if (this.sortExpressions.length) {
|
|
446
|
+
warn('rowOrder dropped: a manual order is mutually exclusive with an active sort');
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
this.stateController.rowReorder.restoreManualOrder(resolveCounted(order, 'rowOrder'));
|
|
450
|
+
}
|
|
451
|
+
applied.push('rowOrder');
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (state.treeExpanded !== undefined || state.treeExpandedKeys !== undefined) {
|
|
456
|
+
const refs = asArray(state.treeExpanded, 'treeExpanded') ?? [];
|
|
457
|
+
const keys = asArray(state.treeExpandedKeys, 'treeExpandedKeys') ?? [];
|
|
458
|
+
this.stateController.tree.restoreExpansion(resolveCounted(refs, 'treeExpanded'), keys);
|
|
459
|
+
applied.push('tree');
|
|
460
|
+
}
|
|
461
|
+
const expansion = asArray(state.expansion, 'expansion');
|
|
462
|
+
if (expansion) {
|
|
463
|
+
this.expandedRows = resolveCounted(expansion, 'expansion');
|
|
464
|
+
applied.push('expansion');
|
|
465
|
+
}
|
|
466
|
+
if (state.rowPinning !== undefined) {
|
|
467
|
+
const pinning = state.rowPinning;
|
|
468
|
+
if (pinning && typeof pinning === 'object') {
|
|
469
|
+
this.stateController.rowPin.restore(resolveCounted(asArray(pinning.top, 'rowPinning.top') ?? [], 'rowPinning.top'), resolveCounted(asArray(pinning.bottom, 'rowPinning.bottom') ?? [], 'rowPinning.bottom'));
|
|
470
|
+
applied.push('rowPinning');
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
warn(`rowPinning: expected an object, got ${typeof pinning}; skipped`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
const selection = asArray(state.selection, 'selection');
|
|
477
|
+
if (selection) {
|
|
478
|
+
this.selectedRows = resolveCounted(selection, 'selection');
|
|
479
|
+
applied.push('selection');
|
|
480
|
+
}
|
|
481
|
+
if (state.pagination !== undefined) {
|
|
482
|
+
const pagination = state.pagination;
|
|
483
|
+
if (pagination && typeof pagination === 'object') {
|
|
484
|
+
const { page, pageSize } = pagination;
|
|
485
|
+
if (pageSize !== undefined) {
|
|
486
|
+
if (typeof pageSize === 'number' && Number.isFinite(pageSize) && pageSize > 0) {
|
|
487
|
+
this.pageSize = pageSize;
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
warn(`pagination: invalid pageSize ${String(pageSize)}; ignored`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (page !== undefined) {
|
|
494
|
+
if (typeof page === 'number' && Number.isFinite(page)) {
|
|
495
|
+
const requested = Math.trunc(page);
|
|
496
|
+
this.page = requested;
|
|
497
|
+
if (this.page !== requested) {
|
|
498
|
+
warn(`pagination: page ${requested} out of range; clamped to ${this.page}`);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
warn(`pagination: invalid page ${String(page)}; ignored`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
applied.push('pagination');
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
warn(`pagination: expected an object, got ${typeof pagination}; skipped`);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
this.requestUpdate(PIPELINE);
|
|
512
|
+
const skipped = SET_STATE_SLICES.filter((slice) => !applied.includes(slice));
|
|
513
|
+
return { applied, skipped, warnings };
|
|
514
|
+
}
|
|
257
515
|
clearSort(key) {
|
|
258
516
|
this.stateController.sorting.reset(key);
|
|
259
517
|
this.requestUpdate(PIPELINE);
|
|
@@ -367,6 +625,33 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
367
625
|
editing.cancelCell();
|
|
368
626
|
}
|
|
369
627
|
}
|
|
628
|
+
get canUndo() {
|
|
629
|
+
return this.stateController.history.canUndo;
|
|
630
|
+
}
|
|
631
|
+
get canRedo() {
|
|
632
|
+
return this.stateController.history.canRedo;
|
|
633
|
+
}
|
|
634
|
+
undo() {
|
|
635
|
+
this.stateController.history.undo();
|
|
636
|
+
}
|
|
637
|
+
redo() {
|
|
638
|
+
this.stateController.history.redo();
|
|
639
|
+
}
|
|
640
|
+
clearHistory() {
|
|
641
|
+
this.stateController.history.clear();
|
|
642
|
+
}
|
|
643
|
+
pinRow(row, position = 'top') {
|
|
644
|
+
return this.stateController.rowPin.pinRow(row, position);
|
|
645
|
+
}
|
|
646
|
+
unpinRow(row) {
|
|
647
|
+
return this.stateController.rowPin.unpinRow(row);
|
|
648
|
+
}
|
|
649
|
+
get pinnedRows() {
|
|
650
|
+
return this.stateController.rowPin.pinnedRows;
|
|
651
|
+
}
|
|
652
|
+
moveRow(from, to, position = 'before') {
|
|
653
|
+
return this.stateController.rowReorder.moveRow(from, to, position);
|
|
654
|
+
}
|
|
370
655
|
exportToCSV(options = {}) {
|
|
371
656
|
const csv = buildCSV(this, options);
|
|
372
657
|
const filename = options.filename;
|
|
@@ -381,6 +666,9 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
381
666
|
get exportFormats() {
|
|
382
667
|
return [{ id: 'csv', label: 'Export CSV' }];
|
|
383
668
|
}
|
|
669
|
+
get toolbarActions() {
|
|
670
|
+
return [];
|
|
671
|
+
}
|
|
384
672
|
exportAs(formatId, options = {}) {
|
|
385
673
|
if (formatId === 'csv') {
|
|
386
674
|
this.exportToCSV(options);
|
|
@@ -438,6 +726,8 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
438
726
|
bodyPointerHandler(event) {
|
|
439
727
|
if (this.stateController.modules.size === 0)
|
|
440
728
|
return;
|
|
729
|
+
if (event.type === 'pointermove' && event.buttons === 0)
|
|
730
|
+
return;
|
|
441
731
|
const target = event.composedPath().find((el) => el instanceof ApexGridCell);
|
|
442
732
|
if (!target?.row)
|
|
443
733
|
return;
|
|
@@ -453,12 +743,25 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
453
743
|
originalEvent: event,
|
|
454
744
|
});
|
|
455
745
|
}
|
|
746
|
+
renderGroupHeaderRow() {
|
|
747
|
+
if (!this.hasColumnGroups)
|
|
748
|
+
return nothing;
|
|
749
|
+
return html `
|
|
750
|
+
<apex-grid-group-header-row
|
|
751
|
+
style=${styleMap(this.DOM.columnSizes)}
|
|
752
|
+
.columns=${this.DOM.displayColumns}
|
|
753
|
+
.pinOffsets=${this.DOM.pinOffsets}
|
|
754
|
+
.groups=${this.columnGroups ?? []}
|
|
755
|
+
></apex-grid-group-header-row>
|
|
756
|
+
`;
|
|
757
|
+
}
|
|
456
758
|
renderHeaderRow() {
|
|
457
759
|
return html `
|
|
458
760
|
<apex-grid-header-row
|
|
459
761
|
style=${styleMap(this.DOM.columnSizes)}
|
|
460
762
|
.columns=${this.DOM.displayColumns}
|
|
461
763
|
.pinOffsets=${this.DOM.pinOffsets}
|
|
764
|
+
.coordinateHints=${this.coordinateHints}
|
|
462
765
|
></apex-grid-header-row>
|
|
463
766
|
`;
|
|
464
767
|
}
|
|
@@ -470,19 +773,46 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
470
773
|
@click=${this.bodyClickHandler}
|
|
471
774
|
@keydown=${this.bodyKeydownHandler}
|
|
472
775
|
@pointerdown=${this.bodyPointerHandler}
|
|
473
|
-
@
|
|
776
|
+
@pointermove=${this.bodyPointerHandler}
|
|
474
777
|
@pointerup=${this.bodyPointerHandler}
|
|
475
778
|
></apex-virtualizer>
|
|
476
779
|
`;
|
|
477
780
|
}
|
|
781
|
+
get headerRowCount() {
|
|
782
|
+
return this.columnGroupDepth + 1 + (this.columns.some((column) => column.filter) ? 1 : 0);
|
|
783
|
+
}
|
|
784
|
+
renderPinnedTop() {
|
|
785
|
+
const rowPin = this.stateController.rowPin;
|
|
786
|
+
if (!rowPin.enabled)
|
|
787
|
+
return nothing;
|
|
788
|
+
const rows = rowPin.pinnedRows.top;
|
|
789
|
+
if (rows.length === 0)
|
|
790
|
+
return nothing;
|
|
791
|
+
return html `<div part="pinned-rows pinned-top">
|
|
792
|
+
${rows.map((data, i) => this.DOM.pinnedRowRenderer(data, i, this.headerRowCount))}
|
|
793
|
+
</div>`;
|
|
794
|
+
}
|
|
795
|
+
renderPinnedBottom() {
|
|
796
|
+
const rowPin = this.stateController.rowPin;
|
|
797
|
+
if (!rowPin.enabled)
|
|
798
|
+
return nothing;
|
|
799
|
+
const rows = rowPin.pinnedRows.bottom;
|
|
800
|
+
if (rows.length === 0)
|
|
801
|
+
return nothing;
|
|
802
|
+
const offset = this.headerRowCount + rowPin.pinnedRows.top.length + this.pageItems.length;
|
|
803
|
+
return html `<div part="pinned-rows pinned-bottom">
|
|
804
|
+
${rows.map((data, i) => this.DOM.pinnedRowRenderer(data, i, offset))}
|
|
805
|
+
</div>`;
|
|
806
|
+
}
|
|
478
807
|
renderFilterRow() {
|
|
479
808
|
return this.columns.some((column) => column.filter)
|
|
480
|
-
? html `<apex-filter-row
|
|
809
|
+
? html `<apex-filter-row></apex-filter-row>`
|
|
481
810
|
: nothing;
|
|
482
811
|
}
|
|
483
812
|
renderToolbar() {
|
|
484
|
-
if (!this.showQuickFilter && !this.showExport)
|
|
813
|
+
if (!this.showQuickFilter && !this.showExport && this.toolbarActions.length === 0) {
|
|
485
814
|
return nothing;
|
|
815
|
+
}
|
|
486
816
|
return html `<apex-grid-toolbar
|
|
487
817
|
.value=${this.quickFilter}
|
|
488
818
|
.showQuickFilter=${this.showQuickFilter}
|
|
@@ -512,15 +842,48 @@ export class ApexGrid extends EventEmitterBase {
|
|
|
512
842
|
${this.stateController.announcement}
|
|
513
843
|
</div>`;
|
|
514
844
|
}
|
|
845
|
+
renderRowDragGhost() {
|
|
846
|
+
const ghost = this.stateController.rowReorder.ghost;
|
|
847
|
+
if (!ghost)
|
|
848
|
+
return nothing;
|
|
849
|
+
return html `<div
|
|
850
|
+
part="row-drag-ghost"
|
|
851
|
+
style=${styleMap({
|
|
852
|
+
left: `${ghost.x}px`,
|
|
853
|
+
top: `${ghost.y}px`,
|
|
854
|
+
height: `${ghost.height}px`,
|
|
855
|
+
})}
|
|
856
|
+
>
|
|
857
|
+
<span part="row-drag-ghost-grip" aria-hidden="true">
|
|
858
|
+
<svg viewBox="0 0 16 16" width="16" height="16">
|
|
859
|
+
<circle cx="6" cy="3.5" r="1.25" />
|
|
860
|
+
<circle cx="10" cy="3.5" r="1.25" />
|
|
861
|
+
<circle cx="6" cy="8" r="1.25" />
|
|
862
|
+
<circle cx="10" cy="8" r="1.25" />
|
|
863
|
+
<circle cx="6" cy="12.5" r="1.25" />
|
|
864
|
+
<circle cx="10" cy="12.5" r="1.25" />
|
|
865
|
+
</svg>
|
|
866
|
+
</span>
|
|
867
|
+
${ghost.cells.map((cell) => html `<span
|
|
868
|
+
part="row-drag-ghost-cell"
|
|
869
|
+
style=${styleMap({ width: `${cell.width}px`, textAlign: cell.align })}
|
|
870
|
+
>${cell.text}</span
|
|
871
|
+
>`)}
|
|
872
|
+
</div>`;
|
|
873
|
+
}
|
|
515
874
|
render() {
|
|
516
875
|
return html `
|
|
517
876
|
${this.stateController.resizing.renderIndicator()}
|
|
518
877
|
${this.renderToolbar()}
|
|
878
|
+
${this.renderGroupHeaderRow()}
|
|
519
879
|
${this.renderHeaderRow()}
|
|
520
880
|
${this.renderFilterRow()}
|
|
881
|
+
${this.renderPinnedTop()}
|
|
521
882
|
${this.renderBody()}
|
|
883
|
+
${this.renderPinnedBottom()}
|
|
522
884
|
${this.renderPaginator()}
|
|
523
885
|
${this.renderLiveRegion()}
|
|
886
|
+
${this.renderRowDragGhost()}
|
|
524
887
|
`;
|
|
525
888
|
}
|
|
526
889
|
announce(message) {
|
|
@@ -554,6 +917,9 @@ __decorate([
|
|
|
554
917
|
__decorate([
|
|
555
918
|
property({ attribute: false })
|
|
556
919
|
], ApexGrid.prototype, "data", void 0);
|
|
920
|
+
__decorate([
|
|
921
|
+
property({ attribute: false })
|
|
922
|
+
], ApexGrid.prototype, "rowId", void 0);
|
|
557
923
|
__decorate([
|
|
558
924
|
property({ type: Boolean, attribute: 'auto-generate' })
|
|
559
925
|
], ApexGrid.prototype, "autoGenerate", void 0);
|
|
@@ -575,9 +941,15 @@ __decorate([
|
|
|
575
941
|
__decorate([
|
|
576
942
|
property({ type: Boolean, attribute: 'show-export' })
|
|
577
943
|
], ApexGrid.prototype, "showExport", void 0);
|
|
944
|
+
__decorate([
|
|
945
|
+
property({ attribute: false })
|
|
946
|
+
], ApexGrid.prototype, "localeText", void 0);
|
|
578
947
|
__decorate([
|
|
579
948
|
property({ type: Boolean, attribute: 'column-reordering' })
|
|
580
949
|
], ApexGrid.prototype, "columnReordering", void 0);
|
|
950
|
+
__decorate([
|
|
951
|
+
property({ type: Boolean, attribute: 'column-separator', reflect: true })
|
|
952
|
+
], ApexGrid.prototype, "columnSeparator", void 0);
|
|
581
953
|
__decorate([
|
|
582
954
|
property({ attribute: false })
|
|
583
955
|
], ApexGrid.prototype, "editing", void 0);
|
|
@@ -587,6 +959,21 @@ __decorate([
|
|
|
587
959
|
__decorate([
|
|
588
960
|
property({ attribute: false })
|
|
589
961
|
], ApexGrid.prototype, "expansion", void 0);
|
|
962
|
+
__decorate([
|
|
963
|
+
property({ attribute: false })
|
|
964
|
+
], ApexGrid.prototype, "rowPinning", void 0);
|
|
965
|
+
__decorate([
|
|
966
|
+
property({ attribute: false })
|
|
967
|
+
], ApexGrid.prototype, "rowReordering", void 0);
|
|
968
|
+
__decorate([
|
|
969
|
+
property({ type: Boolean, reflect: true, attribute: 'coordinate-hints' })
|
|
970
|
+
], ApexGrid.prototype, "coordinateHints", void 0);
|
|
971
|
+
__decorate([
|
|
972
|
+
property({ attribute: false })
|
|
973
|
+
], ApexGrid.prototype, "columnMenu", void 0);
|
|
974
|
+
__decorate([
|
|
975
|
+
property({ attribute: false })
|
|
976
|
+
], ApexGrid.prototype, "columnGroups", void 0);
|
|
590
977
|
__decorate([
|
|
591
978
|
property({ attribute: false })
|
|
592
979
|
], ApexGrid.prototype, "tree", void 0);
|