@rickcedwhat/playwright-smart-table 6.18.0 → 6.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine/rowFinder.d.ts +16 -1
- package/dist/engine/rowFinder.js +156 -83
- package/dist/engine/rowResolution.d.ts +35 -0
- package/dist/engine/rowResolution.js +78 -0
- package/dist/engine/tableIteration.d.ts +4 -2
- package/dist/engine/tableIteration.js +72 -57
- package/dist/engine/tableMapper.js +10 -3
- package/dist/index.d.ts +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/plugins/index.d.ts +9 -3
- package/dist/presets/glide/headers.js +6 -3
- package/dist/presets/mui.js +28 -1
- package/dist/smartRow.js +240 -48
- package/dist/strategies/fill.js +5 -2
- package/dist/strategies/headers.js +6 -3
- package/dist/strategies/viewport.js +46 -3
- package/dist/typeContext.d.ts +1 -1
- package/dist/typeContext.js +146 -16
- package/dist/types.d.ts +140 -14
- package/dist/useTable.js +202 -26
- package/dist/utils/mergeTableConfig.js +4 -0
- package/package.json +1 -1
package/dist/useTable.js
CHANGED
|
@@ -27,6 +27,7 @@ const filterEngine_1 = require("./filterEngine");
|
|
|
27
27
|
const tableMapper_1 = require("./engine/tableMapper");
|
|
28
28
|
const rowFinder_1 = require("./engine/rowFinder");
|
|
29
29
|
const tableIteration_1 = require("./engine/tableIteration");
|
|
30
|
+
const rowResolution_1 = require("./engine/rowResolution");
|
|
30
31
|
const debugUtils_1 = require("./utils/debugUtils");
|
|
31
32
|
const smartRowArray_1 = require("./utils/smartRowArray");
|
|
32
33
|
const elementTracker_1 = require("./utils/elementTracker");
|
|
@@ -69,9 +70,11 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
69
70
|
const vp = config.strategies.viewport;
|
|
70
71
|
let colRangeCache = null;
|
|
71
72
|
let rowRangeCache = null;
|
|
73
|
+
let rowIndicesCache = null;
|
|
72
74
|
_clearViewportCache = () => {
|
|
73
75
|
colRangeCache = null;
|
|
74
76
|
rowRangeCache = null;
|
|
77
|
+
rowIndicesCache = null;
|
|
75
78
|
};
|
|
76
79
|
config.strategies.viewport = Object.assign(Object.assign({}, vp), { getVisibleColumnRange: vp.getVisibleColumnRange
|
|
77
80
|
? async (ctx) => {
|
|
@@ -85,15 +88,23 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
85
88
|
rowRangeCache = await vp.getVisibleRowRange(ctx);
|
|
86
89
|
return rowRangeCache;
|
|
87
90
|
}
|
|
91
|
+
: undefined, getVisibleRowIndices: vp.getVisibleRowIndices
|
|
92
|
+
? async (ctx) => {
|
|
93
|
+
if (!rowIndicesCache)
|
|
94
|
+
rowIndicesCache = await vp.getVisibleRowIndices(ctx);
|
|
95
|
+
return rowIndicesCache;
|
|
96
|
+
}
|
|
88
97
|
: undefined, scrollToColumn: vp.scrollToColumn
|
|
89
98
|
? async (ctx, colIndex) => {
|
|
90
99
|
colRangeCache = null;
|
|
91
100
|
rowRangeCache = null;
|
|
101
|
+
rowIndicesCache = null;
|
|
92
102
|
await vp.scrollToColumn(ctx, colIndex);
|
|
93
103
|
}
|
|
94
104
|
: undefined, scrollToRow: vp.scrollToRow
|
|
95
105
|
? async (ctx, rowIndex) => {
|
|
96
106
|
rowRangeCache = null;
|
|
107
|
+
rowIndicesCache = null;
|
|
97
108
|
await vp.scrollToRow(ctx, rowIndex);
|
|
98
109
|
}
|
|
99
110
|
: undefined });
|
|
@@ -134,10 +145,16 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
134
145
|
// Placeholder for the final table object
|
|
135
146
|
let finalTable = null;
|
|
136
147
|
// Helper factory
|
|
137
|
-
const _makeSmart = (rowLocator, map, rowIndex, tablePageIndex, barrier) => {
|
|
138
|
-
|
|
148
|
+
const _makeSmart = (rowLocator, map, rowIndex, tablePageIndex, barrier, rowSelector) => {
|
|
149
|
+
const effectiveLocator = rowSelector
|
|
150
|
+
? rootLocator.locator(rowSelector)
|
|
151
|
+
: rowLocator;
|
|
152
|
+
const sr = (0, smartRow_1.default)(effectiveLocator, map, rowIndex, config, rootLocator, resolve, finalTable, tablePageIndex, barrier);
|
|
153
|
+
if (rowSelector)
|
|
154
|
+
sr._selfHealing = true;
|
|
155
|
+
return sr;
|
|
139
156
|
};
|
|
140
|
-
const tableState = { currentPageIndex: 0 };
|
|
157
|
+
const tableState = { currentPageIndex: 0, empty: false };
|
|
141
158
|
const rowFinder = new rowFinder_1.RowFinder(rootLocator, config, resolve, filterEngine, tableMapper, _makeSmart, tableState, (useBulk) => _advancePage(useBulk));
|
|
142
159
|
/** Builds a full TableContext/StrategyContext with getHeaderCell, getHeaders, scrollToColumn. Set after result is created. */
|
|
143
160
|
let createStrategyContext = () => ({ root: rootLocator, config, page: rootLocator.page(), resolve });
|
|
@@ -215,7 +232,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
215
232
|
set currentPageIndex(v) { tableState.currentPageIndex = v; },
|
|
216
233
|
init: async (options) => {
|
|
217
234
|
var _a;
|
|
218
|
-
if (tableMapper.isInitialized())
|
|
235
|
+
if (tableMapper.isInitialized() || tableState.empty)
|
|
219
236
|
return result;
|
|
220
237
|
if (config.strategies.sorting)
|
|
221
238
|
(0, validation_1.validateSortingStrategy)(config.strategies.sorting);
|
|
@@ -223,7 +240,21 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
223
240
|
(0, validation_1.validateFillStrategy)(config.strategies.fill);
|
|
224
241
|
(0, debugUtils_1.warnIfDebugInCI)(config);
|
|
225
242
|
(0, debugUtils_1.logDebug)(config, 'info', 'Initializing table');
|
|
226
|
-
|
|
243
|
+
let map;
|
|
244
|
+
try {
|
|
245
|
+
map = await tableMapper.getMap(options === null || options === void 0 ? void 0 : options.timeout);
|
|
246
|
+
}
|
|
247
|
+
catch (headerError) {
|
|
248
|
+
if (config.emptyState) {
|
|
249
|
+
const visible = await config.emptyState.isVisible().catch(() => false);
|
|
250
|
+
if (visible) {
|
|
251
|
+
tableState.empty = true;
|
|
252
|
+
(0, debugUtils_1.logDebug)(config, 'info', 'init: header resolution failed but emptyState locator is visible — table is empty');
|
|
253
|
+
return result;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
throw headerError;
|
|
257
|
+
}
|
|
227
258
|
(0, debugUtils_1.logDebug)(config, 'info', `Table initialized with ${map.size} columns`, Array.from(map.keys()));
|
|
228
259
|
if ((_a = config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.detectCurrentPage) {
|
|
229
260
|
try {
|
|
@@ -256,9 +287,10 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
256
287
|
await headerCell.scrollIntoViewIfNeeded();
|
|
257
288
|
},
|
|
258
289
|
getHeaders: async () => {
|
|
290
|
+
var _a;
|
|
259
291
|
log("getHeaders: fetching available columns");
|
|
260
292
|
const map = await tableMapper.getMap();
|
|
261
|
-
return
|
|
293
|
+
return [...map.keys(), ...Object.keys((_a = config.syntheticColumns) !== null && _a !== void 0 ? _a : {})];
|
|
262
294
|
},
|
|
263
295
|
getHeaderCell: async (columnName) => {
|
|
264
296
|
log(`getHeaderCell: column="${columnName}"`);
|
|
@@ -268,25 +300,86 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
268
300
|
throw _createColumnError(columnName, map, 'header cell');
|
|
269
301
|
return resolve(config.headerSelector, rootLocator).nth(idx);
|
|
270
302
|
},
|
|
271
|
-
countRows: async () => {
|
|
303
|
+
countRows: async (filters, options) => {
|
|
304
|
+
var _a, _b, _c, _d;
|
|
305
|
+
if (tableState.empty)
|
|
306
|
+
return 0;
|
|
272
307
|
await _autoInit();
|
|
308
|
+
const filtersRecord = (filters !== null && filters !== void 0 ? filters : {});
|
|
309
|
+
const hasFilters = Object.keys(filtersRecord).length > 0;
|
|
310
|
+
const effectiveMaxPages = (_a = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
|
|
273
311
|
const pag = config.strategies.pagination;
|
|
274
|
-
const hasPagination =
|
|
312
|
+
const hasPagination = effectiveMaxPages > 1 && !!((pag === null || pag === void 0 ? void 0 : pag.goNext) || (pag === null || pag === void 0 ? void 0 : pag.goNextBulk));
|
|
313
|
+
const domFilters = {};
|
|
314
|
+
const overrideFilters = {};
|
|
315
|
+
const syntheticFilters = {};
|
|
316
|
+
if (hasFilters) {
|
|
317
|
+
for (const [key, value] of Object.entries(filtersRecord)) {
|
|
318
|
+
if ((_b = config.syntheticColumns) === null || _b === void 0 ? void 0 : _b[key]) {
|
|
319
|
+
syntheticFilters[key] = value;
|
|
320
|
+
}
|
|
321
|
+
else if ((_d = (_c = config.columnOverrides) === null || _c === void 0 ? void 0 : _c[key]) === null || _d === void 0 ? void 0 : _d.read) {
|
|
322
|
+
overrideFilters[key] = value;
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
domFilters[key] = value;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const hasPostFilters = Object.keys(overrideFilters).length > 0 || Object.keys(syntheticFilters).length > 0;
|
|
330
|
+
const resolveRows = () => {
|
|
331
|
+
var _a;
|
|
332
|
+
let rows = resolve(config.rowSelector, rootLocator);
|
|
333
|
+
if (Object.keys(domFilters).length > 0) {
|
|
334
|
+
const map = tableMapper.getMapSync();
|
|
335
|
+
if (!map)
|
|
336
|
+
throw new Error('Initialization Error: Table map not available. Call "await table.init()" first.');
|
|
337
|
+
rows = filterEngine.applyFilters(rows, domFilters, map, (_a = options === null || options === void 0 ? void 0 : options.exact) !== null && _a !== void 0 ? _a : false, rootLocator.page(), rootLocator);
|
|
338
|
+
}
|
|
339
|
+
return rows;
|
|
340
|
+
};
|
|
341
|
+
const countPostFilterMatches = async (candidates, indices) => {
|
|
342
|
+
var _a;
|
|
343
|
+
if (!hasPostFilters)
|
|
344
|
+
return indices.length;
|
|
345
|
+
const map = tableMapper.getMapSync();
|
|
346
|
+
if (!map)
|
|
347
|
+
throw new Error('Initialization Error: Table map not available. Call "await table.init()" first.');
|
|
348
|
+
const exact = (_a = options === null || options === void 0 ? void 0 : options.exact) !== null && _a !== void 0 ? _a : false;
|
|
349
|
+
const hasOverrides = Object.keys(overrideFilters).length > 0;
|
|
350
|
+
const hasSynthetics = Object.keys(syntheticFilters).length > 0;
|
|
351
|
+
let count = 0;
|
|
352
|
+
for (const idx of indices) {
|
|
353
|
+
const row = candidates[idx];
|
|
354
|
+
if (hasOverrides && !await rowFinder.matchesOverrideFilters(row, overrideFilters, map, exact))
|
|
355
|
+
continue;
|
|
356
|
+
if (hasSynthetics && !await rowFinder.matchesSyntheticFilters(row, syntheticFilters, map, exact))
|
|
357
|
+
continue;
|
|
358
|
+
count++;
|
|
359
|
+
}
|
|
360
|
+
return count;
|
|
361
|
+
};
|
|
275
362
|
if (!hasPagination) {
|
|
276
|
-
log(
|
|
277
|
-
|
|
363
|
+
log(`countRows: counting rows in current viewport (no pagination)${hasFilters ? ` filters=${safeStringify(filtersRecord)}` : ''}`);
|
|
364
|
+
if (!hasPostFilters)
|
|
365
|
+
return resolveRows().count();
|
|
366
|
+
const all = await resolveRows().all();
|
|
367
|
+
return countPostFilterMatches(all, all.map((_, i) => i));
|
|
278
368
|
}
|
|
279
|
-
log(`countRows: paginating up to ${
|
|
369
|
+
log(`countRows: paginating up to ${effectiveMaxPages} page(s)${hasFilters ? ` filters=${safeStringify(filtersRecord)}` : ''}`);
|
|
280
370
|
const tracker = new elementTracker_1.ElementTracker('countRows');
|
|
281
371
|
let total = 0;
|
|
282
372
|
let pagesScanned = 1;
|
|
283
373
|
let paginationError;
|
|
284
374
|
try {
|
|
285
375
|
while (true) {
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
376
|
+
const rowLocators = resolveRows();
|
|
377
|
+
const newIndices = await tracker.getUnseenIndices(rowLocators);
|
|
378
|
+
const candidates = await rowLocators.all();
|
|
379
|
+
const matched = await countPostFilterMatches(candidates, newIndices);
|
|
380
|
+
total += matched;
|
|
381
|
+
log(`countRows: page ${pagesScanned} — ${matched} row(s) (running total: ${total})`);
|
|
382
|
+
if (pagesScanned >= effectiveMaxPages)
|
|
290
383
|
break;
|
|
291
384
|
if (!await _advancePage(false))
|
|
292
385
|
break;
|
|
@@ -326,7 +419,10 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
326
419
|
await cell.bringIntoView();
|
|
327
420
|
const columnOverride = (_a = config.columnOverrides) === null || _a === void 0 ? void 0 : _a[columnName];
|
|
328
421
|
if (columnOverride === null || columnOverride === void 0 ? void 0 : columnOverride.read) {
|
|
329
|
-
return await columnOverride.read(cell
|
|
422
|
+
return await columnOverride.read(cell, {
|
|
423
|
+
row, columnName, columnIndex: map.get(columnName),
|
|
424
|
+
getCell: (name) => row.getCell(name),
|
|
425
|
+
});
|
|
330
426
|
}
|
|
331
427
|
const text = await cell.innerText();
|
|
332
428
|
return (text || '').trim();
|
|
@@ -340,7 +436,6 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
340
436
|
reset: async () => {
|
|
341
437
|
var _a;
|
|
342
438
|
log("Resetting table...");
|
|
343
|
-
await config.onReset(createStrategyContext());
|
|
344
439
|
if ((_a = config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.goToFirst) {
|
|
345
440
|
log("Auto-navigating to first page...");
|
|
346
441
|
await config.strategies.pagination.goToFirst(createStrategyContext());
|
|
@@ -349,17 +444,25 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
349
444
|
log("No goToFirst strategy configured. Table may not be on page 1.");
|
|
350
445
|
}
|
|
351
446
|
tableState.currentPageIndex = 0;
|
|
447
|
+
tableState.empty = false;
|
|
352
448
|
tableMapper.clear();
|
|
353
449
|
log("Table reset complete. Calling autoInit to restore state.");
|
|
354
450
|
await _autoInit();
|
|
451
|
+
await config.onReset(createStrategyContext());
|
|
355
452
|
},
|
|
356
453
|
revalidate: async () => {
|
|
357
454
|
log("Revalidating table structure...");
|
|
358
455
|
await tableMapper.remapHeaders();
|
|
456
|
+
tableState.empty = false;
|
|
359
457
|
log("Table revalidated.");
|
|
360
458
|
},
|
|
361
459
|
getRow: (filters, options = { exact: false }) => {
|
|
362
460
|
log(`getRow: filters=${safeStringify(filters)} exact=${options.exact}`);
|
|
461
|
+
const syntheticKeys = Object.keys(filters).filter(k => { var _a; return (_a = config.syntheticColumns) === null || _a === void 0 ? void 0 : _a[k]; });
|
|
462
|
+
if (syntheticKeys.length > 0) {
|
|
463
|
+
throw new Error(`getRow() cannot filter by synthetic column(s): ${syntheticKeys.join(', ')}. ` +
|
|
464
|
+
`Use findRow() instead — synthetic columns require async evaluation.`);
|
|
465
|
+
}
|
|
363
466
|
const map = tableMapper.getMapSync();
|
|
364
467
|
if (!map)
|
|
365
468
|
throw new Error('Initialization Error: You attempted to access a row before the table structure was mapped. Please call "await table.init()" once before using synchronous row access.');
|
|
@@ -375,6 +478,62 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
375
478
|
const rowLocator = resolve(config.rowSelector, rootLocator).nth(index);
|
|
376
479
|
return _makeSmart(rowLocator, map, index);
|
|
377
480
|
},
|
|
481
|
+
findRowByIndex: async (index, options) => {
|
|
482
|
+
var _a, _b;
|
|
483
|
+
log(`findRowByIndex: index=${index} options=${safeStringify(options)}`);
|
|
484
|
+
await _autoInit();
|
|
485
|
+
const map = tableMapper.getMapSync();
|
|
486
|
+
const resolveRI = config.strategies.resolveRowIndex;
|
|
487
|
+
const viewport = config.strategies.viewport;
|
|
488
|
+
// Identifying a row by its logical index requires a resolveRowIndex strategy. Without one
|
|
489
|
+
// the library can only offer render-window-relative getRowByIndex, or filter-based findRow.
|
|
490
|
+
if (!resolveRI) {
|
|
491
|
+
throw new Error(`findRowByIndex(${index}) requires a strategies.resolveRowIndex to identify rows by their logical index. ` +
|
|
492
|
+
`Configure one (e.g. read the grid's row-index attribute), or use getRowByIndex() (current render window) / findRow(filters).`);
|
|
493
|
+
}
|
|
494
|
+
let foundSelector;
|
|
495
|
+
// The currently-mounted row whose logical index === index, if any.
|
|
496
|
+
const findMounted = async () => {
|
|
497
|
+
const rows = await resolve(config.rowSelector, rootLocator).all();
|
|
498
|
+
for (const r of rows) {
|
|
499
|
+
const result = await resolveRI(r);
|
|
500
|
+
if (result === undefined)
|
|
501
|
+
continue;
|
|
502
|
+
const normalized = (0, rowResolution_1.normalizeRowIndexResult)(result);
|
|
503
|
+
if (normalized.index === index) {
|
|
504
|
+
foundSelector = normalized.selector;
|
|
505
|
+
return r;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return null;
|
|
509
|
+
};
|
|
510
|
+
// 1. Already mounted (no navigation needed)?
|
|
511
|
+
let loc = await findMounted();
|
|
512
|
+
// 2. Fast path: jump straight to it via the viewport's random-access scroll.
|
|
513
|
+
if (!loc && (viewport === null || viewport === void 0 ? void 0 : viewport.scrollToRow)) {
|
|
514
|
+
log(`findRowByIndex: scrolling to row ${index}`);
|
|
515
|
+
await viewport.scrollToRow(createStrategyContext(), index);
|
|
516
|
+
loc = await findMounted();
|
|
517
|
+
}
|
|
518
|
+
// 3. Fallback: advance pages (on infinite-scroll tables, a "page" is a scroll step) until
|
|
519
|
+
// the row is reached. Bounded by maxPages so an unreachable index can't loop forever.
|
|
520
|
+
if (!loc && config.strategies.pagination) {
|
|
521
|
+
const effectiveMaxPages = (_a = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
|
|
522
|
+
let pagesScanned = 1;
|
|
523
|
+
while (!loc && pagesScanned < effectiveMaxPages) {
|
|
524
|
+
if (!await _advancePage(false))
|
|
525
|
+
break;
|
|
526
|
+
pagesScanned++;
|
|
527
|
+
loc = await findMounted();
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (!loc) {
|
|
531
|
+
throw new Error(`findRowByIndex(${index}): could not reach row ${index}. ` +
|
|
532
|
+
`Ensure a viewport.scrollToRow or pagination can bring it into view (searched up to maxPages=${(_b = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _b !== void 0 ? _b : config.maxPages}).`);
|
|
533
|
+
}
|
|
534
|
+
await (0, debugUtils_1.debugDelay)(config, 'findRow');
|
|
535
|
+
return _makeSmart(loc, map, index, tableState.currentPageIndex, undefined, foundSelector);
|
|
536
|
+
},
|
|
378
537
|
findRow: async (filters, options) => {
|
|
379
538
|
log(`findRow: filters=${safeStringify(filters)} options=${safeStringify(options)}`);
|
|
380
539
|
return rowFinder.findRow(filters, options);
|
|
@@ -384,13 +543,16 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
384
543
|
return rowFinder.findRows(filters !== null && filters !== void 0 ? filters : {}, options);
|
|
385
544
|
},
|
|
386
545
|
isInitialized: () => {
|
|
387
|
-
const initialized = tableMapper.isInitialized();
|
|
546
|
+
const initialized = tableMapper.isInitialized() || tableState.empty;
|
|
388
547
|
log(`isInitialized: ${initialized}`);
|
|
389
548
|
return initialized;
|
|
390
549
|
},
|
|
550
|
+
isEmpty: () => {
|
|
551
|
+
return tableState.empty;
|
|
552
|
+
},
|
|
391
553
|
sorting: {
|
|
392
554
|
apply: async (columnName, direction) => {
|
|
393
|
-
var _a;
|
|
555
|
+
var _a, _b, _c, _d, _e;
|
|
394
556
|
await _autoInit();
|
|
395
557
|
if (!config.strategies.sorting)
|
|
396
558
|
throw new Error('No sorting strategy has been configured.');
|
|
@@ -405,13 +567,16 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
405
567
|
}
|
|
406
568
|
await config.strategies.sorting.doSort({ columnName, direction, context });
|
|
407
569
|
if ((_a = config.strategies.loading) === null || _a === void 0 ? void 0 : _a.isTableLoading) {
|
|
408
|
-
const
|
|
570
|
+
const timeout = (_b = config.strategies.loading.sortStabilizationTimeout) !== null && _b !== void 0 ? _b : 10000;
|
|
571
|
+
const poll = (_c = config.strategies.loading.sortStabilizationPollInterval) !== null && _c !== void 0 ? _c : 100;
|
|
572
|
+
const deadline = Date.now() + timeout;
|
|
409
573
|
while (Date.now() < deadline && await config.strategies.loading.isTableLoading(context)) {
|
|
410
|
-
await rootLocator.page().waitForTimeout(
|
|
574
|
+
await rootLocator.page().waitForTimeout(poll);
|
|
411
575
|
}
|
|
412
576
|
}
|
|
413
577
|
else {
|
|
414
|
-
|
|
578
|
+
const fallback = (_e = (_d = config.strategies.loading) === null || _d === void 0 ? void 0 : _d.sortStabilizationFallbackDelay) !== null && _e !== void 0 ? _e : 200;
|
|
579
|
+
await rootLocator.page().waitForTimeout(fallback);
|
|
415
580
|
}
|
|
416
581
|
await (0, debugUtils_1.debugDelay)(config, 'default');
|
|
417
582
|
const newState = await config.strategies.sorting.getSortState({ columnName, context });
|
|
@@ -434,6 +599,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
434
599
|
// ─── Shared async row iterator ───────────────────────────────────────────
|
|
435
600
|
[Symbol.asyncIterator]() {
|
|
436
601
|
return __asyncGenerator(this, arguments, function* _a() {
|
|
602
|
+
var _b;
|
|
437
603
|
yield __await(_autoInit());
|
|
438
604
|
const map = tableMapper.getMapSync();
|
|
439
605
|
const effectiveMaxPages = config.maxPages;
|
|
@@ -449,7 +615,14 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
449
615
|
const pageRows = yield __await(rowLocators.all());
|
|
450
616
|
const barrier = new navigationBarrier_1.NavigationBarrier(newIndices.length);
|
|
451
617
|
for (const idx of newIndices) {
|
|
452
|
-
|
|
618
|
+
// index = visit-order counter; rowIndex = logical/data index (B-hybrid, #362).
|
|
619
|
+
const resolved = yield __await((0, rowResolution_1.resolveLogicalRowIndex)(pageRows[idx], config, () => rowIndex));
|
|
620
|
+
const logical = (_b = resolved === null || resolved === void 0 ? void 0 : resolved.index) !== null && _b !== void 0 ? _b : rowIndex;
|
|
621
|
+
const sr = _makeSmart(pageRows[idx], map, logical, tableState.currentPageIndex, barrier, resolved === null || resolved === void 0 ? void 0 : resolved.selector);
|
|
622
|
+
// Iterator rows share one per-page DOM snapshot (positional locators); disable
|
|
623
|
+
// toJSON's scroll-back recovery so reading one row can't invalidate the others (#366).
|
|
624
|
+
sr._inBatch = true;
|
|
625
|
+
yield yield __await({ row: sr, index: rowIndex, rowIndex: logical, pageIndex: tableState.currentPageIndex });
|
|
453
626
|
rowIndex++;
|
|
454
627
|
}
|
|
455
628
|
if (pagesScanned >= effectiveMaxPages)
|
|
@@ -472,11 +645,12 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
472
645
|
getRowLocators: () => resolve(config.rowSelector, rootLocator),
|
|
473
646
|
getMap: () => tableMapper.getMapSync(),
|
|
474
647
|
advancePage: _advancePage,
|
|
475
|
-
makeSmartRow: (loc, map, idx, pageIdx, barrier) => _makeSmart(loc, map, idx, pageIdx, barrier),
|
|
648
|
+
makeSmartRow: (loc, map, idx, pageIdx, barrier, sel) => _makeSmart(loc, map, idx, pageIdx, barrier, sel),
|
|
476
649
|
createSmartRowArray: smartRowArray_1.createSmartRowArray,
|
|
477
650
|
config,
|
|
478
651
|
getPage: () => rootLocator.page(),
|
|
479
652
|
getCurrentPageIndex: () => tableState.currentPageIndex,
|
|
653
|
+
getContext: () => createStrategyContext(),
|
|
480
654
|
}, callback, options);
|
|
481
655
|
},
|
|
482
656
|
map: async (callback, options = {}) => {
|
|
@@ -486,11 +660,12 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
486
660
|
getRowLocators: () => resolve(config.rowSelector, rootLocator),
|
|
487
661
|
getMap: () => tableMapper.getMapSync(),
|
|
488
662
|
advancePage: _advancePage,
|
|
489
|
-
makeSmartRow: (loc, map, idx, pageIdx, barrier) => _makeSmart(loc, map, idx, pageIdx, barrier),
|
|
663
|
+
makeSmartRow: (loc, map, idx, pageIdx, barrier, sel) => _makeSmart(loc, map, idx, pageIdx, barrier, sel),
|
|
490
664
|
createSmartRowArray: smartRowArray_1.createSmartRowArray,
|
|
491
665
|
config,
|
|
492
666
|
getPage: () => rootLocator.page(),
|
|
493
667
|
getCurrentPageIndex: () => tableState.currentPageIndex,
|
|
668
|
+
getContext: () => createStrategyContext(),
|
|
494
669
|
}, callback, options);
|
|
495
670
|
},
|
|
496
671
|
toArray: async (callback, options = {}) => {
|
|
@@ -510,11 +685,12 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
510
685
|
getRowLocators: () => resolve(config.rowSelector, rootLocator),
|
|
511
686
|
getMap: () => tableMapper.getMapSync(),
|
|
512
687
|
advancePage: _advancePage,
|
|
513
|
-
makeSmartRow: (loc, map, idx, pageIdx, barrier) => _makeSmart(loc, map, idx, pageIdx, barrier),
|
|
688
|
+
makeSmartRow: (loc, map, idx, pageIdx, barrier, sel) => _makeSmart(loc, map, idx, pageIdx, barrier, sel),
|
|
514
689
|
createSmartRowArray: smartRowArray_1.createSmartRowArray,
|
|
515
690
|
config,
|
|
516
691
|
getPage: () => rootLocator.page(),
|
|
517
692
|
getCurrentPageIndex: () => tableState.currentPageIndex,
|
|
693
|
+
getContext: () => createStrategyContext(),
|
|
518
694
|
}, predicate, options);
|
|
519
695
|
},
|
|
520
696
|
generateConfig: async () => {
|
|
@@ -56,5 +56,9 @@ function mergeTableConfig(base, overrides) {
|
|
|
56
56
|
if (base.columnOverrides || overrides.columnOverrides) {
|
|
57
57
|
result.columnOverrides = Object.assign(Object.assign({}, base.columnOverrides), overrides.columnOverrides);
|
|
58
58
|
}
|
|
59
|
+
// Deep-merge syntheticColumns (override keys replace, preset keys retained)
|
|
60
|
+
if (base.syntheticColumns || overrides.syntheticColumns) {
|
|
61
|
+
result.syntheticColumns = Object.assign(Object.assign({}, base.syntheticColumns), overrides.syntheticColumns);
|
|
62
|
+
}
|
|
59
63
|
return result;
|
|
60
64
|
}
|