@rozie-ui/data-table-lit 0.3.1 → 0.3.2
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/dist/index.cjs +108 -28
- package/dist/index.d.cts +7 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +108 -28
- package/package.json +1 -1
- package/src/DataTable.ts +205 -34
- package/src/helpers/columnDefUtils.ts +77 -1
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,39 @@ const wrapAggregationFn = (fn) => {
|
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
|
+
const collectNestedDefs = (list, out) => {
|
|
28
|
+
if (!Array.isArray(list)) return;
|
|
29
|
+
for (const d of list) {
|
|
30
|
+
if (!d || d.id == null) continue;
|
|
31
|
+
const id = String(d.id);
|
|
32
|
+
if (!(id in out)) out[id] = d;
|
|
33
|
+
if (Array.isArray(d.columns)) collectNestedDefs(d.columns, out);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const indexDefsById = (defs) => {
|
|
37
|
+
const out = Object.create(null);
|
|
38
|
+
if (!Array.isArray(defs)) return out;
|
|
39
|
+
for (const d of defs) {
|
|
40
|
+
if (!d || d.id == null) continue;
|
|
41
|
+
out[String(d.id)] = d;
|
|
42
|
+
}
|
|
43
|
+
for (const d of defs) if (d && Array.isArray(d.columns)) collectNestedDefs(d.columns, out);
|
|
44
|
+
return out;
|
|
45
|
+
};
|
|
46
|
+
const collectGroupableLeafDefs = (defs) => {
|
|
47
|
+
const out = [];
|
|
48
|
+
if (!Array.isArray(defs)) return out;
|
|
49
|
+
for (const d of defs) {
|
|
50
|
+
if (!d) continue;
|
|
51
|
+
if (Array.isArray(d.columns)) {
|
|
52
|
+
out.push(...collectGroupableLeafDefs(d.columns));
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (d.groupable === false) continue;
|
|
56
|
+
out.push(d);
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
};
|
|
27
60
|
//#endregion
|
|
28
61
|
//#region src/helpers/indexMath.ts
|
|
29
62
|
const clamp = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
|
|
@@ -468,6 +501,7 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
|
|
|
468
501
|
this.columnDefsCache = null;
|
|
469
502
|
this.columnDefsCacheColumnsRef = void 0;
|
|
470
503
|
this.columnDefsCacheColRegRef = void 0;
|
|
504
|
+
this.columnDefsIndexCache = null;
|
|
471
505
|
this.columnDefs = () => {
|
|
472
506
|
const cfg = this.columns || [];
|
|
473
507
|
const reg = this._colReg.value || {};
|
|
@@ -511,8 +545,13 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
|
|
|
511
545
|
this.columnDefsCache = out;
|
|
512
546
|
this.columnDefsCacheColumnsRef = this.columns;
|
|
513
547
|
this.columnDefsCacheColRegRef = this._colReg.value;
|
|
548
|
+
this.columnDefsIndexCache = indexDefsById(out);
|
|
514
549
|
return out;
|
|
515
550
|
};
|
|
551
|
+
this.defIndex = () => {
|
|
552
|
+
this.columnDefs();
|
|
553
|
+
return this.columnDefsIndexCache || Object.create(null);
|
|
554
|
+
};
|
|
516
555
|
this.SELECT_COL_ID = "__rdt_select";
|
|
517
556
|
this.EXPANDER_COL_ID = "__rdt_expander";
|
|
518
557
|
this.selectionEnabled = () => this.selectionMode === "single" || this.selectionMode === "multiple";
|
|
@@ -1254,9 +1293,9 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
|
|
|
1254
1293
|
return "";
|
|
1255
1294
|
};
|
|
1256
1295
|
this.defFor = (colId) => {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
return null;
|
|
1296
|
+
if (colId == null) return null;
|
|
1297
|
+
const d = this.defIndex()[String(colId)];
|
|
1298
|
+
return d != null ? d : null;
|
|
1260
1299
|
};
|
|
1261
1300
|
this.visibleCellsFor = (row) => this._rowModelVer.value >= 0 ? row.getVisibleCells() : [];
|
|
1262
1301
|
this.editMetaOf = (colId) => {
|
|
@@ -1433,22 +1472,56 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
|
|
|
1433
1472
|
return base;
|
|
1434
1473
|
};
|
|
1435
1474
|
this.rowIsGrouped = (row) => !!(this.tick() >= 0 && row && row.getIsGrouped && row.getIsGrouped());
|
|
1475
|
+
this.rowIndexIsGrouped = (rowIndex) => this.rowIsGrouped((this._rows.value || [])[rowIndex]);
|
|
1436
1476
|
this.groupingActive = () => this.tick() >= 0 && (this.currentState().grouping || []).length > 0;
|
|
1437
1477
|
this.cellIsGrouped = (cellCtx) => !!(this.tick() >= 0 && cellCtx && cellCtx.getIsGrouped && cellCtx.getIsGrouped());
|
|
1438
1478
|
this.cellIsAggregated = (cellCtx) => !!(this.tick() >= 0 && cellCtx && cellCtx.getIsAggregated && cellCtx.getIsAggregated());
|
|
1439
1479
|
this.cellIsPlaceholder = (cellCtx) => !!(this.tick() >= 0 && cellCtx && cellCtx.getIsPlaceholder && cellCtx.getIsPlaceholder());
|
|
1440
|
-
this.groupSubRowCount = (row) =>
|
|
1480
|
+
this.groupSubRowCount = (row) => {
|
|
1481
|
+
if (row && row.getLeafRows) {
|
|
1482
|
+
const leaves = row.getLeafRows();
|
|
1483
|
+
let n = 0;
|
|
1484
|
+
for (let i = 0; i < leaves.length; i++) {
|
|
1485
|
+
const r = leaves[i];
|
|
1486
|
+
if (!(r && r.getIsGrouped && r.getIsGrouped())) n = n + 1;
|
|
1487
|
+
}
|
|
1488
|
+
return n;
|
|
1489
|
+
}
|
|
1490
|
+
return row && row.subRows ? row.subRows.length : 0;
|
|
1491
|
+
};
|
|
1492
|
+
this.groupRowDescriptorCache = null;
|
|
1493
|
+
this.groupRowDescriptorCacheVer = void 0;
|
|
1494
|
+
this.groupRowDescriptor = (row) => {
|
|
1495
|
+
const ver = this._rowModelVer.value;
|
|
1496
|
+
if (!this.groupRowDescriptorCache || this.groupRowDescriptorCacheVer !== ver) {
|
|
1497
|
+
this.groupRowDescriptorCache = Object.create(null);
|
|
1498
|
+
this.groupRowDescriptorCacheVer = ver;
|
|
1499
|
+
}
|
|
1500
|
+
const key = String(row.id);
|
|
1501
|
+
let d = this.groupRowDescriptorCache[key];
|
|
1502
|
+
if (!d) {
|
|
1503
|
+
const groupingColumnId = row.groupingColumnId != null ? row.groupingColumnId : "";
|
|
1504
|
+
const groupingValue = row.getGroupingValue ? row.getGroupingValue(groupingColumnId) : row.groupingValue;
|
|
1505
|
+
d = {
|
|
1506
|
+
isGroupRow: true,
|
|
1507
|
+
groupId: row.id,
|
|
1508
|
+
groupingColumnId,
|
|
1509
|
+
groupingValue,
|
|
1510
|
+
leafCount: this.groupSubRowCount(row)
|
|
1511
|
+
};
|
|
1512
|
+
this.groupRowDescriptorCache[key] = d;
|
|
1513
|
+
}
|
|
1514
|
+
return d;
|
|
1515
|
+
};
|
|
1516
|
+
this.cellSlotRow = (row) => this.rowIsGrouped(row) ? this.groupRowDescriptor(row) : row ? row.original : null;
|
|
1441
1517
|
this.groupingKeys = () => this.currentState().grouping || [];
|
|
1442
1518
|
this.groupableColumns = () => {
|
|
1443
1519
|
const out = [];
|
|
1444
|
-
const defs = this.columnDefs();
|
|
1445
|
-
for (const d of defs) {
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
label: d.header != null ? d.header : d.id
|
|
1450
|
-
});
|
|
1451
|
-
}
|
|
1520
|
+
const defs = collectGroupableLeafDefs(this.columnDefs());
|
|
1521
|
+
for (const d of defs) out.push({
|
|
1522
|
+
id: d.id,
|
|
1523
|
+
label: d.header != null ? d.header : d.id
|
|
1524
|
+
});
|
|
1452
1525
|
return out;
|
|
1453
1526
|
};
|
|
1454
1527
|
this.stopEvent = (evt) => {
|
|
@@ -2446,11 +2519,13 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
|
|
|
2446
2519
|
for (let gr = 0; gr < grid.length; gr++) {
|
|
2447
2520
|
const r = originRow + gr;
|
|
2448
2521
|
if (r > maxRow) break;
|
|
2522
|
+
const rowGrouped = this.rowIndexIsGrouped(r);
|
|
2449
2523
|
const cols = grid[gr] || [];
|
|
2450
2524
|
for (let gc = 0; gc < cols.length; gc++) {
|
|
2451
2525
|
const c = originCol + gc;
|
|
2452
2526
|
if (c > maxCol) break;
|
|
2453
2527
|
total = total + 1;
|
|
2528
|
+
if (rowGrouped) continue;
|
|
2454
2529
|
const colId = this.columnIdAt(r, c);
|
|
2455
2530
|
if (colId == null || !this.columnEditable(colId)) continue;
|
|
2456
2531
|
const rowObj = this.rowOriginalAt(r);
|
|
@@ -2760,11 +2835,13 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
|
|
|
2760
2835
|
return cell && cell.column ? cell.column.id : null;
|
|
2761
2836
|
};
|
|
2762
2837
|
this.isActiveCellEditable = () => {
|
|
2838
|
+
if (this.rowIndexIsGrouped(this._activeRow.value)) return false;
|
|
2763
2839
|
const colId = this.activeCellColumnId();
|
|
2764
2840
|
return colId != null && this.columnEditable(colId);
|
|
2765
2841
|
};
|
|
2766
2842
|
this.isEditing = (rowIndex, colIndex) => {
|
|
2767
2843
|
if (this._editVer.value < 0) return false;
|
|
2844
|
+
if (this.rowIndexIsGrouped(rowIndex)) return false;
|
|
2768
2845
|
if (this._editingRowIndex.value != null && this._editingRowIndex.value === rowIndex) {
|
|
2769
2846
|
const colId = this.columnIdAt(rowIndex, colIndex);
|
|
2770
2847
|
return colId != null && this.columnEditable(colId);
|
|
@@ -2864,6 +2941,7 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
|
|
|
2864
2941
|
return cell ? cell.getValue() : null;
|
|
2865
2942
|
};
|
|
2866
2943
|
this.beginEdit = (rowIndex, colIndex, seed) => {
|
|
2944
|
+
if (this.rowIndexIsGrouped(rowIndex)) return;
|
|
2867
2945
|
const colId = this.columnIdAt(rowIndex, colIndex);
|
|
2868
2946
|
if (colId == null || !this.columnEditable(colId)) return;
|
|
2869
2947
|
this.committedThisSession = false;
|
|
@@ -2981,6 +3059,7 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
|
|
|
2981
3059
|
return true;
|
|
2982
3060
|
};
|
|
2983
3061
|
this.toggleActiveBooleanCell = () => {
|
|
3062
|
+
if (this.rowIndexIsGrouped(this._activeRow.value)) return;
|
|
2984
3063
|
const colId = this.columnIdAt(this._activeRow.value, this._activeColIndex.value);
|
|
2985
3064
|
if (colId == null || !this.columnEditable(colId)) return;
|
|
2986
3065
|
const row = (this._rows.value || [])[this._activeRow.value];
|
|
@@ -3070,6 +3149,7 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
|
|
|
3070
3149
|
this.beginRowEdit = (row) => {
|
|
3071
3150
|
const rowIndex = this.rowIndexOf(row);
|
|
3072
3151
|
if (rowIndex < 0) return;
|
|
3152
|
+
if (this.rowIndexIsGrouped(rowIndex)) return;
|
|
3073
3153
|
const editable = this.editableColumnsForRow(rowIndex);
|
|
3074
3154
|
if (editable.length === 0) return;
|
|
3075
3155
|
this.committedThisSession = false;
|
|
@@ -4349,13 +4429,13 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4349
4429
|
this.onToggleExpand(wr.row, $event);
|
|
4350
4430
|
}} data-rozie-s-d5dcab4c>${(0, _rozie_runtime_lit.rozieDisplay)(this.rowIsExpanded(wr.row) ? "▾" : "▸")}</button>` : lit.nothing}</span>` : this.isSelectColumn(cell.column.id) ? lit.html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
4351
4431
|
${this.selectCell !== void 0 ? this.selectCell({
|
|
4352
|
-
row: wr.row
|
|
4432
|
+
row: this.cellSlotRow(wr.row),
|
|
4353
4433
|
checked: this.rowIsSelected(wr.row),
|
|
4354
4434
|
toggle: (e) => this.onToggleRow(wr.row, e)
|
|
4355
4435
|
}) : lit.html`<slot name="selectCell" data-rozie-params=${(() => {
|
|
4356
4436
|
try {
|
|
4357
4437
|
return JSON.stringify({
|
|
4358
|
-
row: wr.row
|
|
4438
|
+
row: this.cellSlotRow(wr.row),
|
|
4359
4439
|
checked: this.rowIsSelected(wr.row)
|
|
4360
4440
|
});
|
|
4361
4441
|
} catch {
|
|
@@ -4374,14 +4454,14 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4374
4454
|
${this.cell !== void 0 ? this.cell({
|
|
4375
4455
|
columnId: cell.column.id,
|
|
4376
4456
|
column: cell.column,
|
|
4377
|
-
row: wr.row
|
|
4457
|
+
row: this.cellSlotRow(wr.row),
|
|
4378
4458
|
value: cell.getValue()
|
|
4379
4459
|
}) : lit.html`<slot name="cell" data-rozie-params=${(() => {
|
|
4380
4460
|
try {
|
|
4381
4461
|
return JSON.stringify({
|
|
4382
4462
|
columnId: cell.column.id,
|
|
4383
4463
|
column: cell.column,
|
|
4384
|
-
row: wr.row
|
|
4464
|
+
row: this.cellSlotRow(wr.row),
|
|
4385
4465
|
value: cell.getValue()
|
|
4386
4466
|
});
|
|
4387
4467
|
} catch {
|
|
@@ -4395,7 +4475,7 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4395
4475
|
${this.editor !== void 0 ? this.editor({
|
|
4396
4476
|
columnId: cell.column.id,
|
|
4397
4477
|
column: cell.column,
|
|
4398
|
-
row: wr.row
|
|
4478
|
+
row: this.cellSlotRow(wr.row),
|
|
4399
4479
|
value: this.editorValueFor(cell.column.id),
|
|
4400
4480
|
commit: this.editorCommitFor(cell.column.id),
|
|
4401
4481
|
cancel: this.editorCancelFor(),
|
|
@@ -4405,7 +4485,7 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4405
4485
|
return JSON.stringify({
|
|
4406
4486
|
columnId: cell.column.id,
|
|
4407
4487
|
column: cell.column,
|
|
4408
|
-
row: wr.row
|
|
4488
|
+
row: this.cellSlotRow(wr.row),
|
|
4409
4489
|
value: this.editorValueFor(cell.column.id),
|
|
4410
4490
|
commit: this.editorCommitFor(cell.column.id),
|
|
4411
4491
|
cancel: this.editorCancelFor(),
|
|
@@ -4445,14 +4525,14 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4445
4525
|
${this.cell !== void 0 ? this.cell({
|
|
4446
4526
|
columnId: cell.column.id,
|
|
4447
4527
|
column: cell.column,
|
|
4448
|
-
row: wr.row
|
|
4528
|
+
row: this.cellSlotRow(wr.row),
|
|
4449
4529
|
value: cell.getValue()
|
|
4450
4530
|
}) : lit.html`<slot name="cell" data-rozie-params=${(() => {
|
|
4451
4531
|
try {
|
|
4452
4532
|
return JSON.stringify({
|
|
4453
4533
|
columnId: cell.column.id,
|
|
4454
4534
|
column: cell.column,
|
|
4455
|
-
row: wr.row
|
|
4535
|
+
row: this.cellSlotRow(wr.row),
|
|
4456
4536
|
value: cell.getValue()
|
|
4457
4537
|
});
|
|
4458
4538
|
} catch {
|
|
@@ -4643,13 +4723,13 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4643
4723
|
this.onToggleExpand(row, $event);
|
|
4644
4724
|
}} data-rozie-s-d5dcab4c>${(0, _rozie_runtime_lit.rozieDisplay)(this.rowIsExpanded(row) ? "▾" : "▸")}</button>` : lit.nothing}</span>` : this.isSelectColumn(cell.column.id) ? lit.html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
4645
4725
|
${this.selectCell !== void 0 ? this.selectCell({
|
|
4646
|
-
row: row
|
|
4726
|
+
row: this.cellSlotRow(row),
|
|
4647
4727
|
checked: this.rowIsSelected(row),
|
|
4648
4728
|
toggle: (e) => this.onToggleRow(row, e)
|
|
4649
4729
|
}) : lit.html`<slot name="selectCell" data-rozie-params=${(() => {
|
|
4650
4730
|
try {
|
|
4651
4731
|
return JSON.stringify({
|
|
4652
|
-
row: row
|
|
4732
|
+
row: this.cellSlotRow(row),
|
|
4653
4733
|
checked: this.rowIsSelected(row)
|
|
4654
4734
|
});
|
|
4655
4735
|
} catch {
|
|
@@ -4668,14 +4748,14 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4668
4748
|
${this.cell !== void 0 ? this.cell({
|
|
4669
4749
|
columnId: cell.column.id,
|
|
4670
4750
|
column: cell.column,
|
|
4671
|
-
row: row
|
|
4751
|
+
row: this.cellSlotRow(row),
|
|
4672
4752
|
value: cell.getValue()
|
|
4673
4753
|
}) : lit.html`<slot name="cell" data-rozie-params=${(() => {
|
|
4674
4754
|
try {
|
|
4675
4755
|
return JSON.stringify({
|
|
4676
4756
|
columnId: cell.column.id,
|
|
4677
4757
|
column: cell.column,
|
|
4678
|
-
row: row
|
|
4758
|
+
row: this.cellSlotRow(row),
|
|
4679
4759
|
value: cell.getValue()
|
|
4680
4760
|
});
|
|
4681
4761
|
} catch {
|
|
@@ -4689,7 +4769,7 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4689
4769
|
${this.editor !== void 0 ? this.editor({
|
|
4690
4770
|
columnId: cell.column.id,
|
|
4691
4771
|
column: cell.column,
|
|
4692
|
-
row: row
|
|
4772
|
+
row: this.cellSlotRow(row),
|
|
4693
4773
|
value: this.editorValueFor(cell.column.id),
|
|
4694
4774
|
commit: this.editorCommitFor(cell.column.id),
|
|
4695
4775
|
cancel: this.editorCancelFor(),
|
|
@@ -4699,7 +4779,7 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4699
4779
|
return JSON.stringify({
|
|
4700
4780
|
columnId: cell.column.id,
|
|
4701
4781
|
column: cell.column,
|
|
4702
|
-
row: row
|
|
4782
|
+
row: this.cellSlotRow(row),
|
|
4703
4783
|
value: this.editorValueFor(cell.column.id),
|
|
4704
4784
|
commit: this.editorCommitFor(cell.column.id),
|
|
4705
4785
|
cancel: this.editorCancelFor(),
|
|
@@ -4739,14 +4819,14 @@ ${this.groupable ? lit.html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4
|
|
|
4739
4819
|
${this.cell !== void 0 ? this.cell({
|
|
4740
4820
|
columnId: cell.column.id,
|
|
4741
4821
|
column: cell.column,
|
|
4742
|
-
row: row
|
|
4822
|
+
row: this.cellSlotRow(row),
|
|
4743
4823
|
value: cell.getValue()
|
|
4744
4824
|
}) : lit.html`<slot name="cell" data-rozie-params=${(() => {
|
|
4745
4825
|
try {
|
|
4746
4826
|
return JSON.stringify({
|
|
4747
4827
|
columnId: cell.column.id,
|
|
4748
4828
|
column: cell.column,
|
|
4749
|
-
row: row
|
|
4829
|
+
row: this.cellSlotRow(row),
|
|
4750
4830
|
value: cell.getValue()
|
|
4751
4831
|
});
|
|
4752
4832
|
} catch {
|
package/dist/index.d.cts
CHANGED
|
@@ -308,7 +308,9 @@ declare class DataTable extends DataTable_base {
|
|
|
308
308
|
columnDefsCache: any[] | null;
|
|
309
309
|
columnDefsCacheColumnsRef: any;
|
|
310
310
|
columnDefsCacheColRegRef: any;
|
|
311
|
+
columnDefsIndexCache: any;
|
|
311
312
|
columnDefs: () => any[];
|
|
313
|
+
defIndex: () => any;
|
|
312
314
|
SELECT_COL_ID: string;
|
|
313
315
|
EXPANDER_COL_ID: string;
|
|
314
316
|
selectionEnabled: () => boolean;
|
|
@@ -456,11 +458,16 @@ declare class DataTable extends DataTable_base {
|
|
|
456
458
|
onToggleExpand: (row: any, evt: any) => void;
|
|
457
459
|
bodyCellStyle: (row: any, colId: any) => string;
|
|
458
460
|
rowIsGrouped: (row: any) => boolean;
|
|
461
|
+
rowIndexIsGrouped: (rowIndex: any) => boolean;
|
|
459
462
|
groupingActive: () => boolean;
|
|
460
463
|
cellIsGrouped: (cellCtx: any) => boolean;
|
|
461
464
|
cellIsAggregated: (cellCtx: any) => boolean;
|
|
462
465
|
cellIsPlaceholder: (cellCtx: any) => boolean;
|
|
463
466
|
groupSubRowCount: (row: any) => any;
|
|
467
|
+
groupRowDescriptorCache: any;
|
|
468
|
+
groupRowDescriptorCacheVer: any;
|
|
469
|
+
groupRowDescriptor: (row: any) => any;
|
|
470
|
+
cellSlotRow: (row: any) => any;
|
|
464
471
|
groupingKeys: () => any;
|
|
465
472
|
groupableColumns: () => any[];
|
|
466
473
|
stopEvent: (evt: any) => void;
|
package/dist/index.d.mts
CHANGED
|
@@ -308,7 +308,9 @@ declare class DataTable extends DataTable_base {
|
|
|
308
308
|
columnDefsCache: any[] | null;
|
|
309
309
|
columnDefsCacheColumnsRef: any;
|
|
310
310
|
columnDefsCacheColRegRef: any;
|
|
311
|
+
columnDefsIndexCache: any;
|
|
311
312
|
columnDefs: () => any[];
|
|
313
|
+
defIndex: () => any;
|
|
312
314
|
SELECT_COL_ID: string;
|
|
313
315
|
EXPANDER_COL_ID: string;
|
|
314
316
|
selectionEnabled: () => boolean;
|
|
@@ -456,11 +458,16 @@ declare class DataTable extends DataTable_base {
|
|
|
456
458
|
onToggleExpand: (row: any, evt: any) => void;
|
|
457
459
|
bodyCellStyle: (row: any, colId: any) => string;
|
|
458
460
|
rowIsGrouped: (row: any) => boolean;
|
|
461
|
+
rowIndexIsGrouped: (rowIndex: any) => boolean;
|
|
459
462
|
groupingActive: () => boolean;
|
|
460
463
|
cellIsGrouped: (cellCtx: any) => boolean;
|
|
461
464
|
cellIsAggregated: (cellCtx: any) => boolean;
|
|
462
465
|
cellIsPlaceholder: (cellCtx: any) => boolean;
|
|
463
466
|
groupSubRowCount: (row: any) => any;
|
|
467
|
+
groupRowDescriptorCache: any;
|
|
468
|
+
groupRowDescriptorCacheVer: any;
|
|
469
|
+
groupRowDescriptor: (row: any) => any;
|
|
470
|
+
cellSlotRow: (row: any) => any;
|
|
464
471
|
groupingKeys: () => any;
|
|
465
472
|
groupableColumns: () => any[];
|
|
466
473
|
stopEvent: (evt: any) => void;
|
package/dist/index.mjs
CHANGED
|
@@ -20,6 +20,39 @@ const wrapAggregationFn = (fn) => {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
|
+
const collectNestedDefs = (list, out) => {
|
|
24
|
+
if (!Array.isArray(list)) return;
|
|
25
|
+
for (const d of list) {
|
|
26
|
+
if (!d || d.id == null) continue;
|
|
27
|
+
const id = String(d.id);
|
|
28
|
+
if (!(id in out)) out[id] = d;
|
|
29
|
+
if (Array.isArray(d.columns)) collectNestedDefs(d.columns, out);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const indexDefsById = (defs) => {
|
|
33
|
+
const out = Object.create(null);
|
|
34
|
+
if (!Array.isArray(defs)) return out;
|
|
35
|
+
for (const d of defs) {
|
|
36
|
+
if (!d || d.id == null) continue;
|
|
37
|
+
out[String(d.id)] = d;
|
|
38
|
+
}
|
|
39
|
+
for (const d of defs) if (d && Array.isArray(d.columns)) collectNestedDefs(d.columns, out);
|
|
40
|
+
return out;
|
|
41
|
+
};
|
|
42
|
+
const collectGroupableLeafDefs = (defs) => {
|
|
43
|
+
const out = [];
|
|
44
|
+
if (!Array.isArray(defs)) return out;
|
|
45
|
+
for (const d of defs) {
|
|
46
|
+
if (!d) continue;
|
|
47
|
+
if (Array.isArray(d.columns)) {
|
|
48
|
+
out.push(...collectGroupableLeafDefs(d.columns));
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (d.groupable === false) continue;
|
|
52
|
+
out.push(d);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
};
|
|
23
56
|
//#endregion
|
|
24
57
|
//#region src/helpers/indexMath.ts
|
|
25
58
|
const clamp = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
|
|
@@ -464,6 +497,7 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
|
|
|
464
497
|
this.columnDefsCache = null;
|
|
465
498
|
this.columnDefsCacheColumnsRef = void 0;
|
|
466
499
|
this.columnDefsCacheColRegRef = void 0;
|
|
500
|
+
this.columnDefsIndexCache = null;
|
|
467
501
|
this.columnDefs = () => {
|
|
468
502
|
const cfg = this.columns || [];
|
|
469
503
|
const reg = this._colReg.value || {};
|
|
@@ -507,8 +541,13 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
|
|
|
507
541
|
this.columnDefsCache = out;
|
|
508
542
|
this.columnDefsCacheColumnsRef = this.columns;
|
|
509
543
|
this.columnDefsCacheColRegRef = this._colReg.value;
|
|
544
|
+
this.columnDefsIndexCache = indexDefsById(out);
|
|
510
545
|
return out;
|
|
511
546
|
};
|
|
547
|
+
this.defIndex = () => {
|
|
548
|
+
this.columnDefs();
|
|
549
|
+
return this.columnDefsIndexCache || Object.create(null);
|
|
550
|
+
};
|
|
512
551
|
this.SELECT_COL_ID = "__rdt_select";
|
|
513
552
|
this.EXPANDER_COL_ID = "__rdt_expander";
|
|
514
553
|
this.selectionEnabled = () => this.selectionMode === "single" || this.selectionMode === "multiple";
|
|
@@ -1250,9 +1289,9 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
|
|
|
1250
1289
|
return "";
|
|
1251
1290
|
};
|
|
1252
1291
|
this.defFor = (colId) => {
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
return null;
|
|
1292
|
+
if (colId == null) return null;
|
|
1293
|
+
const d = this.defIndex()[String(colId)];
|
|
1294
|
+
return d != null ? d : null;
|
|
1256
1295
|
};
|
|
1257
1296
|
this.visibleCellsFor = (row) => this._rowModelVer.value >= 0 ? row.getVisibleCells() : [];
|
|
1258
1297
|
this.editMetaOf = (colId) => {
|
|
@@ -1429,22 +1468,56 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
|
|
|
1429
1468
|
return base;
|
|
1430
1469
|
};
|
|
1431
1470
|
this.rowIsGrouped = (row) => !!(this.tick() >= 0 && row && row.getIsGrouped && row.getIsGrouped());
|
|
1471
|
+
this.rowIndexIsGrouped = (rowIndex) => this.rowIsGrouped((this._rows.value || [])[rowIndex]);
|
|
1432
1472
|
this.groupingActive = () => this.tick() >= 0 && (this.currentState().grouping || []).length > 0;
|
|
1433
1473
|
this.cellIsGrouped = (cellCtx) => !!(this.tick() >= 0 && cellCtx && cellCtx.getIsGrouped && cellCtx.getIsGrouped());
|
|
1434
1474
|
this.cellIsAggregated = (cellCtx) => !!(this.tick() >= 0 && cellCtx && cellCtx.getIsAggregated && cellCtx.getIsAggregated());
|
|
1435
1475
|
this.cellIsPlaceholder = (cellCtx) => !!(this.tick() >= 0 && cellCtx && cellCtx.getIsPlaceholder && cellCtx.getIsPlaceholder());
|
|
1436
|
-
this.groupSubRowCount = (row) =>
|
|
1476
|
+
this.groupSubRowCount = (row) => {
|
|
1477
|
+
if (row && row.getLeafRows) {
|
|
1478
|
+
const leaves = row.getLeafRows();
|
|
1479
|
+
let n = 0;
|
|
1480
|
+
for (let i = 0; i < leaves.length; i++) {
|
|
1481
|
+
const r = leaves[i];
|
|
1482
|
+
if (!(r && r.getIsGrouped && r.getIsGrouped())) n = n + 1;
|
|
1483
|
+
}
|
|
1484
|
+
return n;
|
|
1485
|
+
}
|
|
1486
|
+
return row && row.subRows ? row.subRows.length : 0;
|
|
1487
|
+
};
|
|
1488
|
+
this.groupRowDescriptorCache = null;
|
|
1489
|
+
this.groupRowDescriptorCacheVer = void 0;
|
|
1490
|
+
this.groupRowDescriptor = (row) => {
|
|
1491
|
+
const ver = this._rowModelVer.value;
|
|
1492
|
+
if (!this.groupRowDescriptorCache || this.groupRowDescriptorCacheVer !== ver) {
|
|
1493
|
+
this.groupRowDescriptorCache = Object.create(null);
|
|
1494
|
+
this.groupRowDescriptorCacheVer = ver;
|
|
1495
|
+
}
|
|
1496
|
+
const key = String(row.id);
|
|
1497
|
+
let d = this.groupRowDescriptorCache[key];
|
|
1498
|
+
if (!d) {
|
|
1499
|
+
const groupingColumnId = row.groupingColumnId != null ? row.groupingColumnId : "";
|
|
1500
|
+
const groupingValue = row.getGroupingValue ? row.getGroupingValue(groupingColumnId) : row.groupingValue;
|
|
1501
|
+
d = {
|
|
1502
|
+
isGroupRow: true,
|
|
1503
|
+
groupId: row.id,
|
|
1504
|
+
groupingColumnId,
|
|
1505
|
+
groupingValue,
|
|
1506
|
+
leafCount: this.groupSubRowCount(row)
|
|
1507
|
+
};
|
|
1508
|
+
this.groupRowDescriptorCache[key] = d;
|
|
1509
|
+
}
|
|
1510
|
+
return d;
|
|
1511
|
+
};
|
|
1512
|
+
this.cellSlotRow = (row) => this.rowIsGrouped(row) ? this.groupRowDescriptor(row) : row ? row.original : null;
|
|
1437
1513
|
this.groupingKeys = () => this.currentState().grouping || [];
|
|
1438
1514
|
this.groupableColumns = () => {
|
|
1439
1515
|
const out = [];
|
|
1440
|
-
const defs = this.columnDefs();
|
|
1441
|
-
for (const d of defs) {
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
label: d.header != null ? d.header : d.id
|
|
1446
|
-
});
|
|
1447
|
-
}
|
|
1516
|
+
const defs = collectGroupableLeafDefs(this.columnDefs());
|
|
1517
|
+
for (const d of defs) out.push({
|
|
1518
|
+
id: d.id,
|
|
1519
|
+
label: d.header != null ? d.header : d.id
|
|
1520
|
+
});
|
|
1448
1521
|
return out;
|
|
1449
1522
|
};
|
|
1450
1523
|
this.stopEvent = (evt) => {
|
|
@@ -2442,11 +2515,13 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
|
|
|
2442
2515
|
for (let gr = 0; gr < grid.length; gr++) {
|
|
2443
2516
|
const r = originRow + gr;
|
|
2444
2517
|
if (r > maxRow) break;
|
|
2518
|
+
const rowGrouped = this.rowIndexIsGrouped(r);
|
|
2445
2519
|
const cols = grid[gr] || [];
|
|
2446
2520
|
for (let gc = 0; gc < cols.length; gc++) {
|
|
2447
2521
|
const c = originCol + gc;
|
|
2448
2522
|
if (c > maxCol) break;
|
|
2449
2523
|
total = total + 1;
|
|
2524
|
+
if (rowGrouped) continue;
|
|
2450
2525
|
const colId = this.columnIdAt(r, c);
|
|
2451
2526
|
if (colId == null || !this.columnEditable(colId)) continue;
|
|
2452
2527
|
const rowObj = this.rowOriginalAt(r);
|
|
@@ -2756,11 +2831,13 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
|
|
|
2756
2831
|
return cell && cell.column ? cell.column.id : null;
|
|
2757
2832
|
};
|
|
2758
2833
|
this.isActiveCellEditable = () => {
|
|
2834
|
+
if (this.rowIndexIsGrouped(this._activeRow.value)) return false;
|
|
2759
2835
|
const colId = this.activeCellColumnId();
|
|
2760
2836
|
return colId != null && this.columnEditable(colId);
|
|
2761
2837
|
};
|
|
2762
2838
|
this.isEditing = (rowIndex, colIndex) => {
|
|
2763
2839
|
if (this._editVer.value < 0) return false;
|
|
2840
|
+
if (this.rowIndexIsGrouped(rowIndex)) return false;
|
|
2764
2841
|
if (this._editingRowIndex.value != null && this._editingRowIndex.value === rowIndex) {
|
|
2765
2842
|
const colId = this.columnIdAt(rowIndex, colIndex);
|
|
2766
2843
|
return colId != null && this.columnEditable(colId);
|
|
@@ -2860,6 +2937,7 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
|
|
|
2860
2937
|
return cell ? cell.getValue() : null;
|
|
2861
2938
|
};
|
|
2862
2939
|
this.beginEdit = (rowIndex, colIndex, seed) => {
|
|
2940
|
+
if (this.rowIndexIsGrouped(rowIndex)) return;
|
|
2863
2941
|
const colId = this.columnIdAt(rowIndex, colIndex);
|
|
2864
2942
|
if (colId == null || !this.columnEditable(colId)) return;
|
|
2865
2943
|
this.committedThisSession = false;
|
|
@@ -2977,6 +3055,7 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
|
|
|
2977
3055
|
return true;
|
|
2978
3056
|
};
|
|
2979
3057
|
this.toggleActiveBooleanCell = () => {
|
|
3058
|
+
if (this.rowIndexIsGrouped(this._activeRow.value)) return;
|
|
2980
3059
|
const colId = this.columnIdAt(this._activeRow.value, this._activeColIndex.value);
|
|
2981
3060
|
if (colId == null || !this.columnEditable(colId)) return;
|
|
2982
3061
|
const row = (this._rows.value || [])[this._activeRow.value];
|
|
@@ -3066,6 +3145,7 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
|
|
|
3066
3145
|
this.beginRowEdit = (row) => {
|
|
3067
3146
|
const rowIndex = this.rowIndexOf(row);
|
|
3068
3147
|
if (rowIndex < 0) return;
|
|
3148
|
+
if (this.rowIndexIsGrouped(rowIndex)) return;
|
|
3069
3149
|
const editable = this.editableColumnsForRow(rowIndex);
|
|
3070
3150
|
if (editable.length === 0) return;
|
|
3071
3151
|
this.committedThisSession = false;
|
|
@@ -4345,13 +4425,13 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4345
4425
|
this.onToggleExpand(wr.row, $event);
|
|
4346
4426
|
}} data-rozie-s-d5dcab4c>${rozieDisplay(this.rowIsExpanded(wr.row) ? "▾" : "▸")}</button>` : nothing}</span>` : this.isSelectColumn(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
4347
4427
|
${this.selectCell !== void 0 ? this.selectCell({
|
|
4348
|
-
row: wr.row
|
|
4428
|
+
row: this.cellSlotRow(wr.row),
|
|
4349
4429
|
checked: this.rowIsSelected(wr.row),
|
|
4350
4430
|
toggle: (e) => this.onToggleRow(wr.row, e)
|
|
4351
4431
|
}) : html`<slot name="selectCell" data-rozie-params=${(() => {
|
|
4352
4432
|
try {
|
|
4353
4433
|
return JSON.stringify({
|
|
4354
|
-
row: wr.row
|
|
4434
|
+
row: this.cellSlotRow(wr.row),
|
|
4355
4435
|
checked: this.rowIsSelected(wr.row)
|
|
4356
4436
|
});
|
|
4357
4437
|
} catch {
|
|
@@ -4370,14 +4450,14 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4370
4450
|
${this.cell !== void 0 ? this.cell({
|
|
4371
4451
|
columnId: cell.column.id,
|
|
4372
4452
|
column: cell.column,
|
|
4373
|
-
row: wr.row
|
|
4453
|
+
row: this.cellSlotRow(wr.row),
|
|
4374
4454
|
value: cell.getValue()
|
|
4375
4455
|
}) : html`<slot name="cell" data-rozie-params=${(() => {
|
|
4376
4456
|
try {
|
|
4377
4457
|
return JSON.stringify({
|
|
4378
4458
|
columnId: cell.column.id,
|
|
4379
4459
|
column: cell.column,
|
|
4380
|
-
row: wr.row
|
|
4460
|
+
row: this.cellSlotRow(wr.row),
|
|
4381
4461
|
value: cell.getValue()
|
|
4382
4462
|
});
|
|
4383
4463
|
} catch {
|
|
@@ -4391,7 +4471,7 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4391
4471
|
${this.editor !== void 0 ? this.editor({
|
|
4392
4472
|
columnId: cell.column.id,
|
|
4393
4473
|
column: cell.column,
|
|
4394
|
-
row: wr.row
|
|
4474
|
+
row: this.cellSlotRow(wr.row),
|
|
4395
4475
|
value: this.editorValueFor(cell.column.id),
|
|
4396
4476
|
commit: this.editorCommitFor(cell.column.id),
|
|
4397
4477
|
cancel: this.editorCancelFor(),
|
|
@@ -4401,7 +4481,7 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4401
4481
|
return JSON.stringify({
|
|
4402
4482
|
columnId: cell.column.id,
|
|
4403
4483
|
column: cell.column,
|
|
4404
|
-
row: wr.row
|
|
4484
|
+
row: this.cellSlotRow(wr.row),
|
|
4405
4485
|
value: this.editorValueFor(cell.column.id),
|
|
4406
4486
|
commit: this.editorCommitFor(cell.column.id),
|
|
4407
4487
|
cancel: this.editorCancelFor(),
|
|
@@ -4441,14 +4521,14 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4441
4521
|
${this.cell !== void 0 ? this.cell({
|
|
4442
4522
|
columnId: cell.column.id,
|
|
4443
4523
|
column: cell.column,
|
|
4444
|
-
row: wr.row
|
|
4524
|
+
row: this.cellSlotRow(wr.row),
|
|
4445
4525
|
value: cell.getValue()
|
|
4446
4526
|
}) : html`<slot name="cell" data-rozie-params=${(() => {
|
|
4447
4527
|
try {
|
|
4448
4528
|
return JSON.stringify({
|
|
4449
4529
|
columnId: cell.column.id,
|
|
4450
4530
|
column: cell.column,
|
|
4451
|
-
row: wr.row
|
|
4531
|
+
row: this.cellSlotRow(wr.row),
|
|
4452
4532
|
value: cell.getValue()
|
|
4453
4533
|
});
|
|
4454
4534
|
} catch {
|
|
@@ -4639,13 +4719,13 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4639
4719
|
this.onToggleExpand(row, $event);
|
|
4640
4720
|
}} data-rozie-s-d5dcab4c>${rozieDisplay(this.rowIsExpanded(row) ? "▾" : "▸")}</button>` : nothing}</span>` : this.isSelectColumn(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
4641
4721
|
${this.selectCell !== void 0 ? this.selectCell({
|
|
4642
|
-
row: row
|
|
4722
|
+
row: this.cellSlotRow(row),
|
|
4643
4723
|
checked: this.rowIsSelected(row),
|
|
4644
4724
|
toggle: (e) => this.onToggleRow(row, e)
|
|
4645
4725
|
}) : html`<slot name="selectCell" data-rozie-params=${(() => {
|
|
4646
4726
|
try {
|
|
4647
4727
|
return JSON.stringify({
|
|
4648
|
-
row: row
|
|
4728
|
+
row: this.cellSlotRow(row),
|
|
4649
4729
|
checked: this.rowIsSelected(row)
|
|
4650
4730
|
});
|
|
4651
4731
|
} catch {
|
|
@@ -4664,14 +4744,14 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4664
4744
|
${this.cell !== void 0 ? this.cell({
|
|
4665
4745
|
columnId: cell.column.id,
|
|
4666
4746
|
column: cell.column,
|
|
4667
|
-
row: row
|
|
4747
|
+
row: this.cellSlotRow(row),
|
|
4668
4748
|
value: cell.getValue()
|
|
4669
4749
|
}) : html`<slot name="cell" data-rozie-params=${(() => {
|
|
4670
4750
|
try {
|
|
4671
4751
|
return JSON.stringify({
|
|
4672
4752
|
columnId: cell.column.id,
|
|
4673
4753
|
column: cell.column,
|
|
4674
|
-
row: row
|
|
4754
|
+
row: this.cellSlotRow(row),
|
|
4675
4755
|
value: cell.getValue()
|
|
4676
4756
|
});
|
|
4677
4757
|
} catch {
|
|
@@ -4685,7 +4765,7 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4685
4765
|
${this.editor !== void 0 ? this.editor({
|
|
4686
4766
|
columnId: cell.column.id,
|
|
4687
4767
|
column: cell.column,
|
|
4688
|
-
row: row
|
|
4768
|
+
row: this.cellSlotRow(row),
|
|
4689
4769
|
value: this.editorValueFor(cell.column.id),
|
|
4690
4770
|
commit: this.editorCommitFor(cell.column.id),
|
|
4691
4771
|
cancel: this.editorCancelFor(),
|
|
@@ -4695,7 +4775,7 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4695
4775
|
return JSON.stringify({
|
|
4696
4776
|
columnId: cell.column.id,
|
|
4697
4777
|
column: cell.column,
|
|
4698
|
-
row: row
|
|
4778
|
+
row: this.cellSlotRow(row),
|
|
4699
4779
|
value: this.editorValueFor(cell.column.id),
|
|
4700
4780
|
commit: this.editorCommitFor(cell.column.id),
|
|
4701
4781
|
cancel: this.editorCancelFor(),
|
|
@@ -4735,14 +4815,14 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4735
4815
|
${this.cell !== void 0 ? this.cell({
|
|
4736
4816
|
columnId: cell.column.id,
|
|
4737
4817
|
column: cell.column,
|
|
4738
|
-
row: row
|
|
4818
|
+
row: this.cellSlotRow(row),
|
|
4739
4819
|
value: cell.getValue()
|
|
4740
4820
|
}) : html`<slot name="cell" data-rozie-params=${(() => {
|
|
4741
4821
|
try {
|
|
4742
4822
|
return JSON.stringify({
|
|
4743
4823
|
columnId: cell.column.id,
|
|
4744
4824
|
column: cell.column,
|
|
4745
|
-
row: row
|
|
4825
|
+
row: this.cellSlotRow(row),
|
|
4746
4826
|
value: cell.getValue()
|
|
4747
4827
|
});
|
|
4748
4828
|
} catch {
|
package/package.json
CHANGED
package/src/DataTable.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { RozieSlotDistributor, createLitControllableProperty, rozieAttr, rozieDi
|
|
|
5
5
|
import { ContextProvider, createContext } from '@lit/context';
|
|
6
6
|
import { repeat } from 'lit/directives/repeat.js';
|
|
7
7
|
import '@rozie-ui/popover-lit';
|
|
8
|
-
import { isSafeKey, wrapAggregationFn } from './helpers/columnDefUtils';
|
|
8
|
+
import { isSafeKey, wrapAggregationFn, indexDefsById, collectGroupableLeafDefs } from './helpers/columnDefUtils';
|
|
9
9
|
import { applyUpdater, clamp, focusables } from './helpers/indexMath';
|
|
10
10
|
import { escapeTsvField, parseTsv, tileGridToBox, tileIndex } from './helpers/tsvGrid';
|
|
11
11
|
import { replaceRowValue, indexOfRowIn, replaceRowValues } from './helpers/rowValueUtils';
|
|
@@ -1335,22 +1335,22 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
1335
1335
|
|
|
1336
1336
|
${this.isExpanderColumn(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1337
1337
|
${this.rowCanExpand(wr.row) ? html`<button class="rdt-expander" type="button" data-expander="" aria-expanded=${!!this.rowIsExpanded(wr.row)} aria-label=${rozieAttr(this.rowIsExpanded(wr.row) ? 'Collapse row' : 'Expand row')} @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onToggleExpand(wr.row, $event); }} data-rozie-s-d5dcab4c>${rozieDisplay(this.rowIsExpanded(wr.row) ? '▾' : '▸')}</button>` : nothing}</span>` : this.isSelectColumn(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1338
|
-
${this.selectCell !== undefined ? this.selectCell({row: wr.row
|
|
1338
|
+
${this.selectCell !== undefined ? this.selectCell({row: this.cellSlotRow(wr.row), checked: this.rowIsSelected(wr.row), toggle: e => this.onToggleRow(wr.row, e)}) : html`<slot name="selectCell" data-rozie-params=${(() => { try { return JSON.stringify({row: this.cellSlotRow(wr.row), checked: this.rowIsSelected(wr.row)}); } catch { return '{}'; } })()} @rozie-select-cell-toggle=${($event: CustomEvent) => ((e => this.onToggleRow(wr.row, e)) as (...args: any[]) => any)($event.detail)}>
|
|
1339
1339
|
<input class="rdt-select-row" type="checkbox" aria-label="Select row" ?checked=${this.rowIsSelected(wr.row)} @change=${($event: Event & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onToggleRow(wr.row, $event); }} data-rozie-s-d5dcab4c />
|
|
1340
1340
|
</slot>`}
|
|
1341
1341
|
</span>` : this.cellIsGrouped(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1342
1342
|
<button class="rdt-expander rdt-group-toggle" type="button" data-expander="" aria-expanded=${!!this.rowIsExpanded(wr.row)} aria-label=${rozieAttr(this.rowIsExpanded(wr.row) ? 'Collapse group' : 'Expand group')} @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onToggleExpand(wr.row, $event); }} data-rozie-s-d5dcab4c>${rozieDisplay(this.rowIsExpanded(wr.row) ? '▾' : '▸')}</button>
|
|
1343
1343
|
<span class="rdt-group-value" data-rozie-s-d5dcab4c>
|
|
1344
|
-
${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: wr.row
|
|
1344
|
+
${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
|
|
1345
1345
|
</span>
|
|
1346
1346
|
<span class="rdt-group-count" data-rozie-s-d5dcab4c>${rozieDisplay('(' + this.groupSubRowCount(wr.row) + ')')}</span>
|
|
1347
1347
|
</span>` : this.isEditing(wr.vi.index, this.colIndexOf(wr.row, cell)) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1348
1348
|
${this.hasEditorSlot(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1349
|
-
${this.editor !== undefined ? this.editor({columnId: cell.column.id, column: cell.column, row: wr.row
|
|
1349
|
+
${this.editor !== undefined ? this.editor({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, wr.vi.index)}) : html`<slot name="editor" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, wr.vi.index)}); } catch { return '{}'; } })()}></slot>`}
|
|
1350
1350
|
</span>` : this.editorTypeOf(cell.column.id) === 'number' ? html`<input class="rdt-cell-editor" type="number" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : this.editorTypeOf(cell.column.id) === 'select' ? html`<select class="rdt-cell-editor" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c>
|
|
1351
1351
|
${repeat<any>(this.editorOptionsOf(cell.column.id), (opt, _idx) => opt.value, (opt, _idx) => html`<option value=${rozieAttr(opt.value)} data-rozie-s-d5dcab4c>${rozieDisplay(opt.label)}</option>`)}
|
|
1352
1352
|
</select>` : this.editorTypeOf(cell.column.id) === 'checkbox' ? html`<input class="rdt-cell-editor" type="checkbox" data-editing-cell="" ?checked=${this.editorCheckedFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorCheckbox(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : html`<input class="rdt-cell-editor" type="text" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />`}</span>` : this.cellIsPlaceholder(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : html`<span class="rdt-cell-value" data-rozie-s-d5dcab4c>
|
|
1353
|
-
${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: wr.row
|
|
1353
|
+
${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
|
|
1354
1354
|
</span>`}${this.isFillHandleCell(wr.vi.index, this.colIndexOf(wr.row, cell)) ? html`<span class="rdt-fill-handle" data-fill-handle="" data-testid="fill-handle" aria-hidden="true" @pointerdown=${($event: PointerEvent & { currentTarget: HTMLSpanElement; target: HTMLSpanElement }) => { this.onFillHandlePointerDown($event); }} data-rozie-s-d5dcab4c></span>` : nothing}</td>`)}
|
|
1355
1355
|
|
|
1356
1356
|
${this.colsWindowed() ? html`<td class="rdt-col-spacer" aria-hidden="true" style=${rozieStyle('width:' + this.colPadRight() + 'px;padding:0;border:0')} data-rozie-s-d5dcab4c></td>` : nothing}</tr>
|
|
@@ -1416,22 +1416,22 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
1416
1416
|
|
|
1417
1417
|
${this.isExpanderColumn(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1418
1418
|
${this.rowCanExpand(row) ? html`<button class="rdt-expander" type="button" data-expander="" aria-expanded=${!!this.rowIsExpanded(row)} aria-label=${rozieAttr(this.rowIsExpanded(row) ? 'Collapse row' : 'Expand row')} @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onToggleExpand(row, $event); }} data-rozie-s-d5dcab4c>${rozieDisplay(this.rowIsExpanded(row) ? '▾' : '▸')}</button>` : nothing}</span>` : this.isSelectColumn(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1419
|
-
${this.selectCell !== undefined ? this.selectCell({row: row
|
|
1419
|
+
${this.selectCell !== undefined ? this.selectCell({row: this.cellSlotRow(row), checked: this.rowIsSelected(row), toggle: e => this.onToggleRow(row, e)}) : html`<slot name="selectCell" data-rozie-params=${(() => { try { return JSON.stringify({row: this.cellSlotRow(row), checked: this.rowIsSelected(row)}); } catch { return '{}'; } })()} @rozie-select-cell-toggle=${($event: CustomEvent) => ((e => this.onToggleRow(row, e)) as (...args: any[]) => any)($event.detail)}>
|
|
1420
1420
|
<input class="rdt-select-row" type="checkbox" aria-label="Select row" ?checked=${this.rowIsSelected(row)} @change=${($event: Event & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onToggleRow(row, $event); }} data-rozie-s-d5dcab4c />
|
|
1421
1421
|
</slot>`}
|
|
1422
1422
|
</span>` : this.cellIsGrouped(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1423
1423
|
<button class="rdt-expander rdt-group-toggle" type="button" data-expander="" aria-expanded=${!!this.rowIsExpanded(row)} aria-label=${rozieAttr(this.rowIsExpanded(row) ? 'Collapse group' : 'Expand group')} @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onToggleExpand(row, $event); }} data-rozie-s-d5dcab4c>${rozieDisplay(this.rowIsExpanded(row) ? '▾' : '▸')}</button>
|
|
1424
1424
|
<span class="rdt-group-value" data-rozie-s-d5dcab4c>
|
|
1425
|
-
${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: row
|
|
1425
|
+
${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
|
|
1426
1426
|
</span>
|
|
1427
1427
|
<span class="rdt-group-count" data-rozie-s-d5dcab4c>${rozieDisplay('(' + this.groupSubRowCount(row) + ')')}</span>
|
|
1428
1428
|
</span>` : this.isEditing(this.rowIndexOf(row), this.colIndexOf(row, cell)) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1429
1429
|
${this.hasEditorSlot(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
|
|
1430
|
-
${this.editor !== undefined ? this.editor({columnId: cell.column.id, column: cell.column, row: row
|
|
1430
|
+
${this.editor !== undefined ? this.editor({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, this.rowIndexOf(row))}) : html`<slot name="editor" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, this.rowIndexOf(row))}); } catch { return '{}'; } })()}></slot>`}
|
|
1431
1431
|
</span>` : this.editorTypeOf(cell.column.id) === 'number' ? html`<input class="rdt-cell-editor" type="number" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : this.editorTypeOf(cell.column.id) === 'select' ? html`<select class="rdt-cell-editor" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c>
|
|
1432
1432
|
${repeat<any>(this.editorOptionsOf(cell.column.id), (opt, _idx) => opt.value, (opt, _idx) => html`<option value=${rozieAttr(opt.value)} data-rozie-s-d5dcab4c>${rozieDisplay(opt.label)}</option>`)}
|
|
1433
1433
|
</select>` : this.editorTypeOf(cell.column.id) === 'checkbox' ? html`<input class="rdt-cell-editor" type="checkbox" data-editing-cell="" ?checked=${this.editorCheckedFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorCheckbox(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : html`<input class="rdt-cell-editor" type="text" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />`}</span>` : this.cellIsPlaceholder(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : html`<span class="rdt-cell-value" data-rozie-s-d5dcab4c>
|
|
1434
|
-
${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: row
|
|
1434
|
+
${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
|
|
1435
1435
|
</span>`}${this.isFillHandleCell(this.rowIndexOf(row), this.colIndexOf(row, cell)) ? html`<span class="rdt-fill-handle" data-fill-handle="" data-testid="fill-handle" aria-hidden="true" @pointerdown=${($event: PointerEvent & { currentTarget: HTMLSpanElement; target: HTMLSpanElement }) => { this.onFillHandlePointerDown($event); }} data-rozie-s-d5dcab4c></span>` : nothing}</td>`)}
|
|
1436
1436
|
</tr>
|
|
1437
1437
|
|
|
@@ -1770,6 +1770,13 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
1770
1770
|
|
|
1771
1771
|
columnDefsCacheColRegRef: any = undefined;
|
|
1772
1772
|
|
|
1773
|
+
// B1 (quick 260906-afh) — the def-lookup index, populated INSIDE this SAME memo block on
|
|
1774
|
+
// a cache MISS only (never rebuilt per call — a per-call recursive scan would restore the
|
|
1775
|
+
// O(N^2 x M) blowup D-23 removed, T-AFH-03). A top-level `let` lowers to a per-instance
|
|
1776
|
+
// `useRef` on React (verified in the emitted leaf), so this is instance-scoped like
|
|
1777
|
+
// columnDefsCache above.
|
|
1778
|
+
columnDefsIndexCache: any = null;
|
|
1779
|
+
|
|
1773
1780
|
columnDefs = () => {
|
|
1774
1781
|
const cfg = this.columns || [];
|
|
1775
1782
|
const reg = this._colReg.value || {};
|
|
@@ -1818,9 +1825,20 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
1818
1825
|
this.columnDefsCache = out;
|
|
1819
1826
|
this.columnDefsCacheColumnsRef = this.columns;
|
|
1820
1827
|
this.columnDefsCacheColRegRef = this._colReg.value;
|
|
1828
|
+
this.columnDefsIndexCache = indexDefsById(out);
|
|
1821
1829
|
return out;
|
|
1822
1830
|
};
|
|
1823
1831
|
|
|
1832
|
+
// defIndex: the def-lookup map for the CURRENT columnDefs() array. Calling columnDefs()
|
|
1833
|
+
// first is deliberate — either an O(1) reference-equality cache hit (columnDefsIndexCache
|
|
1834
|
+
// is already fresh) or a miss that repopulates BOTH slots together, so the index can never
|
|
1835
|
+
// go stale relative to the array. Falls back to an empty null-prototype map (never null/
|
|
1836
|
+
// undefined) so a caller can read it unconditionally.
|
|
1837
|
+
defIndex = () => {
|
|
1838
|
+
this.columnDefs();
|
|
1839
|
+
return this.columnDefsIndexCache || Object.create(null);
|
|
1840
|
+
};
|
|
1841
|
+
|
|
1824
1842
|
// The constant id of the auto-injected leading checkbox column (D-04). Distinct from
|
|
1825
1843
|
// any consumer column id (the registry/config guard never produces a leading "__").
|
|
1826
1844
|
SELECT_COL_ID = '__rdt_select';
|
|
@@ -3560,10 +3578,18 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
3560
3578
|
|
|
3561
3579
|
// Template helpers reading the resolved column-def metadata by id (plain fns — used
|
|
3562
3580
|
// in template predicates + interpolation; uniform on all 6, no $computed alias trap).
|
|
3581
|
+
// B1 (quick 260906-afh): reads the O(1) def-lookup index (defIndex(), columnBuilders.rzts)
|
|
3582
|
+
// instead of linearly scanning columnDefs() — which only ever held TOP-LEVEL entries, so a
|
|
3583
|
+
// NESTED group leaf (a `columns:` group child) was invisible to every caller (headerLabel,
|
|
3584
|
+
// columnIsFilterable, editMetaOf/columnEditable/editorTypeOf/editorOptionsOf) and silently
|
|
3585
|
+
// took the "no def" fallback. defIndex() resolves both top-level AND nested leaf ids. This
|
|
3586
|
+
// also removes the per-cell O(N) scan D-23 left in place — defIndex() is memoized in the
|
|
3587
|
+
// SAME cache-invalidation block as columnDefs() itself, never rebuilt per call.
|
|
3563
3588
|
defFor = (colId: any) => {
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3589
|
+
if (colId == null) return null;
|
|
3590
|
+
const idx = this.defIndex();
|
|
3591
|
+
const d = idx[String(colId)];
|
|
3592
|
+
return d != null ? d : null;
|
|
3567
3593
|
};
|
|
3568
3594
|
|
|
3569
3595
|
// Per-row visible cells for the body loop. table-core memoizes row objects by id,
|
|
@@ -3925,6 +3951,15 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
3925
3951
|
// rowIsGrouped: this flattened row is a group-header row.
|
|
3926
3952
|
rowIsGrouped = (row: any) => !!(this.tick() >= 0 && row && row.getIsGrouped && row.getIsGrouped());
|
|
3927
3953
|
|
|
3954
|
+
// rowIndexIsGrouped (quick 260906-cvo, C1/C2): THE single row-level editability/writability
|
|
3955
|
+
// predicate — a group-header row is a SYNTHETIC row whose `original` is table-core's
|
|
3956
|
+
// `leafRows[0].original` (the same fact cellSlotRow's header comment documents), so any
|
|
3957
|
+
// edit or bulk write resolved through it silently lands on an UNRELATED record. Every edit/
|
|
3958
|
+
// write guard in this component calls THIS predicate — never a re-implemented inline
|
|
3959
|
+
// `getIsGrouped()` check — so the invariant has one definition. Indexes into the SAME
|
|
3960
|
+
// `$data.rows` flattened row list rowIsGrouped reads.
|
|
3961
|
+
rowIndexIsGrouped = (rowIndex: any) => this.rowIsGrouped((this._rows.value || [])[rowIndex]);
|
|
3962
|
+
|
|
3928
3963
|
// groupingActive: grouping is currently engaged (a non-empty ordered key list). Drives the
|
|
3929
3964
|
// data-group-leaf marker so it is ABSENT when ungrouped (byte-identical-off, req-10).
|
|
3930
3965
|
groupingActive = () => this.tick() >= 0 && (this.currentState().grouping || []).length > 0;
|
|
@@ -3937,34 +3972,119 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
3937
3972
|
|
|
3938
3973
|
cellIsAggregated = (cellCtx: any) => !!(this.tick() >= 0 && cellCtx && cellCtx.getIsAggregated && cellCtx.getIsAggregated());
|
|
3939
3974
|
|
|
3940
|
-
// cellIsPlaceholder:
|
|
3941
|
-
//
|
|
3942
|
-
//
|
|
3943
|
-
//
|
|
3944
|
-
//
|
|
3975
|
+
// cellIsPlaceholder: VERIFIED against @tanstack/table-core@8.21.3 (ColumnGrouping.js:120-121,
|
|
3976
|
+
// quick 260906-afh premise correction). A placeholder cell is a cell IN A GROUPING COLUMN
|
|
3977
|
+
// that is NOT the row's OWN grouping column — `!cell.getIsGrouped() && column.getIsGrouped()`.
|
|
3978
|
+
// That is true both on a group-header row (for every OTHER grouping column) and on every leaf
|
|
3979
|
+
// row (for every grouping column) — it is NOT "never true on a group-header row" and it is NOT
|
|
3980
|
+
// "any non-grouped, non-aggregated cell". The operative consequence for this component: a
|
|
3981
|
+
// placeholder can only EVER be a grouping-column cell, so this branch can never reach a
|
|
3982
|
+
// non-grouping column — it does NOT and CANNOT guard the AGGREGATED-cell `row` leak
|
|
3983
|
+
// (cellSlotRow, below) fixes. Where it DOES apply (e.g. under multi-level grouping, the
|
|
3984
|
+
// OTHER grouping column on a group-header row), table-core still fills cell.getValue() with
|
|
3985
|
+
// the FIRST leaf row's value (cell.getValue() leaks e.g. "Oslo" onto a region-level group
|
|
3986
|
+
// line whose grouping is 'region', not 'city'); this branch renders BLANK via a dedicated
|
|
3987
|
+
// empty template so that leaked value never paints. Tick-gated exactly like cellIsGrouped so
|
|
3988
|
+
// the group chrome re-derives on a re-pull on the fine-grained targets (Solid/Lit).
|
|
3945
3989
|
cellIsPlaceholder = (cellCtx: any) => !!(this.tick() >= 0 && cellCtx && cellCtx.getIsPlaceholder && cellCtx.getIsPlaceholder());
|
|
3946
3990
|
|
|
3947
|
-
// groupSubRowCount: the number of underlying LEAF RECORDS under a group-header row (the
|
|
3948
|
-
// shown in the header, e.g. "North (40)"). row.subRows is the IMMEDIATE members — for
|
|
3949
|
-
// grouping those are sub-GROUPS, not records, so "North" with 2 categories / 40
|
|
3950
|
-
// "North (2)"
|
|
3951
|
-
// subRows
|
|
3952
|
-
//
|
|
3953
|
-
|
|
3991
|
+
// groupSubRowCount: the number of underlying TRUE LEAF RECORDS under a group-header row (the
|
|
3992
|
+
// count shown in the header, e.g. "North (40)"). row.subRows is the IMMEDIATE members — for
|
|
3993
|
+
// MULTI-LEVEL grouping those are sub-GROUPS, not records, so "North" with 2 categories / 40
|
|
3994
|
+
// records would show "North (2)" off subRows alone. row.getLeafRows() is table-core's
|
|
3995
|
+
// `flattenBy(row.subRows, d => d.subRows)` (ColumnGrouping.js / utils.js, verified against
|
|
3996
|
+
// @tanstack/table-core@8.21.3) — it pushes EVERY node it walks, INCLUDING intermediate group
|
|
3997
|
+
// nodes, so under multi-level grouping it over-counts by exactly the number of sub-group
|
|
3998
|
+
// nodes between the row and its true leaves (C4, quick 260906-cvo: North with 2 city
|
|
3999
|
+
// sub-groups + 3 records reported 5, not 3). `row.getIsGrouped()` is `!!row.groupingColumnId`
|
|
4000
|
+
// — precisely the predicate that separates a group node from a real record — so filter the
|
|
4001
|
+
// flattened list on it rather than hand-rolling a recursive `subRows` walk (getLeafRows()
|
|
4002
|
+
// already flattens; the defect is purely that it does not filter). Single-level grouping is
|
|
4003
|
+
// numerically UNCHANGED: a leaf row has no `subRows`, so no node was ever miscounted there.
|
|
4004
|
+
groupSubRowCount = (row: any) => {
|
|
4005
|
+
if (row && row.getLeafRows) {
|
|
4006
|
+
const leaves = row.getLeafRows();
|
|
4007
|
+
let n = 0;
|
|
4008
|
+
for (let i = 0; i < leaves.length; i++) {
|
|
4009
|
+
const r = leaves[i];
|
|
4010
|
+
if (!(r && r.getIsGrouped && r.getIsGrouped())) n = n + 1;
|
|
4011
|
+
}
|
|
4012
|
+
return n;
|
|
4013
|
+
}
|
|
4014
|
+
return row && row.subRows ? row.subRows.length : 0;
|
|
4015
|
+
};
|
|
4016
|
+
|
|
4017
|
+
// ── B2 (quick 260906-afh) — group-header row #cell slot descriptor ─────────────────────
|
|
4018
|
+
// PROBLEM: table-core builds a flattened group-header row via
|
|
4019
|
+
// `createRow(table, id, leafRows[0].original, …)` (getGroupedRowModel.js), so `row.original`
|
|
4020
|
+
// on a group row IS the FIRST LEAF's record. The #cell scoped slot's existing 4 call sites
|
|
4021
|
+
// all bound `:row="row.original"` (or `wr.row.original`), so an AGGREGATED cell (a
|
|
4022
|
+
// non-grouping column on a group row — cellIsGrouped()===false, cellIsPlaceholder()===false,
|
|
4023
|
+
// so it takes the #cell r-else branch, same as any ordinary leaf cell) silently handed a
|
|
4024
|
+
// consumer template the WRONG record's fields (T-AFH-05). The grouped cell itself (the
|
|
4025
|
+
// group's own column, .rdt-group-value) has the same #cell binding and the same leak.
|
|
4026
|
+
//
|
|
4027
|
+
// FIX: `cellSlotRow(row)` returns a STABLE GROUP DESCRIPTOR — never `row.original` — for a
|
|
4028
|
+
// group-header row, and `row.original` unchanged for every other row. The descriptor is an
|
|
4029
|
+
// OBJECT, never `null` (T-AFH-06 — a consumer already reading `row.foo` would throw on
|
|
4030
|
+
// Vue/Angular if handed null).
|
|
4031
|
+
//
|
|
4032
|
+
// Descriptor cache (T-AFH-02/T-AFH-04): a null-prototype map keyed on `String(row.id)`,
|
|
4033
|
+
// invalidated wholesale whenever `$data.rowModelVer` (bumped by every refreshRowModel, the
|
|
4034
|
+
// SAME reactive re-derivation discipline visibleCellsFor/rowIsGrouped use) differs from the
|
|
4035
|
+
// generation the map was built for — so the descriptor's REFERENCE IDENTITY is stable
|
|
4036
|
+
// across every cell of one group row within a row-model generation (an unstable reference
|
|
4037
|
+
// would thrash the fine-grained targets, Solid/Lit) and refreshed the moment the grouping
|
|
4038
|
+
// changes. Group row ids are built from consumer grouping VALUES, so the map MUST be
|
|
4039
|
+
// null-prototype — a `__proto__` grouping value must not reach Object.prototype.
|
|
4040
|
+
groupRowDescriptorCache: any = null;
|
|
4041
|
+
|
|
4042
|
+
groupRowDescriptorCacheVer: any = undefined;
|
|
4043
|
+
|
|
4044
|
+
groupRowDescriptor = (row: any) => {
|
|
4045
|
+
const ver = this._rowModelVer.value;
|
|
4046
|
+
if (!this.groupRowDescriptorCache || this.groupRowDescriptorCacheVer !== ver) {
|
|
4047
|
+
this.groupRowDescriptorCache = Object.create(null);
|
|
4048
|
+
this.groupRowDescriptorCacheVer = ver;
|
|
4049
|
+
}
|
|
4050
|
+
const key = String(row.id);
|
|
4051
|
+
let d = this.groupRowDescriptorCache[key];
|
|
4052
|
+
if (!d) {
|
|
4053
|
+
const groupingColumnId = row.groupingColumnId != null ? row.groupingColumnId : '';
|
|
4054
|
+
const groupingValue = row.getGroupingValue ? row.getGroupingValue(groupingColumnId) : row.groupingValue;
|
|
4055
|
+
d = {
|
|
4056
|
+
isGroupRow: true,
|
|
4057
|
+
groupId: row.id,
|
|
4058
|
+
groupingColumnId,
|
|
4059
|
+
groupingValue,
|
|
4060
|
+
leafCount: this.groupSubRowCount(row)
|
|
4061
|
+
};
|
|
4062
|
+
this.groupRowDescriptorCache[key] = d;
|
|
4063
|
+
}
|
|
4064
|
+
return d;
|
|
4065
|
+
};
|
|
4066
|
+
|
|
4067
|
+
// cellSlotRow: the #cell slot's `:row=` value. A group-header row gets the stable
|
|
4068
|
+
// descriptor above (never the leaked first-leaf record); every other row is unchanged.
|
|
4069
|
+
cellSlotRow = (row: any) => this.rowIsGrouped(row) ? this.groupRowDescriptor(row) : row ? row.original : null;
|
|
3954
4070
|
|
|
3955
4071
|
// groupingKeys: the live ordered grouping array — slot prop for the headless #groupBar + the
|
|
3956
4072
|
// default styled-token reflection. Reads currentState() ($props.grouping ?? $data.groupingDefault),
|
|
3957
4073
|
// both reactive sources, so the bar re-renders on a grouping change across all six targets.
|
|
3958
4074
|
groupingKeys = () => this.currentState().grouping || [];
|
|
3959
4075
|
|
|
3960
|
-
// groupableColumns: the data columns OFFERED to the headless #groupBar
|
|
3961
|
-
//
|
|
3962
|
-
//
|
|
4076
|
+
// groupableColumns: the data columns OFFERED to the headless #groupBar — `[{ id, label }]`.
|
|
4077
|
+
// Excludes the chrome columns (select/expander are not in columnDefs()). C5+C6 (quick
|
|
4078
|
+
// 260906-cvo): delegates the actual walk to collectGroupableLeafDefs (columnDefUtils.ts) —
|
|
4079
|
+
// a GROUP column (a `columns:` group's own entry) is NEVER offered (it has no accessor and
|
|
4080
|
+
// cannot produce a grouping value, regardless of any `groupable` flag on it), and every
|
|
4081
|
+
// groupable NESTED leaf (a `columns:` group child, opted out via `groupable: false` like any
|
|
4082
|
+
// top-level leaf) IS offered, in declaration order. The consumer builds any bar/drag UI from
|
|
4083
|
+
// this; the component ships none.
|
|
3963
4084
|
groupableColumns = () => {
|
|
3964
4085
|
const out = [];
|
|
3965
|
-
const defs = this.columnDefs();
|
|
4086
|
+
const defs = collectGroupableLeafDefs(this.columnDefs());
|
|
3966
4087
|
for (const d of defs as any) {
|
|
3967
|
-
if (!d || d.groupable === false) continue;
|
|
3968
4088
|
out.push({
|
|
3969
4089
|
id: d.id,
|
|
3970
4090
|
label: d.header != null ? d.header : d.id
|
|
@@ -4976,11 +5096,18 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
4976
5096
|
return;
|
|
4977
5097
|
}
|
|
4978
5098
|
// ── C2 (phase 63 wave-8): Enter on a GROUP-HEADER cell toggles that group's collapse/
|
|
4979
|
-
// expand (APG treegrid).
|
|
4980
|
-
//
|
|
4981
|
-
//
|
|
4982
|
-
//
|
|
4983
|
-
//
|
|
5099
|
+
// expand (APG treegrid). C1 (quick 260906-cvo) CORRECTION: the comment here used to claim
|
|
5100
|
+
// "a group cell is non-editable" as "the verified invariant" — that was FALSE AS WRITTEN.
|
|
5101
|
+
// It held only for the grouping column's OWN cell (cellIsGrouped's branch renders before
|
|
5102
|
+
// the editor branch); a non-grouping EDITABLE column's cell on a group row fell straight
|
|
5103
|
+
// through the branch chain to isEditing(...) and opened an editor (the C1 defect this
|
|
5104
|
+
// quick task closed). What is now TRUE, and WHY: isActiveCellEditable() carries an
|
|
5105
|
+
// explicit rowIndexIsGrouped(...) row guard (filterPaginationRowChrome.rzts), so EVERY
|
|
5106
|
+
// editable column's cell on a group row is non-editable — that is what makes the four
|
|
5107
|
+
// edit-entry branches above fall through to this one, not an incidental property of the
|
|
5108
|
+
// grouping column alone. Route it to the SAME onToggleExpand path the chevron uses (group
|
|
5109
|
+
// rows ride the expand model) so one Enter toggles the group. Body cells only (a
|
|
5110
|
+
// header-active Enter is unchanged);
|
|
4984
5111
|
// ($data.rows || [])[$data.activeRow] is the active flattened row (page-relative non-virtual /
|
|
4985
5112
|
// full-model virtual — both index $data.rows). Placed BEFORE the reserved enterControl branch.
|
|
4986
5113
|
else if (key === 'Enter' && !this._activeIsHeader.value && this.rowIsGrouped((this._rows.value || [])[this._activeRow.value])) {
|
|
@@ -5777,6 +5904,11 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
5777
5904
|
// rangeToTsv(): serialize the current range to TSV — rows joined by '\n', cells by '\t',
|
|
5778
5905
|
// reading each cell's value off the visible model by index (cellValueAt). A single active
|
|
5779
5906
|
// cell (no range) serializes that one cell. Each field is B10-escaped. Pure read — never writes.
|
|
5907
|
+
// C2 (quick 260906-cvo) — DELIBERATE NON-CHANGE: this is a READ, unlike applyGridToRange's
|
|
5908
|
+
// write funnel, and stays UNGUARDED for a group-header row on purpose. cellValueAt reads the
|
|
5909
|
+
// column's DISPLAYED aggregate value on a group row (table-core's cell.getValue()), which is
|
|
5910
|
+
// exactly what the user sees — serializing it is correct behavior, not a leak. Do not "fix"
|
|
5911
|
+
// this asymmetry; it is intentional.
|
|
5780
5912
|
rangeToTsv = () => {
|
|
5781
5913
|
const box = this.normalizedRange();
|
|
5782
5914
|
const r0 = box ? box.r0 : this._activeRow.value;
|
|
@@ -5830,11 +5962,22 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
5830
5962
|
for (let gr = 0; gr < grid.length; gr++) {
|
|
5831
5963
|
const r = originRow + gr;
|
|
5832
5964
|
if (r > maxRow) break;
|
|
5965
|
+
// C2 (quick 260906-cvo) — hoisted ONCE per ROW (never per cell): a group-header row's
|
|
5966
|
+
// `original` is table-core's `leafRows[0].original` (a synthetic row), so a write
|
|
5967
|
+
// resolved through it silently lands on an unrelated record. This ONE placement closes
|
|
5968
|
+
// pasteRange, cutRange, clearActiveRange AND fillRange — all four build a grid and hand
|
|
5969
|
+
// it to this single funnel, so guarding the four callers individually would be four
|
|
5970
|
+
// chances to miss one.
|
|
5971
|
+
const rowGrouped = this.rowIndexIsGrouped(r);
|
|
5833
5972
|
const cols = grid[gr] || [];
|
|
5834
5973
|
for (let gc = 0; gc < cols.length; gc++) {
|
|
5835
5974
|
const c = originCol + gc;
|
|
5836
5975
|
if (c > maxCol) break;
|
|
5976
|
+
// A group-row cell still counts toward `total` — it is a skipped TARGET, exactly like
|
|
5977
|
+
// a non-editable or validator-rejected cell — so the "N of M cells pasted" / "no cells
|
|
5978
|
+
// pasted" announce keeps its existing semantics (never silently under-reports M).
|
|
5837
5979
|
total = total + 1;
|
|
5980
|
+
if (rowGrouped) continue;
|
|
5838
5981
|
const colId = this.columnIdAt(r, c);
|
|
5839
5982
|
if (colId == null || !this.columnEditable(colId)) continue;
|
|
5840
5983
|
const rowObj = this.rowOriginalAt(r);
|
|
@@ -6356,7 +6499,13 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
6356
6499
|
// isActiveCellEditable: the active cell sits in an editable column AND is a body cell
|
|
6357
6500
|
// (req-1). Gates the F2/Enter/printable edit-entry branches in onGridKeyDown; a
|
|
6358
6501
|
// non-editable active cell falls through to the reserved enterControl path.
|
|
6502
|
+
// C1 (quick 260906-cvo) — Layer 1: a group-header row is NEVER editable, regardless of
|
|
6503
|
+
// column. This is the single highest-value guard in the cluster: it closes Shift+F2, the
|
|
6504
|
+
// checkbox toggle, and the F2/Enter/printable edit-entry branches in ONE edit (they are all
|
|
6505
|
+
// `else if` branches gated on this predicate), AND restores fallthrough so Enter on a group
|
|
6506
|
+
// row reaches the group-toggle branch below them instead of opening an editor.
|
|
6359
6507
|
isActiveCellEditable = () => {
|
|
6508
|
+
if (this.rowIndexIsGrouped(this._activeRow.value)) return false;
|
|
6360
6509
|
const colId = this.activeCellColumnId();
|
|
6361
6510
|
return colId != null && this.columnEditable(colId);
|
|
6362
6511
|
};
|
|
@@ -6374,6 +6523,14 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
6374
6523
|
// non-virtual, wr.vi.index virtual).
|
|
6375
6524
|
isEditing = (rowIndex: any, colIndex: any) => {
|
|
6376
6525
|
if (this._editVer.value < 0) return false;
|
|
6526
|
+
// C1 (quick 260906-cvo) — Layer 6: the ONLY layer whose reachability does not depend on a
|
|
6527
|
+
// keystroke. Editing state is INDEX-based over the visible model, and nothing clears it
|
|
6528
|
+
// when the row model re-derives — a consumer that changes the grouping model WHILE a cell
|
|
6529
|
+
// editor is open can move a group-header row under the index $data.editingRow/
|
|
6530
|
+
// editingRowIndex still holds, rendering the editor on a group row with no beginEdit
|
|
6531
|
+
// involved. Placed AFTER the editVer read (preserves the Svelte/Solid re-derivation
|
|
6532
|
+
// discipline the header comment above documents).
|
|
6533
|
+
if (this.rowIndexIsGrouped(rowIndex)) return false;
|
|
6377
6534
|
if (this._editingRowIndex.value != null && this._editingRowIndex.value === rowIndex) {
|
|
6378
6535
|
const colId = this.columnIdAt(rowIndex, colIndex);
|
|
6379
6536
|
return colId != null && this.columnEditable(colId);
|
|
@@ -6551,6 +6708,10 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
6551
6708
|
// $data) so a Tab-advance that just setState'd activeRow/Col works on React. Clears any
|
|
6552
6709
|
// prior invalid state. Focus moves into the editor.
|
|
6553
6710
|
beginEdit = (rowIndex: any, colIndex: any, seed: any) => {
|
|
6711
|
+
// C1 (quick 260906-cvo) — Layer 2: closes the `onGridClick` (singleClickEdit) path, which
|
|
6712
|
+
// calls beginEdit directly gated ONLY on columnEditable — isActiveCellEditable (Layer 1)
|
|
6713
|
+
// does not run on that path at all.
|
|
6714
|
+
if (this.rowIndexIsGrouped(rowIndex)) return;
|
|
6554
6715
|
const colId = this.columnIdAt(rowIndex, colIndex);
|
|
6555
6716
|
if (colId == null || !this.columnEditable(colId)) return;
|
|
6556
6717
|
// A new edit session starts — reset the sync idempotency latch so THIS session's eventual
|
|
@@ -6761,6 +6922,11 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
6761
6922
|
// editor:'checkbox' columns only (Space/Enter/F2), full-row edit mode is unaffected (the
|
|
6762
6923
|
// editingRowIndex early return in onGridKeyDown already excludes it).
|
|
6763
6924
|
toggleActiveBooleanCell = () => {
|
|
6925
|
+
// C1 (quick 260906-cvo) — Layer 4: the only write funnel bypassing both beginEdit/
|
|
6926
|
+
// commitEdit and applyGridToRange. Reachable today only through the Layer-1-gated
|
|
6927
|
+
// checkbox branch, so this line is redundant AT HEAD — it earns its place by making "no
|
|
6928
|
+
// write ever targets a group row" a property of the write funnels themselves.
|
|
6929
|
+
if (this.rowIndexIsGrouped(this._activeRow.value)) return;
|
|
6764
6930
|
const colId = this.columnIdAt(this._activeRow.value, this._activeColIndex.value);
|
|
6765
6931
|
if (colId == null || !this.columnEditable(colId)) return;
|
|
6766
6932
|
const rowList = this._rows.value || [];
|
|
@@ -6892,6 +7058,11 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
|
|
|
6892
7058
|
beginRowEdit = (row: any) => {
|
|
6893
7059
|
const rowIndex = this.rowIndexOf(row);
|
|
6894
7060
|
if (rowIndex < 0) return;
|
|
7061
|
+
// C1 (quick 260906-cvo) — Layer 5: a second, independent editing-state funnel that takes a
|
|
7062
|
+
// row OBJECT from its caller. Reachable today only via Shift+F2 (Layer 1), so also
|
|
7063
|
+
// redundant at HEAD; kept for the same reason as Layer 4 — it is a mutation entry point,
|
|
7064
|
+
// and the natural call site for a future #rowActions "Edit" drop-in button.
|
|
7065
|
+
if (this.rowIndexIsGrouped(rowIndex)) return;
|
|
6895
7066
|
const editable = this.editableColumnsForRow(rowIndex);
|
|
6896
7067
|
if (editable.length === 0) return;
|
|
6897
7068
|
// A new edit session starts — reset the sync idempotency latch (see editCellLifecycle.rzts).
|
|
@@ -32,4 +32,80 @@ const wrapAggregationFn = (fn: any) => {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
// ── B1 (quick 260906-afh) — nested group leaf def index ─────────────────────────────
|
|
36
|
+
// LOOKUP-ONLY. This map is never fed to table-core (it does not replace/reshape the
|
|
37
|
+
// columnDefs() array table-core consumes for createTable/setOptions — that stays
|
|
38
|
+
// byte-identical); it exists purely so `defFor(colId)` (columnChrome.rzts) can resolve
|
|
39
|
+
// a NESTED leaf's def (a `columns:` group child) in O(1), the same as a top-level leaf.
|
|
40
|
+
//
|
|
41
|
+
// collectNestedDefs: depth-first walk of a `columns` array (each entry may itself carry
|
|
42
|
+
// a nested `columns` array — 3+ levels deep is supported). Writes `out[String(d.id)] = d`
|
|
43
|
+
// ONLY when the id is ABSENT from `out` — first-write-wins so a caller can pre-seed `out`
|
|
44
|
+
// with the higher-precedence top-level defs and this pass only ever fills GAPS.
|
|
45
|
+
const collectNestedDefs = (list: any, out: any) => {
|
|
46
|
+
if (!Array.isArray(list)) return
|
|
47
|
+
for (const d of list) {
|
|
48
|
+
if (!d || d.id == null) continue
|
|
49
|
+
const id = String(d.id)
|
|
50
|
+
if (!(id in out)) out[id] = d
|
|
51
|
+
if (Array.isArray(d.columns)) collectNestedDefs(d.columns, out)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// indexDefsById: builds a null-prototype `{ id: def }` map from a `columnDefs()`-shaped
|
|
56
|
+
// array in TWO passes. Pass 1 registers every TOP-LEVEL def unconditionally — so any id
|
|
57
|
+
// that already resolves at HEAD (a top-level leaf OR a top-level group's OWN id) keeps
|
|
58
|
+
// resolving to the EXACT SAME def, the byte-identical-lookup guarantee for every
|
|
59
|
+
// pre-existing caller. Pass 2 walks each top-level entry's `columns` (if any) via
|
|
60
|
+
// collectNestedDefs, so a nested leaf only fills a GAP — it can never shadow a
|
|
61
|
+
// same-named top-level id (top-level wins regardless of array order). Object.create(null)
|
|
62
|
+
// (T-AFH-01): a consumer column id of "__proto__"/"constructor" cannot pollute
|
|
63
|
+
// Object.prototype through this map — mirrors the existing `byId` T-48-PP guard in
|
|
64
|
+
// columnBuilders.rzts.
|
|
65
|
+
const indexDefsById = (defs: any): any => {
|
|
66
|
+
const out = Object.create(null)
|
|
67
|
+
if (!Array.isArray(defs)) return out
|
|
68
|
+
for (const d of defs) {
|
|
69
|
+
if (!d || d.id == null) continue
|
|
70
|
+
out[String(d.id)] = d
|
|
71
|
+
}
|
|
72
|
+
for (const d of defs) {
|
|
73
|
+
if (d && Array.isArray(d.columns)) collectNestedDefs(d.columns, out)
|
|
74
|
+
}
|
|
75
|
+
return out
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── C5+C6 (quick 260906-cvo) — groupable-leaf collection for the #groupBar ──────────────
|
|
79
|
+
// C5: buildConfigDef's GROUP branch (columnBuilders.rzts) returns `{ id, header, columns }`
|
|
80
|
+
// with NO `groupable` key and no accessor, so the OLD `groupableColumns()` loop's
|
|
81
|
+
// `d.groupable === false` skip never fired for a group column — it was wrongly OFFERED to
|
|
82
|
+
// the bar even though a group column can never produce a grouping value.
|
|
83
|
+
// C6: that same loop walked TOP-LEVEL `columnDefs()` entries only, so a genuinely groupable
|
|
84
|
+
// NESTED leaf (a `columns:` group child) was never offered at all.
|
|
85
|
+
//
|
|
86
|
+
// collectGroupableLeafDefs: a DEDICATED depth-first walk, NOT a reuse of `indexDefsById`.
|
|
87
|
+
// `indexDefsById` is a LOOKUP index — it deliberately registers group columns too (a group
|
|
88
|
+
// id must keep resolving for `defFor`), and its insertion order is all-top-level-first-then-
|
|
89
|
+
// nested, which would both offer group columns AND hand the group bar an order that does not
|
|
90
|
+
// match the rendered header order. This walk instead: recurses into a `columns:` array
|
|
91
|
+
// WITHOUT ever pushing the group entry itself (closes C5 — a group column has no accessor
|
|
92
|
+
// and cannot be a grouping target, so an explicit `groupable: true` on a group entry is
|
|
93
|
+
// meaningless and is likewise never pushed); pushes every other (leaf) entry unless it opts
|
|
94
|
+
// out via `groupable === false` (closes C6 — nested leaves are now reachable); walks in
|
|
95
|
+
// DECLARATION order, depth-first, matching the rendered header order.
|
|
96
|
+
const collectGroupableLeafDefs = (defs: any): any[] => {
|
|
97
|
+
const out: any[] = []
|
|
98
|
+
if (!Array.isArray(defs)) return out
|
|
99
|
+
for (const d of defs) {
|
|
100
|
+
if (!d) continue
|
|
101
|
+
if (Array.isArray(d.columns)) {
|
|
102
|
+
out.push(...collectGroupableLeafDefs(d.columns))
|
|
103
|
+
continue
|
|
104
|
+
}
|
|
105
|
+
if (d.groupable === false) continue
|
|
106
|
+
out.push(d)
|
|
107
|
+
}
|
|
108
|
+
return out
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { isSafeKey, wrapAggregationFn, collectNestedDefs, indexDefsById, collectGroupableLeafDefs }
|