@ornery/ui-grid-vanilla 0.1.8 → 0.1.10
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/demo/index.html +3 -3
- package/demo/main.ts +1 -0
- package/dist/index.d.mts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +252 -22
- package/dist/index.mjs +252 -22
- package/package.json +2 -2
- package/src/grid-controller.ts +29 -2
- package/src/index.integration.test.ts +31 -0
- package/src/index.test.ts +1 -1
- package/src/ui-grid-standalone.element.ts +291 -27
package/demo/index.html
CHANGED
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
<p>
|
|
180
180
|
Familiar <code>gridOptions</code> and <code>onRegisterApi</code>, rebuilt as a
|
|
181
181
|
framework-neutral custom element with the Rust-backed pipeline, grouping, sorting,
|
|
182
|
-
filtering, and virtualization.
|
|
182
|
+
filtering, Excel-style column resizing, and virtualization.
|
|
183
183
|
</p>
|
|
184
184
|
</div>
|
|
185
185
|
<div class="grid-demo-actions">
|
|
@@ -210,8 +210,8 @@
|
|
|
210
210
|
<div class="grid-demo-toolbar">
|
|
211
211
|
<div><strong id="visible-rows-inline">0</strong> of <span id="total-rows-value">0</span> rows</div>
|
|
212
212
|
<p>
|
|
213
|
-
<code>gridOptions</code> compatibility layer: sorting, filtering, grouping,
|
|
214
|
-
and virtualized rendering.
|
|
213
|
+
<code>gridOptions</code> compatibility layer: sorting, filtering, grouping, column resizing,
|
|
214
|
+
templating, and virtualized rendering.
|
|
215
215
|
</p>
|
|
216
216
|
</div>
|
|
217
217
|
|
package/demo/main.ts
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -41,6 +41,7 @@ declare class VanillaGridController {
|
|
|
41
41
|
private expandedTreeRows;
|
|
42
42
|
private pinnedColumns;
|
|
43
43
|
private columnOrder;
|
|
44
|
+
private columnWidthOverrides;
|
|
44
45
|
private currentPage;
|
|
45
46
|
private pageSize;
|
|
46
47
|
private editingCell;
|
|
@@ -84,6 +85,11 @@ declare class VanillaGridController {
|
|
|
84
85
|
updateEditingValue(value: string): void;
|
|
85
86
|
commitCellEdit(): void;
|
|
86
87
|
cancelCellEdit(): void;
|
|
88
|
+
canResizeColumns(): boolean;
|
|
89
|
+
setColumnWidthOverride(columnName: string, widthPx: number): void;
|
|
90
|
+
/** Returns the grid-template-columns string as if `columnName` had the given width,
|
|
91
|
+
* without triggering a full refresh. Used for smooth drag-resize DOM updates. */
|
|
92
|
+
buildTemplateColumnsWithOverride(columnName: string, widthPx: number): string;
|
|
87
93
|
isGroupingEnabled(): boolean;
|
|
88
94
|
isSortingEnabled(): boolean;
|
|
89
95
|
isFilteringEnabled(): boolean;
|
|
@@ -169,6 +175,7 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
169
175
|
private draggedColumnName;
|
|
170
176
|
private dropTargetColumnName;
|
|
171
177
|
private scrollPosition;
|
|
178
|
+
private horizontalScrollPosition;
|
|
172
179
|
private scrollFrame;
|
|
173
180
|
private suppressScrollEvent;
|
|
174
181
|
private lastVirtualStartIndex;
|
|
@@ -178,6 +185,9 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
178
185
|
private benchmarkAverage;
|
|
179
186
|
private skipNextRender;
|
|
180
187
|
private dataFrame;
|
|
188
|
+
private pendingPatchedRowIds;
|
|
189
|
+
private pendingDataRefreshMode;
|
|
190
|
+
private lastScrollActivityAt;
|
|
181
191
|
static get observedAttributes(): string[];
|
|
182
192
|
get options(): GridOptions;
|
|
183
193
|
set options(value: GridOptions);
|
|
@@ -232,6 +242,8 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
232
242
|
set enablePinning(value: boolean);
|
|
233
243
|
get enableColumnMoving(): boolean;
|
|
234
244
|
set enableColumnMoving(value: boolean);
|
|
245
|
+
get enableColumnResizing(): boolean;
|
|
246
|
+
set enableColumnResizing(value: boolean);
|
|
235
247
|
get enableCellEdit(): boolean;
|
|
236
248
|
set enableCellEdit(value: boolean);
|
|
237
249
|
get enableCellEditOnFocus(): boolean;
|
|
@@ -273,6 +285,7 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
273
285
|
* (the fresh innerHTML already reflects the latest data).
|
|
274
286
|
*/
|
|
275
287
|
setData(rows: GridRecord[]): void;
|
|
288
|
+
private flushPendingDataRefresh;
|
|
276
289
|
private patchCells;
|
|
277
290
|
connectedCallback(): void;
|
|
278
291
|
disconnectedCallback(): void;
|
|
@@ -291,16 +304,20 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
291
304
|
private render;
|
|
292
305
|
private renderHeaderCell;
|
|
293
306
|
private renderFilterCell;
|
|
307
|
+
private measureAutoColumnWidth;
|
|
294
308
|
private renderDisplayItem;
|
|
295
309
|
private renderBodyCell;
|
|
296
310
|
private renderPagination;
|
|
297
311
|
private renderSlotRegistry;
|
|
298
312
|
private renderCellTemplate;
|
|
313
|
+
private renderCellTemplateFromMarkup;
|
|
299
314
|
private renderExpandableTemplate;
|
|
300
315
|
private getTemplateMarkup;
|
|
301
316
|
private interpolateTemplate;
|
|
302
317
|
private resolveTemplateValue;
|
|
303
318
|
private rowIndexFor;
|
|
319
|
+
private classifyDataRefresh;
|
|
320
|
+
private getRenderedDisplayWindow;
|
|
304
321
|
private cellSlotName;
|
|
305
322
|
private downloadCsv;
|
|
306
323
|
private renderControlIcon;
|
package/dist/index.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ declare class VanillaGridController {
|
|
|
41
41
|
private expandedTreeRows;
|
|
42
42
|
private pinnedColumns;
|
|
43
43
|
private columnOrder;
|
|
44
|
+
private columnWidthOverrides;
|
|
44
45
|
private currentPage;
|
|
45
46
|
private pageSize;
|
|
46
47
|
private editingCell;
|
|
@@ -84,6 +85,11 @@ declare class VanillaGridController {
|
|
|
84
85
|
updateEditingValue(value: string): void;
|
|
85
86
|
commitCellEdit(): void;
|
|
86
87
|
cancelCellEdit(): void;
|
|
88
|
+
canResizeColumns(): boolean;
|
|
89
|
+
setColumnWidthOverride(columnName: string, widthPx: number): void;
|
|
90
|
+
/** Returns the grid-template-columns string as if `columnName` had the given width,
|
|
91
|
+
* without triggering a full refresh. Used for smooth drag-resize DOM updates. */
|
|
92
|
+
buildTemplateColumnsWithOverride(columnName: string, widthPx: number): string;
|
|
87
93
|
isGroupingEnabled(): boolean;
|
|
88
94
|
isSortingEnabled(): boolean;
|
|
89
95
|
isFilteringEnabled(): boolean;
|
|
@@ -169,6 +175,7 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
169
175
|
private draggedColumnName;
|
|
170
176
|
private dropTargetColumnName;
|
|
171
177
|
private scrollPosition;
|
|
178
|
+
private horizontalScrollPosition;
|
|
172
179
|
private scrollFrame;
|
|
173
180
|
private suppressScrollEvent;
|
|
174
181
|
private lastVirtualStartIndex;
|
|
@@ -178,6 +185,9 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
178
185
|
private benchmarkAverage;
|
|
179
186
|
private skipNextRender;
|
|
180
187
|
private dataFrame;
|
|
188
|
+
private pendingPatchedRowIds;
|
|
189
|
+
private pendingDataRefreshMode;
|
|
190
|
+
private lastScrollActivityAt;
|
|
181
191
|
static get observedAttributes(): string[];
|
|
182
192
|
get options(): GridOptions;
|
|
183
193
|
set options(value: GridOptions);
|
|
@@ -232,6 +242,8 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
232
242
|
set enablePinning(value: boolean);
|
|
233
243
|
get enableColumnMoving(): boolean;
|
|
234
244
|
set enableColumnMoving(value: boolean);
|
|
245
|
+
get enableColumnResizing(): boolean;
|
|
246
|
+
set enableColumnResizing(value: boolean);
|
|
235
247
|
get enableCellEdit(): boolean;
|
|
236
248
|
set enableCellEdit(value: boolean);
|
|
237
249
|
get enableCellEditOnFocus(): boolean;
|
|
@@ -273,6 +285,7 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
273
285
|
* (the fresh innerHTML already reflects the latest data).
|
|
274
286
|
*/
|
|
275
287
|
setData(rows: GridRecord[]): void;
|
|
288
|
+
private flushPendingDataRefresh;
|
|
276
289
|
private patchCells;
|
|
277
290
|
connectedCallback(): void;
|
|
278
291
|
disconnectedCallback(): void;
|
|
@@ -291,16 +304,20 @@ declare class UiGridStandaloneElement extends HTMLElement {
|
|
|
291
304
|
private render;
|
|
292
305
|
private renderHeaderCell;
|
|
293
306
|
private renderFilterCell;
|
|
307
|
+
private measureAutoColumnWidth;
|
|
294
308
|
private renderDisplayItem;
|
|
295
309
|
private renderBodyCell;
|
|
296
310
|
private renderPagination;
|
|
297
311
|
private renderSlotRegistry;
|
|
298
312
|
private renderCellTemplate;
|
|
313
|
+
private renderCellTemplateFromMarkup;
|
|
299
314
|
private renderExpandableTemplate;
|
|
300
315
|
private getTemplateMarkup;
|
|
301
316
|
private interpolateTemplate;
|
|
302
317
|
private resolveTemplateValue;
|
|
303
318
|
private rowIndexFor;
|
|
319
|
+
private classifyDataRefresh;
|
|
320
|
+
private getRenderedDisplayWindow;
|
|
304
321
|
private cellSlotName;
|
|
305
322
|
private downloadCsv;
|
|
306
323
|
private renderControlIcon;
|
package/dist/index.js
CHANGED
|
@@ -55,6 +55,7 @@ var VanillaGridController = class {
|
|
|
55
55
|
expandedTreeRows = {};
|
|
56
56
|
pinnedColumns = {};
|
|
57
57
|
columnOrder = [];
|
|
58
|
+
columnWidthOverrides = {};
|
|
58
59
|
currentPage = 1;
|
|
59
60
|
pageSize = 0;
|
|
60
61
|
editingCell = null;
|
|
@@ -463,6 +464,24 @@ var VanillaGridController = class {
|
|
|
463
464
|
});
|
|
464
465
|
this.refresh();
|
|
465
466
|
}
|
|
467
|
+
canResizeColumns() {
|
|
468
|
+
return this.options.enableColumnResizing !== false;
|
|
469
|
+
}
|
|
470
|
+
setColumnWidthOverride(columnName, widthPx) {
|
|
471
|
+
const nextWidth = `${Math.max(88, Math.round(widthPx))}px`;
|
|
472
|
+
this.columnWidthOverrides = { ...this.columnWidthOverrides, [columnName]: nextWidth };
|
|
473
|
+
this.refresh();
|
|
474
|
+
}
|
|
475
|
+
/** Returns the grid-template-columns string as if `columnName` had the given width,
|
|
476
|
+
* without triggering a full refresh. Used for smooth drag-resize DOM updates. */
|
|
477
|
+
buildTemplateColumnsWithOverride(columnName, widthPx) {
|
|
478
|
+
const widthStr = `${Math.max(88, Math.round(widthPx))}px`;
|
|
479
|
+
return buildGridTemplateColumns(
|
|
480
|
+
this.visibleColumns.map(
|
|
481
|
+
(c) => c.name === columnName ? { ...c, width: widthStr } : c
|
|
482
|
+
)
|
|
483
|
+
);
|
|
484
|
+
}
|
|
466
485
|
isGroupingEnabled() {
|
|
467
486
|
return (0, import_ui_grid_core.isGridGroupingEnabled)(this.options);
|
|
468
487
|
}
|
|
@@ -581,9 +600,13 @@ var VanillaGridController = class {
|
|
|
581
600
|
}
|
|
582
601
|
refresh() {
|
|
583
602
|
const orderedColumns = orderVisibleColumns(this.options.columnDefs, this.columnOrder);
|
|
603
|
+
const applyWidthOverrides = (columns) => columns.map((col) => {
|
|
604
|
+
const override = this.columnWidthOverrides[col.name];
|
|
605
|
+
return override == null ? col : { ...col, width: override };
|
|
606
|
+
});
|
|
584
607
|
const pinnedEntries = Object.entries(this.pinnedColumns);
|
|
585
608
|
if (pinnedEntries.length === 0) {
|
|
586
|
-
this.visibleColumns = orderedColumns;
|
|
609
|
+
this.visibleColumns = applyWidthOverrides(orderedColumns);
|
|
587
610
|
} else {
|
|
588
611
|
const byName = new Map(orderedColumns.map((column) => [column.name, column]));
|
|
589
612
|
const pinnedLeft = pinnedEntries.filter((entry) => entry[1] === "left").map((entry) => byName.get(entry[0])).filter((column) => column !== void 0);
|
|
@@ -591,7 +614,7 @@ var VanillaGridController = class {
|
|
|
591
614
|
const middleColumns = orderedColumns.filter(
|
|
592
615
|
(column) => this.pinnedColumns[column.name] === void 0
|
|
593
616
|
);
|
|
594
|
-
this.visibleColumns = [...pinnedLeft, ...middleColumns, ...pinnedRight];
|
|
617
|
+
this.visibleColumns = applyWidthOverrides([...pinnedLeft, ...middleColumns, ...pinnedRight]);
|
|
595
618
|
}
|
|
596
619
|
this.pipeline = import_ui_grid_core.defaultGridEngine.buildPipeline({
|
|
597
620
|
options: this.options,
|
|
@@ -779,6 +802,7 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
779
802
|
draggedColumnName = null;
|
|
780
803
|
dropTargetColumnName = null;
|
|
781
804
|
scrollPosition = 0;
|
|
805
|
+
horizontalScrollPosition = 0;
|
|
782
806
|
scrollFrame = null;
|
|
783
807
|
suppressScrollEvent = false;
|
|
784
808
|
lastVirtualStartIndex = -1;
|
|
@@ -788,6 +812,9 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
788
812
|
benchmarkAverage = "\u2014";
|
|
789
813
|
skipNextRender = false;
|
|
790
814
|
dataFrame = null;
|
|
815
|
+
pendingPatchedRowIds = null;
|
|
816
|
+
pendingDataRefreshMode = null;
|
|
817
|
+
lastScrollActivityAt = 0;
|
|
791
818
|
static get observedAttributes() {
|
|
792
819
|
return [
|
|
793
820
|
// Scalar attributes
|
|
@@ -833,10 +860,14 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
833
860
|
];
|
|
834
861
|
}
|
|
835
862
|
get options() {
|
|
836
|
-
|
|
863
|
+
if (this.activeOptions !== null) {
|
|
864
|
+
return this.buildEffectiveOptions(this.activeOptions);
|
|
865
|
+
}
|
|
866
|
+
return {
|
|
837
867
|
id: "__ui-grid-pending__",
|
|
838
868
|
data: [],
|
|
839
|
-
columnDefs: []
|
|
869
|
+
columnDefs: [],
|
|
870
|
+
...this.attributeOptions
|
|
840
871
|
};
|
|
841
872
|
}
|
|
842
873
|
set options(value) {
|
|
@@ -907,6 +938,9 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
907
938
|
const enableColumnMoving = this.parseBooleanAttribute("enable-column-moving");
|
|
908
939
|
if (enableColumnMoving !== void 0)
|
|
909
940
|
this.attributeOptions.enableColumnMoving = enableColumnMoving;
|
|
941
|
+
const enableColumnResizing = this.parseBooleanAttribute("enable-column-resizing");
|
|
942
|
+
if (enableColumnResizing !== void 0)
|
|
943
|
+
this.attributeOptions.enableColumnResizing = enableColumnResizing;
|
|
910
944
|
const enableCellEdit = this.parseBooleanAttribute("enable-cell-edit");
|
|
911
945
|
if (enableCellEdit !== void 0) this.attributeOptions.enableCellEdit = enableCellEdit;
|
|
912
946
|
const enableCellEditOnFocus = this.parseBooleanAttribute("enable-cell-edit-on-focus");
|
|
@@ -959,8 +993,15 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
959
993
|
);
|
|
960
994
|
if (paginationPageSizes !== void 0)
|
|
961
995
|
this.attributeOptions.paginationPageSizes = paginationPageSizes;
|
|
962
|
-
if (this.activeOptions) {
|
|
996
|
+
if (this.activeOptions !== null) {
|
|
963
997
|
this.ensureController(this.buildEffectiveOptions(this.activeOptions));
|
|
998
|
+
} else {
|
|
999
|
+
this.ensureController({
|
|
1000
|
+
id: "__ui-grid-pending__",
|
|
1001
|
+
data: [],
|
|
1002
|
+
columnDefs: [],
|
|
1003
|
+
...this.attributeOptions
|
|
1004
|
+
});
|
|
964
1005
|
}
|
|
965
1006
|
}
|
|
966
1007
|
parseBooleanAttribute(name) {
|
|
@@ -1148,6 +1189,13 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1148
1189
|
this.activeOptions = { ...this.activeOptions, enableColumnMoving: value };
|
|
1149
1190
|
this.ensureController(this.buildEffectiveOptions(this.activeOptions));
|
|
1150
1191
|
}
|
|
1192
|
+
get enableColumnResizing() {
|
|
1193
|
+
return this.options.enableColumnResizing ?? true;
|
|
1194
|
+
}
|
|
1195
|
+
set enableColumnResizing(value) {
|
|
1196
|
+
this.activeOptions = { ...this.activeOptions, enableColumnResizing: value };
|
|
1197
|
+
this.ensureController(this.buildEffectiveOptions(this.activeOptions));
|
|
1198
|
+
}
|
|
1151
1199
|
get enableCellEdit() {
|
|
1152
1200
|
return this.options.enableCellEdit ?? false;
|
|
1153
1201
|
}
|
|
@@ -1272,18 +1320,49 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1272
1320
|
if (!controller) {
|
|
1273
1321
|
return;
|
|
1274
1322
|
}
|
|
1323
|
+
const previousSnapshot = this.snapshot;
|
|
1275
1324
|
this.skipNextRender = true;
|
|
1276
1325
|
controller.refreshData(rows);
|
|
1277
1326
|
this.skipNextRender = false;
|
|
1327
|
+
const { mode, changedRowIds } = this.classifyDataRefresh(previousSnapshot, this.snapshot);
|
|
1328
|
+
if (mode === null) {
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
this.pendingDataRefreshMode = mode;
|
|
1332
|
+
this.pendingPatchedRowIds = changedRowIds;
|
|
1278
1333
|
if (this.dataFrame !== null) {
|
|
1279
1334
|
cancelAnimationFrame(this.dataFrame);
|
|
1280
1335
|
}
|
|
1281
1336
|
this.dataFrame = requestAnimationFrame(() => {
|
|
1282
|
-
this.
|
|
1283
|
-
this.patchCells();
|
|
1337
|
+
this.flushPendingDataRefresh();
|
|
1284
1338
|
});
|
|
1285
1339
|
}
|
|
1286
|
-
|
|
1340
|
+
flushPendingDataRefresh() {
|
|
1341
|
+
this.dataFrame = null;
|
|
1342
|
+
const mode = this.pendingDataRefreshMode;
|
|
1343
|
+
if (mode === null) {
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
if (Date.now() - this.lastScrollActivityAt < 80) {
|
|
1347
|
+
this.dataFrame = requestAnimationFrame(() => {
|
|
1348
|
+
this.flushPendingDataRefresh();
|
|
1349
|
+
});
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
const changedRowIds = this.pendingPatchedRowIds;
|
|
1353
|
+
this.pendingDataRefreshMode = null;
|
|
1354
|
+
this.pendingPatchedRowIds = null;
|
|
1355
|
+
if (mode === "patch") {
|
|
1356
|
+
this.patchCells(changedRowIds ?? void 0);
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
if (mode === "virtual") {
|
|
1360
|
+
this.renderVirtualBody();
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
this.render();
|
|
1364
|
+
}
|
|
1365
|
+
patchCells(changedRowIds) {
|
|
1287
1366
|
const snapshot = this.snapshot;
|
|
1288
1367
|
if (!snapshot) {
|
|
1289
1368
|
return;
|
|
@@ -1293,30 +1372,37 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1293
1372
|
return;
|
|
1294
1373
|
}
|
|
1295
1374
|
const rowMap = /* @__PURE__ */ new Map();
|
|
1375
|
+
const rowIndexMap = /* @__PURE__ */ new Map();
|
|
1296
1376
|
for (const row of snapshot.pipeline.visibleRows) {
|
|
1297
1377
|
rowMap.set(row.id, row);
|
|
1378
|
+
rowIndexMap.set(row.id, rowIndexMap.size);
|
|
1298
1379
|
}
|
|
1299
1380
|
const colMap = /* @__PURE__ */ new Map();
|
|
1381
|
+
const templateMarkupMap = /* @__PURE__ */ new Map();
|
|
1300
1382
|
for (const col of snapshot.visibleColumns) {
|
|
1301
1383
|
colMap.set(col.name, col);
|
|
1384
|
+
templateMarkupMap.set(col.name, this.getTemplateMarkup(this.cellSlotName(col)));
|
|
1302
1385
|
}
|
|
1303
1386
|
const cells = root.querySelectorAll("[data-row][data-column]");
|
|
1304
1387
|
for (const cell of cells) {
|
|
1305
1388
|
const rowId = cell.dataset["row"];
|
|
1306
1389
|
const colName = cell.dataset["column"];
|
|
1307
1390
|
if (!rowId || !colName) continue;
|
|
1391
|
+
if (changedRowIds && !changedRowIds.has(rowId)) continue;
|
|
1308
1392
|
const row = rowMap.get(rowId);
|
|
1309
1393
|
const column = colMap.get(colName);
|
|
1310
1394
|
if (!row || !column) continue;
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
const
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1395
|
+
if (cell.classList.contains("cell-editing")) continue;
|
|
1396
|
+
const cellContent = cell.querySelector(".cell-content");
|
|
1397
|
+
if (!cellContent) continue;
|
|
1398
|
+
const newContent = this.renderCellTemplateFromMarkup(
|
|
1399
|
+
row,
|
|
1400
|
+
column,
|
|
1401
|
+
rowIndexMap.get(rowId) ?? 0,
|
|
1402
|
+
templateMarkupMap.get(colName) ?? null
|
|
1403
|
+
);
|
|
1404
|
+
if (cellContent.innerHTML !== newContent) {
|
|
1405
|
+
cellContent.innerHTML = newContent;
|
|
1320
1406
|
}
|
|
1321
1407
|
}
|
|
1322
1408
|
}
|
|
@@ -1530,11 +1616,51 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1530
1616
|
this.controller.setPageSize(value);
|
|
1531
1617
|
}
|
|
1532
1618
|
});
|
|
1619
|
+
root.addEventListener("mousedown", (event) => {
|
|
1620
|
+
const target = event.target;
|
|
1621
|
+
if (!target || !this.controller) return;
|
|
1622
|
+
const resizer = target.closest(".column-resizer[data-column]");
|
|
1623
|
+
if (!resizer || !this.controller.canResizeColumns()) return;
|
|
1624
|
+
const columnName = resizer.dataset["column"];
|
|
1625
|
+
if (!columnName) return;
|
|
1626
|
+
const headerCell = resizer.closest(".header-cell");
|
|
1627
|
+
if (!headerCell) return;
|
|
1628
|
+
event.preventDefault();
|
|
1629
|
+
event.stopPropagation();
|
|
1630
|
+
const startX = event.clientX;
|
|
1631
|
+
const startWidth = headerCell.getBoundingClientRect().width;
|
|
1632
|
+
let lastWidth = startWidth;
|
|
1633
|
+
const handleMove = (moveEvent) => {
|
|
1634
|
+
lastWidth = Math.max(88, startWidth + (moveEvent.clientX - startX));
|
|
1635
|
+
const newTemplate = this.controller.buildTemplateColumnsWithOverride(columnName, lastWidth);
|
|
1636
|
+
const root2 = this.shadowRoot ?? this;
|
|
1637
|
+
root2.querySelectorAll(".header-grid, .filter-grid, .body-grid").forEach((el) => {
|
|
1638
|
+
el.style.gridTemplateColumns = newTemplate;
|
|
1639
|
+
});
|
|
1640
|
+
};
|
|
1641
|
+
const handleUp = () => {
|
|
1642
|
+
window.removeEventListener("mousemove", handleMove);
|
|
1643
|
+
window.removeEventListener("mouseup", handleUp);
|
|
1644
|
+
this.controller.setColumnWidthOverride(columnName, lastWidth);
|
|
1645
|
+
};
|
|
1646
|
+
window.addEventListener("mousemove", handleMove);
|
|
1647
|
+
window.addEventListener("mouseup", handleUp);
|
|
1648
|
+
});
|
|
1533
1649
|
root.addEventListener("dblclick", (event) => {
|
|
1534
1650
|
const target = event.target;
|
|
1535
1651
|
if (!target || !this.controller) {
|
|
1536
1652
|
return;
|
|
1537
1653
|
}
|
|
1654
|
+
const resizer = target.closest(".column-resizer[data-column]");
|
|
1655
|
+
if (resizer && this.controller.canResizeColumns()) {
|
|
1656
|
+
const columnName2 = resizer.dataset["column"];
|
|
1657
|
+
if (columnName2) {
|
|
1658
|
+
event.preventDefault();
|
|
1659
|
+
event.stopPropagation();
|
|
1660
|
+
this.controller.setColumnWidthOverride(columnName2, this.measureAutoColumnWidth(columnName2));
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1538
1664
|
const cell = target.closest(".body-cell");
|
|
1539
1665
|
if (!cell) {
|
|
1540
1666
|
return;
|
|
@@ -1668,7 +1794,9 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1668
1794
|
if (!target?.classList.contains("grid-table") || this.suppressScrollEvent) {
|
|
1669
1795
|
return;
|
|
1670
1796
|
}
|
|
1797
|
+
this.lastScrollActivityAt = Date.now();
|
|
1671
1798
|
this.scrollPosition = target.scrollTop;
|
|
1799
|
+
this.horizontalScrollPosition = target.scrollLeft;
|
|
1672
1800
|
if (!this.snapshot?.pipeline.virtualizationEnabled) {
|
|
1673
1801
|
return;
|
|
1674
1802
|
}
|
|
@@ -1749,6 +1877,7 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1749
1877
|
const previousGridTable = root.querySelector(".grid-table");
|
|
1750
1878
|
if (previousGridTable && !this.suppressScrollEvent) {
|
|
1751
1879
|
this.scrollPosition = previousGridTable.scrollTop;
|
|
1880
|
+
this.horizontalScrollPosition = previousGridTable.scrollLeft;
|
|
1752
1881
|
}
|
|
1753
1882
|
if (!snapshot) {
|
|
1754
1883
|
root.innerHTML = `<style>${import_ui_grid_core2.GRID_CORE_CSS}</style><section class="grid-shell ui-grid-shell"><div class="empty-state ui-grid-no-row-overlay"><strong>No grid options provided.</strong></div></section>`;
|
|
@@ -1795,12 +1924,18 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1795
1924
|
const bodyContent = itemsToRender.map((item, index) => this.renderDisplayItem(item, startIndex + index)).join("");
|
|
1796
1925
|
const body = snapshot.pipeline.displayItems.length > 0 ? virtualizationEnabled ? `<div class="grid-virtual-spacer" style="height:${totalVirtualHeight}px"><div class="body-grid ui-grid-canvas grid-virtual-body" style="grid-template-columns:${templateColumns};top:${virtualOffset}px">${bodyContent}</div></div>` : `<div class="body-grid ui-grid-canvas" style="grid-template-columns:${templateColumns}">${bodyContent}</div>` : `<div class="empty-state ui-grid-no-row-overlay"><strong>${escapeHtml(options.emptyMessage ?? labels.emptyHeading)}</strong><p>${escapeHtml(labels.emptyDescription)}</p></div>`;
|
|
1797
1926
|
const pagination = paginationEnabled && showPagination ? this.renderPagination(snapshot) : "";
|
|
1798
|
-
const
|
|
1927
|
+
const hasViewportScroll = virtualizationEnabled || options.viewportHeight !== void 0;
|
|
1928
|
+
const gridTableStyle = `${hasViewportScroll ? `height:${viewportHeight}px;overflow-y:auto;` : ""}--ui-grid-header-sticky-top:${headerStickyTop}px;`;
|
|
1799
1929
|
root.innerHTML = `<style>${import_ui_grid_core2.GRID_CORE_CSS}</style>${slotRegistry}<section class="grid-frame ui-grid" role="grid" aria-label="${escapeHtml(options.title ?? "Data grid")}"><div class="grid-table ui-grid-contents-wrapper" style="${gridTableStyle}"><div class="header-grid ui-grid-header ui-grid-header-canvas" style="grid-template-columns:${templateColumns}">${header}</div>${filterRow}${body}</div>${pagination}</section>`;
|
|
1800
1930
|
const gridTable = root.querySelector(".grid-table");
|
|
1801
|
-
if (gridTable && this.scrollPosition > 0
|
|
1931
|
+
if (gridTable && (this.scrollPosition > 0 || this.horizontalScrollPosition > 0)) {
|
|
1802
1932
|
this.suppressScrollEvent = true;
|
|
1803
|
-
|
|
1933
|
+
if (this.scrollPosition > 0) {
|
|
1934
|
+
gridTable.scrollTop = this.scrollPosition;
|
|
1935
|
+
}
|
|
1936
|
+
if (this.horizontalScrollPosition > 0) {
|
|
1937
|
+
gridTable.scrollLeft = this.horizontalScrollPosition;
|
|
1938
|
+
}
|
|
1804
1939
|
requestAnimationFrame(() => {
|
|
1805
1940
|
this.suppressScrollEvent = false;
|
|
1806
1941
|
});
|
|
@@ -1851,8 +1986,10 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1851
1986
|
const sortIconKey = sortDirection === import_ui_grid_core2.SORT_DIRECTIONS.asc ? "sortAsc" : sortDirection === import_ui_grid_core2.SORT_DIRECTIONS.desc ? "sortDesc" : "sortNone";
|
|
1852
1987
|
const draggable = (0, import_ui_grid_core2.canGridMoveColumns)(options) ? 'draggable="true"' : "";
|
|
1853
1988
|
const pinLabel = isPinned ? this.snapshot?.labels.unpin ?? "Unpin" : this.snapshot?.labels.pinColumn ?? "Pin";
|
|
1989
|
+
const canResize = controller.canResizeColumns();
|
|
1854
1990
|
const headerValue = escapeHtml((0, import_ui_grid_core2.formatGridHeaderDisplayValue)((0, import_ui_grid_core2.buildGridHeaderContext)(column)));
|
|
1855
|
-
|
|
1991
|
+
const resizerHtml = canResize ? `<button type="button" class="column-resizer" data-action="resize" data-column="${escapeHtml(column.name)}" aria-label="Resize ${escapeHtml(headerValue)} column" title="Drag to resize, double-click to auto fit"></button>` : "";
|
|
1992
|
+
return `<div class="${classes}" data-column="${escapeHtml(column.name)}" ${draggable} style="${stickyStyle}"><span class="header-label">${headerValue}</span><span class="header-actions">${sortEnabled ? `<button type="button" class="header-action" data-action="sort" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(sortLabel)}" ${canSort ? "" : "disabled"}>${this.renderControlIcon(sortIconKey)}<span class="sr-only">${escapeHtml(sortLabel)}</span></button>` : ""}${groupingEnabled ? `<button type="button" class="chip-action${controller.isColumnGrouped(column) ? " chip-action-active" : ""}" data-action="group" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(groupingLabel)}" ${canGroup ? "" : "disabled"}>${this.renderControlIcon("group")}<span class="sr-only">${escapeHtml(groupingLabel)}</span></button>` : ""}${canPin ? `<div class="pin-control${this.openPinMenuColumn === column.name ? " pin-control-open" : ""}"><button type="button" class="chip-action pin-trigger${isPinned ? " chip-action-active" : ""}" data-action="pin-trigger" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(pinLabel)}">${this.renderControlIcon("pin")}<span class="sr-only">${escapeHtml(pinLabel)}</span></button><div class="pin-menu" role="menu" aria-label="${escapeHtml(pinLabel)}"><button type="button" class="pin-menu-action" data-action="pin-left" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinLeft ?? "Pin left")}">${this.renderIconWithClass("control-icon", "pinLeft")}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinLeft ?? "Pin left")}</span></button><button type="button" class="pin-menu-action" data-action="pin-right" data-column="${escapeHtml(column.name)}" aria-label="${escapeHtml(this.snapshot?.labels.pinRight ?? "Pin right")}">${this.renderIconWithClass("control-icon", "pinRight")}<span class="sr-only">${escapeHtml(this.snapshot?.labels.pinRight ?? "Pin right")}</span></button></div></div>` : ""}</span>${resizerHtml}</div>`;
|
|
1856
1993
|
}
|
|
1857
1994
|
renderFilterCell(column) {
|
|
1858
1995
|
const value = this.snapshot?.activeFilters[column.name] ?? "";
|
|
@@ -1868,6 +2005,23 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1868
2005
|
const stickyStyle = pinOffset ? `${pinOffset.side}:${pinOffset.offset};` : "";
|
|
1869
2006
|
return `<label class="${classes}" style="${stickyStyle}"><input class="ui-grid-filter-input" data-role="filter" data-column="${escapeHtml(column.name)}" placeholder="${escapeHtml(controller.filterPlaceholder(column))}" value="${escapeHtml(value)}" ${canFilter ? "" : "disabled"}></label>`;
|
|
1870
2007
|
}
|
|
2008
|
+
measureAutoColumnWidth(columnName) {
|
|
2009
|
+
const root = this.shadowRoot;
|
|
2010
|
+
if (root == null) return 176;
|
|
2011
|
+
const escaped = CSS.escape ? CSS.escape(columnName) : columnName.replace(/([\\".#:[\](){}+~> ])/g, "\\$1");
|
|
2012
|
+
const selectors = [
|
|
2013
|
+
`.header-cell[data-column="${escaped}"]`,
|
|
2014
|
+
`.filter-cell[data-column="${escaped}"]`,
|
|
2015
|
+
`.body-cell[data-column="${escaped}"] .cell-shell`
|
|
2016
|
+
];
|
|
2017
|
+
let maxWidth = 0;
|
|
2018
|
+
for (const selector of selectors) {
|
|
2019
|
+
for (const el of root.querySelectorAll(selector)) {
|
|
2020
|
+
maxWidth = Math.max(maxWidth, el.scrollWidth);
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
return maxWidth + 12;
|
|
2024
|
+
}
|
|
1871
2025
|
renderDisplayItem(item, displayIndex) {
|
|
1872
2026
|
if (!this.snapshot || !this.controller) {
|
|
1873
2027
|
return "";
|
|
@@ -1912,7 +2066,7 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1912
2066
|
editing ? "cell-editing" : ""
|
|
1913
2067
|
].filter(Boolean).join(" ");
|
|
1914
2068
|
const stickyStyle = pinOffset ? `${pinOffset.side}:${pinOffset.offset};` : "";
|
|
1915
|
-
return `<div class="${classes}" tabindex="0" data-row="${escapeHtml(rowId)}" data-column="${escapeHtml(columnName)}" style="${stickyStyle}"><div class="cell-shell" style="padding-inline-start:${escapeHtml(controller.cellIndent(row, column))}">${treeToggle}${expandToggle}
|
|
2069
|
+
return `<div class="${classes}" tabindex="0" data-row="${escapeHtml(rowId)}" data-column="${escapeHtml(columnName)}" style="${stickyStyle}"><div class="cell-shell" style="padding-inline-start:${escapeHtml(controller.cellIndent(row, column))}">${treeToggle}${expandToggle}<div class="cell-content">${content}</div></div></div>`;
|
|
1916
2070
|
}
|
|
1917
2071
|
renderPagination(snapshot) {
|
|
1918
2072
|
const pageSizes = snapshot.options.paginationPageSizes ?? [10, 25, 50, 100];
|
|
@@ -1926,6 +2080,9 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1926
2080
|
}
|
|
1927
2081
|
renderCellTemplate(row, column, displayIndex) {
|
|
1928
2082
|
const templateMarkup = this.getTemplateMarkup(this.cellSlotName(column));
|
|
2083
|
+
return this.renderCellTemplateFromMarkup(row, column, displayIndex, templateMarkup);
|
|
2084
|
+
}
|
|
2085
|
+
renderCellTemplateFromMarkup(row, column, displayIndex, templateMarkup) {
|
|
1929
2086
|
if (!templateMarkup) {
|
|
1930
2087
|
return `<span class="cell-value">${escapeHtml(this.controller?.displayValue(row, column) ?? "")}</span>`;
|
|
1931
2088
|
}
|
|
@@ -1978,6 +2135,79 @@ var UiGridStandaloneElement = class extends HTMLElement {
|
|
|
1978
2135
|
rowIndexFor(row, fallback = 0) {
|
|
1979
2136
|
return this.snapshot?.pipeline.visibleRows.findIndex((candidate) => candidate.id === row.id) ?? fallback;
|
|
1980
2137
|
}
|
|
2138
|
+
classifyDataRefresh(previousSnapshot, nextSnapshot) {
|
|
2139
|
+
if (!nextSnapshot) {
|
|
2140
|
+
return { mode: "full", changedRowIds: null };
|
|
2141
|
+
}
|
|
2142
|
+
if (!previousSnapshot) {
|
|
2143
|
+
return {
|
|
2144
|
+
mode: nextSnapshot.pipeline.virtualizationEnabled ? "virtual" : "full",
|
|
2145
|
+
changedRowIds: null
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
if (previousSnapshot.visibleColumns.length !== nextSnapshot.visibleColumns.length) {
|
|
2149
|
+
return { mode: "full", changedRowIds: null };
|
|
2150
|
+
}
|
|
2151
|
+
for (let index = 0; index < previousSnapshot.visibleColumns.length; index += 1) {
|
|
2152
|
+
if (previousSnapshot.visibleColumns[index]?.name !== nextSnapshot.visibleColumns[index]?.name) {
|
|
2153
|
+
return { mode: "full", changedRowIds: null };
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
const previousWindow = this.getRenderedDisplayWindow(previousSnapshot);
|
|
2157
|
+
const nextWindow = this.getRenderedDisplayWindow(nextSnapshot);
|
|
2158
|
+
if (previousWindow.startIndex !== nextWindow.startIndex || previousWindow.items.length !== nextWindow.items.length) {
|
|
2159
|
+
return {
|
|
2160
|
+
mode: nextSnapshot.pipeline.virtualizationEnabled ? "virtual" : "full",
|
|
2161
|
+
changedRowIds: null
|
|
2162
|
+
};
|
|
2163
|
+
}
|
|
2164
|
+
const changedRowIds = /* @__PURE__ */ new Set();
|
|
2165
|
+
for (let index = 0; index < previousWindow.items.length; index += 1) {
|
|
2166
|
+
const previousItem = previousWindow.items[index];
|
|
2167
|
+
const nextItem = nextWindow.items[index];
|
|
2168
|
+
if (!previousItem || !nextItem || previousItem.kind !== "row" || nextItem.kind !== "row") {
|
|
2169
|
+
return {
|
|
2170
|
+
mode: nextSnapshot.pipeline.virtualizationEnabled ? "virtual" : "full",
|
|
2171
|
+
changedRowIds: null
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2174
|
+
if (previousItem.row.id !== nextItem.row.id) {
|
|
2175
|
+
return {
|
|
2176
|
+
mode: nextSnapshot.pipeline.virtualizationEnabled ? "virtual" : "full",
|
|
2177
|
+
changedRowIds: null
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
if (previousItem.row.entity !== nextItem.row.entity) {
|
|
2181
|
+
changedRowIds.add(nextItem.row.id);
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
return {
|
|
2185
|
+
mode: changedRowIds.size > 0 ? "patch" : null,
|
|
2186
|
+
changedRowIds: changedRowIds.size > 0 ? changedRowIds : null
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
getRenderedDisplayWindow(snapshot) {
|
|
2190
|
+
if (!snapshot.pipeline.virtualizationEnabled) {
|
|
2191
|
+
return {
|
|
2192
|
+
startIndex: 0,
|
|
2193
|
+
items: snapshot.pipeline.displayItems
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2196
|
+
const stickyChromeHeight = this.measuredHeaderStickyHeight + this.measuredFilterStickyHeight;
|
|
2197
|
+
const viewportHeight = snapshot.options.viewportHeight ?? 560;
|
|
2198
|
+
const bodyViewportHeight = Math.max(snapshot.rowSize, viewportHeight - stickyChromeHeight);
|
|
2199
|
+
const bodyScrollTop = Math.max(0, this.scrollPosition - stickyChromeHeight);
|
|
2200
|
+
const overscan = 4;
|
|
2201
|
+
const startIndex = Math.max(0, Math.floor(bodyScrollTop / snapshot.rowSize) - overscan);
|
|
2202
|
+
const visibleCount = Math.ceil(bodyViewportHeight / snapshot.rowSize) + overscan * 2;
|
|
2203
|
+
return {
|
|
2204
|
+
startIndex,
|
|
2205
|
+
items: snapshot.pipeline.displayItems.slice(
|
|
2206
|
+
startIndex,
|
|
2207
|
+
Math.min(snapshot.pipeline.displayItems.length, startIndex + visibleCount)
|
|
2208
|
+
)
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
1981
2211
|
cellSlotName(column) {
|
|
1982
2212
|
return `cell-${column.name}`;
|
|
1983
2213
|
}
|