@rickcedwhat/playwright-smart-table 6.9.0 → 6.10.1

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.
Files changed (42) hide show
  1. package/README.md +9 -6
  2. package/dist/engine/rowFinder.js +153 -168
  3. package/dist/engine/tableIteration.js +105 -120
  4. package/dist/engine/tableMapper.js +88 -103
  5. package/dist/minimalConfigContext.d.ts +1 -1
  6. package/dist/minimalConfigContext.js +1 -1
  7. package/dist/packageVersion.d.ts +1 -1
  8. package/dist/packageVersion.js +1 -1
  9. package/dist/presets/glide/columns.js +23 -32
  10. package/dist/presets/glide/headers.js +18 -27
  11. package/dist/presets/glide/index.d.ts +9 -9
  12. package/dist/presets/glide/index.js +24 -33
  13. package/dist/presets/mui.js +197 -124
  14. package/dist/presets/rdg.d.ts +1 -1
  15. package/dist/presets/rdg.js +32 -41
  16. package/dist/smartRow.js +209 -101
  17. package/dist/strategies/columns.js +2 -11
  18. package/dist/strategies/dedupe.js +3 -12
  19. package/dist/strategies/fill.js +20 -29
  20. package/dist/strategies/headers.js +22 -31
  21. package/dist/strategies/index.d.ts +7 -0
  22. package/dist/strategies/index.js +3 -0
  23. package/dist/strategies/loading.js +24 -33
  24. package/dist/strategies/pagination.d.ts +10 -0
  25. package/dist/strategies/pagination.js +49 -30
  26. package/dist/strategies/sorting.js +18 -31
  27. package/dist/strategies/stabilization.js +28 -37
  28. package/dist/strategies/viewport.d.ts +52 -0
  29. package/dist/strategies/viewport.js +123 -0
  30. package/dist/typeContext.d.ts +1 -1
  31. package/dist/typeContext.js +160 -5
  32. package/dist/types.d.ts +153 -5
  33. package/dist/useTable.js +142 -76
  34. package/dist/utils/debugUtils.js +5 -16
  35. package/dist/utils/elementTracker.js +27 -40
  36. package/dist/utils/mutex.js +5 -16
  37. package/dist/utils/navigationBarrier.js +25 -36
  38. package/dist/utils/paginationPath.d.ts +4 -1
  39. package/dist/utils/paginationPath.js +164 -141
  40. package/dist/utils/smartRowArray.js +2 -11
  41. package/dist/utils.js +4 -13
  42. package/package.json +13 -8
package/dist/useTable.js CHANGED
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
12
3
  var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
13
4
  if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
@@ -56,7 +47,38 @@ const useTable = (rootLocator, configOptions = {}) => {
56
47
  isHeaderLoading: loading_1.LoadingStrategies.Headers.stable(200)
57
48
  }
58
49
  };
59
- const config = Object.assign(Object.assign({ rowSelector: "tbody tr", headerSelector: "thead th", cellSelector: "td", maxPages: 1, headerTransformer: ({ text }) => text, autoScroll: true, onReset: () => __awaiter(void 0, void 0, void 0, function* () { }) }, configOptions), { strategies: Object.assign(Object.assign({}, defaultStrategies), configOptions.strategies) });
50
+ const config = Object.assign(Object.assign({ rowSelector: "tbody tr", headerSelector: "thead th", cellSelector: "td", maxPages: 1, headerTransformer: ({ text }) => text, autoScroll: true, onReset: async () => { } }, configOptions), { strategies: Object.assign(Object.assign({}, defaultStrategies), configOptions.strategies) });
51
+ // Automatically memoize viewport range oracles so user-provided functions are
52
+ // pure DOM queries with no cache bookkeeping. Invalidated after each scroll call.
53
+ if (config.strategies.viewport && !config.strategies.viewport.disableCache) {
54
+ const vp = config.strategies.viewport;
55
+ let colRangeCache = null;
56
+ let rowRangeCache = null;
57
+ config.strategies.viewport = Object.assign(Object.assign({}, vp), { getVisibleColumnRange: vp.getVisibleColumnRange
58
+ ? async (ctx) => {
59
+ if (!colRangeCache)
60
+ colRangeCache = await vp.getVisibleColumnRange(ctx);
61
+ return colRangeCache;
62
+ }
63
+ : undefined, getVisibleRowRange: vp.getVisibleRowRange
64
+ ? async (ctx) => {
65
+ if (!rowRangeCache)
66
+ rowRangeCache = await vp.getVisibleRowRange(ctx);
67
+ return rowRangeCache;
68
+ }
69
+ : undefined, scrollToColumn: vp.scrollToColumn
70
+ ? async (ctx, colIndex) => {
71
+ colRangeCache = null;
72
+ rowRangeCache = null;
73
+ await vp.scrollToColumn(ctx, colIndex);
74
+ }
75
+ : undefined, scrollToRow: vp.scrollToRow
76
+ ? async (ctx, rowIndex) => {
77
+ rowRangeCache = null;
78
+ await vp.scrollToRow(ctx, rowIndex);
79
+ }
80
+ : undefined });
81
+ }
60
82
  const resolve = (item, parent) => {
61
83
  if (typeof item === 'string')
62
84
  return parent.locator(item);
@@ -102,7 +124,7 @@ const useTable = (rootLocator, configOptions = {}) => {
102
124
  const rowFinder = new rowFinder_1.RowFinder(rootLocator, config, resolve, filterEngine, tableMapper, _makeSmart, tableState);
103
125
  /** Builds a full TableContext/StrategyContext with getHeaderCell, getHeaders, scrollToColumn. Set after result is created. */
104
126
  let createStrategyContext = () => ({ root: rootLocator, config, page: rootLocator.page(), resolve });
105
- const _getCleanHtml = (loc) => __awaiter(void 0, void 0, void 0, function* () {
127
+ const _getCleanHtml = async (loc) => {
106
128
  return loc.evaluate((el) => {
107
129
  const clone = el.cloneNode(true);
108
130
  const removeSelectors = 'script, style, svg, path, circle, rect, noscript, [hidden]';
@@ -123,33 +145,33 @@ const useTable = (rootLocator, configOptions = {}) => {
123
145
  }
124
146
  return clone.outerHTML;
125
147
  });
126
- });
127
- const _handlePrompt = (promptName, content) => __awaiter(void 0, void 0, void 0, function* () {
148
+ };
149
+ const _handlePrompt = async (promptName, content) => {
128
150
  let finalPrompt = content;
129
151
  finalPrompt += `\n\n👇 Useful TypeScript Definitions 👇\n\`\`\`typescript\n${minimalConfigContext_1.MINIMAL_CONFIG_CONTEXT}\n\`\`\`\n`;
130
152
  console.log(`⚠️ Throwing error to display [${promptName}] cleanly...`);
131
153
  throw new Error(finalPrompt);
132
- });
133
- const _autoInit = () => __awaiter(void 0, void 0, void 0, function* () {
134
- yield tableMapper.getMap();
135
- });
154
+ };
155
+ const _autoInit = async () => {
156
+ await tableMapper.getMap();
157
+ };
136
158
  // Default: goNext (one page). Pass useBulk true to prefer goNextBulk. "How far" uses numeric return when strategy provides it.
137
- const _advancePage = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (useBulk = false) {
159
+ const _advancePage = async (useBulk = false) => {
138
160
  const context = createStrategyContext();
139
161
  const pagination = config.strategies.pagination;
140
162
  let rawResult;
141
163
  let primitive;
142
164
  if (useBulk && (pagination === null || pagination === void 0 ? void 0 : pagination.goNextBulk)) {
143
165
  primitive = 'goNextBulk';
144
- rawResult = yield pagination.goNextBulk(context);
166
+ rawResult = await pagination.goNextBulk(context);
145
167
  }
146
168
  else if (pagination === null || pagination === void 0 ? void 0 : pagination.goNext) {
147
169
  primitive = 'goNext';
148
- rawResult = yield pagination.goNext(context);
170
+ rawResult = await pagination.goNext(context);
149
171
  }
150
172
  else if (pagination === null || pagination === void 0 ? void 0 : pagination.goNextBulk) {
151
173
  primitive = 'goNextBulk (fallback)';
152
- rawResult = yield pagination.goNextBulk(context);
174
+ rawResult = await pagination.goNextBulk(context);
153
175
  }
154
176
  else {
155
177
  log('_advancePage: no pagination primitive available — returning false');
@@ -165,47 +187,91 @@ const useTable = (rootLocator, configOptions = {}) => {
165
187
  log(`_advancePage: ${primitive} returned false — end of data`);
166
188
  }
167
189
  return didAdvance;
168
- });
190
+ };
169
191
  const result = {
170
192
  get currentPageIndex() { return tableState.currentPageIndex; },
171
193
  set currentPageIndex(v) { tableState.currentPageIndex = v; },
172
- init: (options) => __awaiter(void 0, void 0, void 0, function* () {
194
+ init: async (options) => {
195
+ var _a;
173
196
  if (tableMapper.isInitialized())
174
197
  return result;
175
198
  (0, debugUtils_1.warnIfDebugInCI)(config);
176
199
  (0, debugUtils_1.logDebug)(config, 'info', 'Initializing table');
177
- const map = yield tableMapper.getMap(options === null || options === void 0 ? void 0 : options.timeout);
200
+ const map = await tableMapper.getMap(options === null || options === void 0 ? void 0 : options.timeout);
178
201
  (0, debugUtils_1.logDebug)(config, 'info', `Table initialized with ${map.size} columns`, Array.from(map.keys()));
179
- yield (0, debugUtils_1.debugDelay)(config, 'default');
202
+ if ((_a = config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.detectCurrentPage) {
203
+ try {
204
+ const detected = await config.strategies.pagination.detectCurrentPage(rootLocator);
205
+ if (Number.isInteger(detected) && detected >= 0) {
206
+ tableState.currentPageIndex = detected;
207
+ (0, debugUtils_1.logDebug)(config, 'info', `init: detected starting page index ${detected}`);
208
+ }
209
+ else {
210
+ tableState.currentPageIndex = 0;
211
+ (0, debugUtils_1.logDebug)(config, 'error', `init: detectCurrentPage returned invalid index (${detected}); defaulting to 0`);
212
+ }
213
+ }
214
+ catch (e) {
215
+ tableState.currentPageIndex = 0;
216
+ (0, debugUtils_1.logDebug)(config, 'error', `init: detectCurrentPage failed`, e);
217
+ }
218
+ }
219
+ await (0, debugUtils_1.debugDelay)(config, 'default');
180
220
  return result;
181
- }),
182
- scrollToColumn: (columnName) => __awaiter(void 0, void 0, void 0, function* () {
183
- const map = yield tableMapper.getMap();
221
+ },
222
+ scrollToColumn: async (columnName) => {
223
+ const map = await tableMapper.getMap();
184
224
  const idx = map.get(columnName);
185
225
  if (idx === undefined)
186
226
  throw _createColumnError(columnName, map);
187
227
  // Use header cell for scrolling
188
228
  const headerCell = resolve(config.headerSelector, rootLocator).nth(idx);
189
- yield headerCell.scrollIntoViewIfNeeded();
190
- }),
191
- getHeaders: () => __awaiter(void 0, void 0, void 0, function* () {
192
- const map = yield tableMapper.getMap();
229
+ await headerCell.scrollIntoViewIfNeeded();
230
+ },
231
+ getHeaders: async () => {
232
+ const map = await tableMapper.getMap();
193
233
  return Array.from(map.keys());
194
- }),
195
- getHeaderCell: (columnName) => __awaiter(void 0, void 0, void 0, function* () {
196
- const map = yield tableMapper.getMap();
234
+ },
235
+ getHeaderCell: async (columnName) => {
236
+ const map = await tableMapper.getMap();
197
237
  const idx = map.get(columnName);
198
238
  if (idx === undefined)
199
239
  throw _createColumnError(columnName, map, 'header cell');
200
240
  return resolve(config.headerSelector, rootLocator).nth(idx);
201
- }),
202
- reset: () => __awaiter(void 0, void 0, void 0, function* () {
241
+ },
242
+ countRows: async () => {
243
+ await _autoInit();
244
+ const allRows = resolve(config.rowSelector, rootLocator);
245
+ return allRows.count();
246
+ },
247
+ mapColumn: async (columnName, options = {}) => {
248
+ await _autoInit();
249
+ const map = await tableMapper.getMap();
250
+ if (!map.has(columnName))
251
+ throw _createColumnError(columnName, map, 'mapColumn iteration');
252
+ return result.map(async ({ row }) => {
253
+ var _a;
254
+ const cell = row.getCell(columnName);
255
+ await cell.bringIntoView();
256
+ const columnOverride = (_a = config.columnOverrides) === null || _a === void 0 ? void 0 : _a[columnName];
257
+ if (columnOverride === null || columnOverride === void 0 ? void 0 : columnOverride.read) {
258
+ return await columnOverride.read(cell);
259
+ }
260
+ const text = await cell.innerText();
261
+ return (text || '').trim();
262
+ }, options);
263
+ },
264
+ getColumnValues: async (columnName, options = {}) => {
265
+ const values = await result.mapColumn(columnName, options);
266
+ return values.map(v => String(v));
267
+ },
268
+ reset: async () => {
203
269
  var _a;
204
270
  log("Resetting table...");
205
- yield config.onReset(createStrategyContext());
271
+ await config.onReset(createStrategyContext());
206
272
  if ((_a = config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.goToFirst) {
207
273
  log("Auto-navigating to first page...");
208
- yield config.strategies.pagination.goToFirst(createStrategyContext());
274
+ await config.strategies.pagination.goToFirst(createStrategyContext());
209
275
  }
210
276
  else if (hasPaginationInConfig) {
211
277
  log("No goToFirst strategy configured. Table may not be on page 1.");
@@ -214,13 +280,13 @@ const useTable = (rootLocator, configOptions = {}) => {
214
280
  tableState.currentPageIndex = 0;
215
281
  tableMapper.clear();
216
282
  log("Table reset complete. Calling autoInit to restore state.");
217
- yield _autoInit();
218
- }),
219
- revalidate: () => __awaiter(void 0, void 0, void 0, function* () {
283
+ await _autoInit();
284
+ },
285
+ revalidate: async () => {
220
286
  log("Revalidating table structure...");
221
- yield tableMapper.remapHeaders();
287
+ await tableMapper.remapHeaders();
222
288
  log("Table revalidated.");
223
- }),
289
+ },
224
290
  getRow: (filters, options = { exact: false }) => {
225
291
  const map = tableMapper.getMapSync();
226
292
  if (!map)
@@ -237,53 +303,53 @@ const useTable = (rootLocator, configOptions = {}) => {
237
303
  const rowLocator = resolve(config.rowSelector, rootLocator).nth(index);
238
304
  return _makeSmart(rowLocator, map, index);
239
305
  },
240
- findRow: (filters, options) => __awaiter(void 0, void 0, void 0, function* () {
306
+ findRow: async (filters, options) => {
241
307
  return rowFinder.findRow(filters, options);
242
- }),
243
- findRows: (filters, options) => __awaiter(void 0, void 0, void 0, function* () {
308
+ },
309
+ findRows: async (filters, options) => {
244
310
  return rowFinder.findRows(filters !== null && filters !== void 0 ? filters : {}, options);
245
- }),
311
+ },
246
312
  isInitialized: () => {
247
313
  return tableMapper.isInitialized();
248
314
  },
249
315
  sorting: {
250
- apply: (columnName, direction) => __awaiter(void 0, void 0, void 0, function* () {
316
+ apply: async (columnName, direction) => {
251
317
  var _a;
252
- yield _autoInit();
318
+ await _autoInit();
253
319
  if (!config.strategies.sorting)
254
320
  throw new Error('No sorting strategy has been configured.');
255
321
  log(`Applying sort for column "${columnName}" (${direction})`);
256
322
  const context = Object.assign(Object.assign({}, createStrategyContext()), { getHeaderCell: result.getHeaderCell });
257
323
  const maxRetries = 3;
258
324
  for (let i = 0; i < maxRetries; i++) {
259
- const currentState = yield config.strategies.sorting.getSortState({ columnName, context });
325
+ const currentState = await config.strategies.sorting.getSortState({ columnName, context });
260
326
  if (currentState === direction) {
261
327
  log(`Sort for "${columnName}" is already "${direction}".`);
262
328
  return;
263
329
  }
264
- yield config.strategies.sorting.doSort({ columnName, direction, context });
330
+ await config.strategies.sorting.doSort({ columnName, direction, context });
265
331
  if ((_a = config.strategies.loading) === null || _a === void 0 ? void 0 : _a.isTableLoading) {
266
- yield config.strategies.loading.isTableLoading(context);
332
+ await config.strategies.loading.isTableLoading(context);
267
333
  }
268
334
  else {
269
- yield rootLocator.page().waitForTimeout(200);
335
+ await rootLocator.page().waitForTimeout(200);
270
336
  }
271
- yield (0, debugUtils_1.debugDelay)(config, 'default');
272
- const newState = yield config.strategies.sorting.getSortState({ columnName, context });
337
+ await (0, debugUtils_1.debugDelay)(config, 'default');
338
+ const newState = await config.strategies.sorting.getSortState({ columnName, context });
273
339
  if (newState === direction) {
274
340
  log(`Successfully sorted "${columnName}" to "${direction}".`);
275
341
  return;
276
342
  }
277
343
  }
278
344
  throw new Error(`Failed to sort column "${columnName}" to "${direction}" after ${maxRetries} attempts.`);
279
- }),
280
- getState: (columnName) => __awaiter(void 0, void 0, void 0, function* () {
281
- yield _autoInit();
345
+ },
346
+ getState: async (columnName) => {
347
+ await _autoInit();
282
348
  if (!config.strategies.sorting)
283
349
  throw new Error('No sorting strategy has been configured.');
284
350
  const context = Object.assign(Object.assign({}, createStrategyContext()), { getHeaderCell: result.getHeaderCell });
285
351
  return config.strategies.sorting.getSortState({ columnName, context });
286
- })
352
+ }
287
353
  },
288
354
  // ─── Shared async row iterator ───────────────────────────────────────────
289
355
  [Symbol.asyncIterator]() {
@@ -318,9 +384,9 @@ const useTable = (rootLocator, configOptions = {}) => {
318
384
  });
319
385
  },
320
386
  // ─── Row iteration (delegated to engine/tableIteration) ──────────────────
321
- forEach: (callback_1, ...args_1) => __awaiter(void 0, [callback_1, ...args_1], void 0, function* (callback, options = {}) {
322
- yield _autoInit();
323
- yield (0, tableIteration_1.runForEach)({
387
+ forEach: async (callback, options = {}) => {
388
+ await _autoInit();
389
+ await (0, tableIteration_1.runForEach)({
324
390
  getRowLocators: () => resolve(config.rowSelector, rootLocator),
325
391
  getMap: () => tableMapper.getMapSync(),
326
392
  advancePage: _advancePage,
@@ -329,9 +395,9 @@ const useTable = (rootLocator, configOptions = {}) => {
329
395
  config,
330
396
  getPage: () => rootLocator.page(),
331
397
  }, callback, options);
332
- }),
333
- map: (callback_1, ...args_1) => __awaiter(void 0, [callback_1, ...args_1], void 0, function* (callback, options = {}) {
334
- yield _autoInit();
398
+ },
399
+ map: async (callback, options = {}) => {
400
+ await _autoInit();
335
401
  return (0, tableIteration_1.runMap)({
336
402
  getRowLocators: () => resolve(config.rowSelector, rootLocator),
337
403
  getMap: () => tableMapper.getMapSync(),
@@ -341,9 +407,9 @@ const useTable = (rootLocator, configOptions = {}) => {
341
407
  config,
342
408
  getPage: () => rootLocator.page(),
343
409
  }, callback, options);
344
- }),
345
- filter: (predicate_1, ...args_1) => __awaiter(void 0, [predicate_1, ...args_1], void 0, function* (predicate, options = {}) {
346
- yield _autoInit();
410
+ },
411
+ filter: async (predicate, options = {}) => {
412
+ await _autoInit();
347
413
  return (0, tableIteration_1.runFilter)({
348
414
  getRowLocators: () => resolve(config.rowSelector, rootLocator),
349
415
  getMap: () => tableMapper.getMapSync(),
@@ -353,17 +419,17 @@ const useTable = (rootLocator, configOptions = {}) => {
353
419
  config,
354
420
  getPage: () => rootLocator.page(),
355
421
  }, predicate, options);
356
- }),
357
- generateConfig: () => __awaiter(void 0, void 0, void 0, function* () {
358
- const html = yield _getCleanHtml(rootLocator);
422
+ },
423
+ generateConfig: async () => {
424
+ const html = await _getCleanHtml(rootLocator);
359
425
  const separator = "=".repeat(50);
360
426
  const content = `\n${separator} \n🤖 COPY INTO GEMINI / ChatGPT 🤖\n${separator} \nI am using 'playwright-smart-table'.\nTarget Table Locator: ${rootLocator.toString()} \nGenerate config for: \n\`\`\`html\n${html.substring(0, 10000)} ...\n\`\`\`\n${separator}\n`;
361
- yield _handlePrompt('Smart Table Config', content);
362
- }),
363
- generateConfigPrompt: () => __awaiter(void 0, void 0, void 0, function* () {
427
+ await _handlePrompt('Smart Table Config', content);
428
+ },
429
+ generateConfigPrompt: async () => {
364
430
  console.warn('⚠️ [playwright-smart-table] generateConfigPrompt() is deprecated and will be removed in v7.0.0. Please use generateConfig() instead.');
365
431
  return result.generateConfig();
366
- }),
432
+ },
367
433
  };
368
434
  createStrategyContext = () => ({
369
435
  root: rootLocator,
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.getDebugDelay = getDebugDelay;
13
4
  exports.debugDelay = debugDelay;
@@ -28,13 +19,11 @@ function getDebugDelay(config, actionType) {
28
19
  /**
29
20
  * Add debug delay for specific action type
30
21
  */
31
- function debugDelay(config, actionType) {
32
- return __awaiter(this, void 0, void 0, function* () {
33
- const delay = getDebugDelay(config, actionType);
34
- if (delay > 0) {
35
- yield new Promise(resolve => setTimeout(resolve, delay));
36
- }
37
- });
22
+ async function debugDelay(config, actionType) {
23
+ const delay = getDebugDelay(config, actionType);
24
+ if (delay > 0) {
25
+ await new Promise(resolve => setTimeout(resolve, delay));
26
+ }
38
27
  }
39
28
  /**
40
29
  * Log debug message based on log level
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.ElementTracker = void 0;
13
4
  class ElementTracker {
@@ -19,42 +10,38 @@ class ElementTracker {
19
10
  * in a WeakMap. This gracefully handles both append-only DOMs (by identity) and
20
11
  * virtualized DOMs (by text signature if nodes are recycled).
21
12
  */
22
- getUnseenIndices(locators) {
23
- return __awaiter(this, void 0, void 0, function* () {
24
- return yield locators.evaluateAll((elements, trackerId) => {
25
- const win = window;
26
- if (!win[trackerId]) {
27
- win[trackerId] = new WeakMap();
13
+ async getUnseenIndices(locators) {
14
+ return await locators.evaluateAll((elements, trackerId) => {
15
+ const win = window;
16
+ if (!win[trackerId]) {
17
+ win[trackerId] = new WeakMap();
18
+ }
19
+ const seenMap = win[trackerId];
20
+ const newIndices = [];
21
+ elements.forEach((el, index) => {
22
+ // Determine a lightweight signature for the row (textContent strips HTML, fast)
23
+ const signature = el.textContent || '';
24
+ // If it's a new element, OR a recycled element with new data
25
+ if (seenMap.get(el) !== signature) {
26
+ seenMap.set(el, signature);
27
+ newIndices.push(index);
28
28
  }
29
- const seenMap = win[trackerId];
30
- const newIndices = [];
31
- elements.forEach((el, index) => {
32
- // Determine a lightweight signature for the row (textContent strips HTML, fast)
33
- const signature = el.textContent || '';
34
- // If it's a new element, OR a recycled element with new data
35
- if (seenMap.get(el) !== signature) {
36
- seenMap.set(el, signature);
37
- newIndices.push(index);
38
- }
39
- });
40
- return newIndices;
41
- }, this.id);
42
- });
29
+ });
30
+ return newIndices;
31
+ }, this.id);
43
32
  }
44
33
  /**
45
34
  * Cleans up the tracking map from the browser window object.
46
35
  */
47
- cleanup(page) {
48
- return __awaiter(this, void 0, void 0, function* () {
49
- try {
50
- yield page.evaluate((trackerId) => {
51
- delete window[trackerId];
52
- }, this.id);
53
- }
54
- catch (e) {
55
- // Ignore context destroyed errors during cleanup
56
- }
57
- });
36
+ async cleanup(page) {
37
+ try {
38
+ await page.evaluate((trackerId) => {
39
+ delete window[trackerId];
40
+ }, this.id);
41
+ }
42
+ catch (e) {
43
+ // Ignore context destroyed errors during cleanup
44
+ }
58
45
  }
59
46
  }
60
47
  exports.ElementTracker = ElementTracker;
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.Mutex = void 0;
13
4
  /**
@@ -18,14 +9,12 @@ class Mutex {
18
9
  constructor() {
19
10
  this.queue = Promise.resolve();
20
11
  }
21
- run(action) {
22
- return __awaiter(this, void 0, void 0, function* () {
23
- const next = this.queue.then(() => __awaiter(this, void 0, void 0, function* () {
24
- return yield action();
25
- }));
26
- this.queue = next.catch(() => { }); // prevent chain breakage
27
- return yield next;
12
+ async run(action) {
13
+ const next = this.queue.then(async () => {
14
+ return await action();
28
15
  });
16
+ this.queue = next.catch(() => { }); // prevent chain breakage
17
+ return await next;
29
18
  }
30
19
  }
31
20
  exports.Mutex = Mutex;
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.NavigationBarrier = void 0;
13
4
  /**
@@ -25,34 +16,32 @@ class NavigationBarrier {
25
16
  * Synchronize all active rows at a specific column index.
26
17
  * The last row to arrive will trigger the `moveAction`.
27
18
  */
28
- sync(colIndex, moveAction) {
29
- return __awaiter(this, void 0, void 0, function* () {
30
- if (this.total <= 1) {
31
- if (moveAction)
32
- return yield moveAction();
33
- return;
19
+ async sync(colIndex, moveAction) {
20
+ if (this.total <= 1) {
21
+ if (moveAction)
22
+ return await moveAction();
23
+ return;
24
+ }
25
+ return new Promise((resolve) => {
26
+ let bucket = this.buckets.get(colIndex);
27
+ if (!bucket) {
28
+ bucket = new Set();
29
+ this.buckets.set(colIndex, bucket);
30
+ }
31
+ bucket.add(resolve);
32
+ if (bucket.size + this.finishedCount >= this.total) {
33
+ // Use a self-executing async function to handle the moveAction synchronously in this context
34
+ (async () => {
35
+ let result;
36
+ try {
37
+ if (moveAction)
38
+ result = await moveAction();
39
+ }
40
+ finally {
41
+ this.broadcast(colIndex, result);
42
+ }
43
+ })();
34
44
  }
35
- return new Promise((resolve) => {
36
- let bucket = this.buckets.get(colIndex);
37
- if (!bucket) {
38
- bucket = new Set();
39
- this.buckets.set(colIndex, bucket);
40
- }
41
- bucket.add(resolve);
42
- if (bucket.size + this.finishedCount >= this.total) {
43
- // Use a self-executing async function to handle the moveAction synchronously in this context
44
- (() => __awaiter(this, void 0, void 0, function* () {
45
- let result;
46
- try {
47
- if (moveAction)
48
- result = yield moveAction();
49
- }
50
- finally {
51
- this.broadcast(colIndex, result);
52
- }
53
- }))();
54
- }
55
- });
56
45
  });
57
46
  }
58
47
  /**
@@ -3,6 +3,9 @@ import type { PaginationPrimitives, TableContext } from '../types';
3
3
  export type NavigationStep = {
4
4
  type: 'goToPage';
5
5
  pageIndex: number;
6
+ } | {
7
+ type: 'goToLast';
8
+ targetIndex: number;
6
9
  } | {
7
10
  type: 'goNextBulk';
8
11
  count: number;
@@ -22,7 +25,7 @@ export type NavigationStep = {
22
25
  * single steps (goNext / goPrevious). May choose to overshoot with bulk then step back when
23
26
  * that reduces total primitive calls (e.g. page 3 → 12 with bulk 10: goNextBulk once, goPrevious once).
24
27
  */
25
- export declare function planNavigationPath(currentPageIndex: number, targetPageIndex: number, primitives: PaginationPrimitives): NavigationStep[];
28
+ export declare function planNavigationPath(currentPageIndex: number, targetPageIndex: number, primitives: PaginationPrimitives, totalPages?: number): NavigationStep[];
26
29
  /**
27
30
  * Navigate to targetPageIndex when goToPage is available but may be "windowed"
28
31
  * (e.g. only works for visible page links 6–14). Tries goToPage(target); on false,