@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/smartRow.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
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  const fill_1 = require("./strategies/fill");
13
4
  const stringUtils_1 = require("./utils/stringUtils");
@@ -19,14 +10,14 @@ const sentinel_1 = require("./utils/sentinel");
19
10
  * Uses `strategies.navigation` primitives (goUp/goDown/goLeft/goRight, optional snap/seek/goHome).
20
11
  * Returns the target cell locator after navigation.
21
12
  */
22
- const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function* () {
13
+ const _navigateToCell = async (params) => {
23
14
  const { config, rootLocator, page, resolve, column, index, rowLocator, rowIndex, barrier } = params;
24
15
  const rowLabel = typeof rowIndex === 'number' ? `row ${rowIndex}` : 'row ?';
25
- (0, debugUtils_1.logDebug)(config, 'verbose', `_navigateToCell: navigating to column "${column}" (colIndex ${index}), ${rowLabel}`);
16
+ (0, debugUtils_1.logDebug)(config, 'verbose', `_navigateToCell: resolving column "${column}" (colIndex ${index}), ${rowLabel}`);
26
17
  // Get active cell if strategy is available
27
18
  let activeCell = null;
28
19
  if (config.strategies.getActiveCell) {
29
- activeCell = yield config.strategies.getActiveCell({
20
+ activeCell = await config.strategies.getActiveCell({
30
21
  config,
31
22
  root: rootLocator,
32
23
  page,
@@ -39,18 +30,120 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
39
30
  }
40
31
  }
41
32
  const context = { config, root: rootLocator, page, resolve };
33
+ // Shared helper: is the target cell currently in the DOM?
34
+ const targetReached = async () => {
35
+ if (config.strategies.getActiveCell) {
36
+ const ac = await config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
37
+ if (ac && ac.rowIndex === rowIndex && ac.columnIndex === index)
38
+ return true;
39
+ }
40
+ // Locator presence: virtualized grids (e.g. Glide) often attach the target `td` after scroll
41
+ // while focus id lags; do not require getActiveCell to match for this to count as reached.
42
+ const cell = config.strategies.getCellLocator
43
+ ? config.strategies.getCellLocator({ row: rowLocator, root: rootLocator, columnName: column, columnIndex: index, rowIndex, page, config })
44
+ : resolve(config.cellSelector, rowLocator).nth(index);
45
+ return (await cell.count() > 0);
46
+ };
47
+ const getCellLocator = () => config.strategies.getCellLocator
48
+ ? config.strategies.getCellLocator({ row: rowLocator, root: rootLocator, columnName: column, columnIndex: index, rowIndex, page, config })
49
+ : resolve(config.cellSelector, rowLocator).nth(index);
50
+ // Viewport-oracle phase: direct positioning for 2D virtualized tables.
51
+ // Runs before navigation primitives; falls through to them if cell still not accessible.
52
+ const viewport = config.strategies.viewport;
53
+ if (viewport && typeof rowIndex === 'number') {
54
+ // Fast path via range oracle: if the user provides getVisibleColumnRange (and memoizes it),
55
+ // this check is a near-instant JS lookup — no DOM count() round-trip needed.
56
+ // Rows do NOT sync at the barrier here — only scroll boundaries need coordination.
57
+ if (viewport.getVisibleColumnRange) {
58
+ const colRange = await viewport.getVisibleColumnRange(context);
59
+ if (colRange && index >= colRange.first && index <= colRange.last) {
60
+ const rowRange = viewport.getVisibleRowRange
61
+ ? await viewport.getVisibleRowRange(context)
62
+ : null;
63
+ const rowVisible = !rowRange || (rowIndex >= rowRange.first && rowIndex <= rowRange.last);
64
+ if (rowVisible && await targetReached()) {
65
+ (0, debugUtils_1.logDebug)(config, 'verbose', `_navigateToCell: col ${index} in visible range [${colRange.first}-${colRange.last}], reading directly`);
66
+ return getCellLocator();
67
+ }
68
+ }
69
+ }
70
+ else if (await targetReached()) {
71
+ // No range oracle — fall back to DOM count() check.
72
+ if (barrier)
73
+ await barrier.sync(index);
74
+ return getCellLocator();
75
+ }
76
+ // Column is out of view. Scroll to bring it in.
77
+ // In synchronized mode, the last row to arrive triggers the scroll once for all rows.
78
+ const scrollIntoViewport = async () => {
79
+ const colRange = viewport.getVisibleColumnRange
80
+ ? await viewport.getVisibleColumnRange(context)
81
+ : null;
82
+ const colOutOfView = !colRange || index < colRange.first || index > colRange.last;
83
+ if (colOutOfView) {
84
+ (0, debugUtils_1.logDebug)(config, 'verbose', `_navigateToCell: col ${index} out of view, scrolling`);
85
+ if (viewport.scrollToColumn) {
86
+ await viewport.scrollToColumn(context, index);
87
+ }
88
+ }
89
+ // Some row locators (notably rows returned by findRow()) have a logical
90
+ // rowIndex that is not the grid's viewport coordinate. If the target cell
91
+ // is already mounted after any column scroll, avoid a misleading row jump.
92
+ if (await targetReached()) {
93
+ return;
94
+ }
95
+ // 2D scroll hazard guard: scrolling horizontally may have unmounted the target row.
96
+ const rowRange = viewport.getVisibleRowRange
97
+ ? await viewport.getVisibleRowRange(context)
98
+ : null;
99
+ const rowOutOfView = rowRange && (rowIndex < rowRange.first || rowIndex > rowRange.last);
100
+ if (rowOutOfView) {
101
+ (0, debugUtils_1.logDebug)(config, 'verbose', `_navigateToCell: row ${rowIndex} out of view after col scroll, recovering`);
102
+ if (viewport.scrollToRow) {
103
+ await viewport.scrollToRow(context, rowIndex);
104
+ }
105
+ }
106
+ };
107
+ if (barrier) {
108
+ await barrier.sync(index, scrollIntoViewport);
109
+ }
110
+ else {
111
+ await scrollIntoViewport();
112
+ }
113
+ if (await targetReached()) {
114
+ return getCellLocator();
115
+ }
116
+ // Cell still not accessible — fall through to navigation primitives if configured.
117
+ if (!config.strategies.navigation) {
118
+ const colRange = viewport.getVisibleColumnRange ? await viewport.getVisibleColumnRange(context) : null;
119
+ const rowRange = viewport.getVisibleRowRange ? await viewport.getVisibleRowRange(context) : null;
120
+ let errMsg = `SmartTable: could not reach cell for column "${column}" (colIndex ${index}) at row ${rowIndex}.\n`;
121
+ if (colRange) {
122
+ errMsg += ` Visible column range: [${colRange.first}–${colRange.last}]. Column is out of view and no navigation fallback is configured.\n`;
123
+ }
124
+ else {
125
+ errMsg += ` Column is out of view and no navigation fallback is configured.\n`;
126
+ }
127
+ if (rowRange && rowIndex !== undefined) {
128
+ const inView = rowIndex >= rowRange.first && rowIndex <= rowRange.last;
129
+ errMsg += ` Visible row range: [${rowRange.first}–${rowRange.last}]. ${inView ? 'Row is in view.' : 'Row is out of view.'}\n`;
130
+ }
131
+ errMsg += ` → Add a \`strategies.navigation\` or \`strategies.viewport.scrollToColumn\` to handle off-screen columns.`;
132
+ throw new Error(errMsg);
133
+ }
134
+ }
42
135
  // Use navigation primitives if available
43
136
  if (config.strategies.navigation) {
44
137
  const nav = config.strategies.navigation;
45
138
  if (typeof rowIndex !== 'number') {
46
139
  throw new Error('Row index is required for navigation');
47
140
  }
48
- const navigateOnce = () => __awaiter(void 0, void 0, void 0, function* () {
141
+ const navigateOnce = async () => {
49
142
  // Get current position again to be sure
50
143
  let currRow = 0;
51
144
  let currCol = 0;
52
145
  if (config.strategies.getActiveCell) {
53
- const ac = yield config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
146
+ const ac = await config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
54
147
  if (ac) {
55
148
  currRow = ac.rowIndex;
56
149
  currCol = ac.columnIndex;
@@ -61,67 +154,51 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
61
154
  // Move one step vertically
62
155
  if (rDiff > 0 && nav.goDown) {
63
156
  (0, debugUtils_1.logDebug)(config, 'verbose', '_navigateToCell: moving down');
64
- yield nav.goDown(context);
157
+ await nav.goDown(context);
65
158
  }
66
159
  else if (rDiff < 0 && nav.goUp) {
67
160
  (0, debugUtils_1.logDebug)(config, 'verbose', '_navigateToCell: moving up');
68
- yield nav.goUp(context);
161
+ await nav.goUp(context);
69
162
  }
70
163
  // Move one step horizontally
71
164
  if (cDiff > 0 && nav.goRight) {
72
165
  (0, debugUtils_1.logDebug)(config, 'verbose', '_navigateToCell: moving right');
73
- yield nav.goRight(context);
166
+ await nav.goRight(context);
74
167
  }
75
168
  else if (cDiff < 0 && nav.goLeft) {
76
169
  (0, debugUtils_1.logDebug)(config, 'verbose', '_navigateToCell: moving left');
77
- yield nav.goLeft(context);
170
+ await nav.goLeft(context);
78
171
  }
79
- });
80
- const targetReached = () => __awaiter(void 0, void 0, void 0, function* () {
81
- if (config.strategies.getActiveCell) {
82
- const ac = yield config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
83
- if (ac && ac.rowIndex === rowIndex && ac.columnIndex === index)
84
- return true;
85
- }
86
- // Locator presence: virtualized grids (e.g. Glide) often attach the target `td` after scroll
87
- // while focus id lags; do not require getActiveCell to match for this to count as reached.
88
- const cell = config.strategies.getCellLocator
89
- ? config.strategies.getCellLocator({ row: rowLocator, columnName: column, columnIndex: index, page })
90
- : resolve(config.cellSelector, rowLocator).nth(index);
91
- return ((yield cell.count()) > 0);
92
- });
93
- if (yield targetReached()) {
172
+ };
173
+ if (await targetReached()) {
94
174
  // Already there. If we have a barrier, check-in to stay in lock-step.
95
175
  if (barrier)
96
- yield barrier.sync(index);
97
- const cell = config.strategies.getCellLocator
98
- ? config.strategies.getCellLocator({ row: rowLocator, columnName: column, columnIndex: index, page })
99
- : resolve(config.cellSelector, rowLocator).nth(index);
100
- return cell;
176
+ await barrier.sync(index);
177
+ return getCellLocator();
101
178
  }
102
179
  // If getActiveCell is present but returns null (no focus), and cell is in DOM,
103
180
  // try to focus it once before entering navigation loop.
104
181
  if (config.strategies.getActiveCell) {
105
- const ac = yield config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
182
+ const ac = await config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
106
183
  if (!ac) {
107
184
  const cell = resolve(config.cellSelector, rowLocator).nth(index);
108
- if ((yield cell.count()) > 0) {
185
+ if (await cell.count() > 0) {
109
186
  (0, debugUtils_1.logDebug)(config, 'verbose', `_navigateToCell: cell "${column}" found but not focused; focusing.`);
110
- yield cell.focus();
187
+ await cell.focus();
111
188
  // Re-check target
112
- if (yield targetReached()) {
189
+ if (await targetReached()) {
113
190
  if (barrier)
114
- yield barrier.sync(index);
191
+ await barrier.sync(index);
115
192
  return cell;
116
193
  }
117
194
  }
118
195
  }
119
196
  }
120
- const navigateUntilReached = () => __awaiter(void 0, void 0, void 0, function* () {
197
+ const navigateUntilReached = async () => {
121
198
  let currRow = 0;
122
199
  let currCol = 0;
123
200
  if (config.strategies.getActiveCell) {
124
- const ac = yield config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
201
+ const ac = await config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
125
202
  if (ac) {
126
203
  currRow = ac.rowIndex;
127
204
  currCol = ac.columnIndex;
@@ -131,12 +208,12 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
131
208
  // Navigate vertically (tight loop)
132
209
  for (let i = 0; i < Math.abs(rDiff); i++) {
133
210
  if (rDiff > 0 && nav.goDown)
134
- yield nav.goDown(context);
211
+ await nav.goDown(context);
135
212
  else if (rDiff < 0 && nav.goUp)
136
- yield nav.goUp(context);
213
+ await nav.goUp(context);
137
214
  }
138
215
  if (config.strategies.getActiveCell) {
139
- const ac = yield config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
216
+ const ac = await config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
140
217
  if (ac) {
141
218
  currRow = ac.rowIndex;
142
219
  currCol = ac.columnIndex;
@@ -144,9 +221,9 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
144
221
  }
145
222
  if (index === 0 && nav.snapFirstColumnIntoView) {
146
223
  (0, debugUtils_1.logDebug)(config, 'verbose', '_navigateToCell: snapFirstColumnIntoView for column index 0');
147
- yield nav.snapFirstColumnIntoView(context);
224
+ await nav.snapFirstColumnIntoView(context);
148
225
  if (config.strategies.getActiveCell) {
149
- const ac = yield config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
226
+ const ac = await config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
150
227
  if (ac) {
151
228
  currRow = ac.rowIndex;
152
229
  currCol = ac.columnIndex;
@@ -155,7 +232,7 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
155
232
  // Home moves a11y focus within the current row to column 0. If focus row !== target row
156
233
  // (e.g. still on previous row), Home jumps to grid origin and breaks `tr.nth(k)` reads.
157
234
  if (typeof rowIndex === 'number' && currRow === rowIndex) {
158
- yield rootLocator.evaluate((el) => {
235
+ await rootLocator.evaluate((el) => {
159
236
  var _a;
160
237
  const canvas = el.closest('canvas') || ((_a = el.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector('canvas'));
161
238
  if (canvas instanceof HTMLCanvasElement) {
@@ -163,10 +240,10 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
163
240
  canvas.focus();
164
241
  }
165
242
  });
166
- yield page.keyboard.press('Home');
167
- yield page.waitForTimeout(120);
243
+ await page.keyboard.press('Home');
244
+ await page.waitForTimeout(120);
168
245
  if (config.strategies.getActiveCell) {
169
- const ac = yield config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
246
+ const ac = await config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
170
247
  if (ac) {
171
248
  currRow = ac.rowIndex;
172
249
  currCol = ac.columnIndex;
@@ -177,9 +254,9 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
177
254
  let cDiff = index - currCol;
178
255
  if (Math.abs(cDiff) > 12 && nav.seekColumnIndex) {
179
256
  (0, debugUtils_1.logDebug)(config, 'verbose', `_navigateToCell: seekColumnIndex approx for column ${index}`);
180
- yield nav.seekColumnIndex(context, index);
257
+ await nav.seekColumnIndex(context, index);
181
258
  if (config.strategies.getActiveCell) {
182
- const ac = yield config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
259
+ const ac = await config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
183
260
  if (ac) {
184
261
  currRow = ac.rowIndex;
185
262
  currCol = ac.columnIndex;
@@ -189,14 +266,14 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
189
266
  }
190
267
  for (let i = 0; i < Math.abs(cDiff); i++) {
191
268
  if (cDiff > 0 && nav.goRight)
192
- yield nav.goRight(context);
269
+ await nav.goRight(context);
193
270
  else if (cDiff < 0 && nav.goLeft)
194
- yield nav.goLeft(context);
271
+ await nav.goLeft(context);
195
272
  }
196
273
  const horizontalSteps = Math.abs(cDiff);
197
274
  if (horizontalSteps > 0) {
198
275
  const settleMs = Math.min(2500, 60 + horizontalSteps * 12);
199
- yield page.waitForTimeout(settleMs);
276
+ await page.waitForTimeout(settleMs);
200
277
  }
201
278
  // Wait for active cell to match target: poll getActiveCell or fallback to fixed delay
202
279
  // This is the "Midas Touch" buffer needed for Glide's async accessibility updates.
@@ -205,40 +282,40 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
205
282
  const start = Date.now();
206
283
  while (Date.now() - start < maxWaitMs) {
207
284
  if (config.strategies.getActiveCell) {
208
- const ac = yield config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
285
+ const ac = await config.strategies.getActiveCell({ config, root: rootLocator, page, resolve });
209
286
  if (ac && ac.rowIndex === rowIndex && ac.columnIndex === index) {
210
287
  return ac.locator;
211
288
  }
212
289
  }
213
- if (yield targetReached()) {
290
+ if (await targetReached()) {
214
291
  break;
215
292
  }
216
- yield page.waitForTimeout(pollIntervalMs);
293
+ await page.waitForTimeout(pollIntervalMs);
217
294
  }
218
- });
295
+ };
219
296
  // Not there, perform (coordinated) navigation
220
297
  let navResult;
221
298
  if (barrier) {
222
- navResult = yield barrier.sync(index, navigateUntilReached);
299
+ navResult = await barrier.sync(index, navigateUntilReached);
223
300
  }
224
301
  else {
225
- navResult = yield navigateUntilReached();
302
+ navResult = await navigateUntilReached();
226
303
  }
227
304
  if (navResult instanceof Object && navResult._isLocator) {
228
305
  const loc = navResult;
229
- if ((yield loc.count()) > 0)
306
+ if (await loc.count() > 0)
230
307
  return loc;
231
308
  }
232
309
  // Return final locator if reached
233
- const finalCell = config.strategies.getCellLocator
234
- ? config.strategies.getCellLocator({ row: rowLocator, columnName: column, columnIndex: index, page })
235
- : resolve(config.cellSelector, rowLocator).nth(index);
236
- if ((yield finalCell.count()) > 0)
310
+ const finalCell = getCellLocator();
311
+ if (await finalCell.count() > 0)
237
312
  return finalCell;
238
- return null;
313
+ throw new Error(`SmartTable: could not reach cell for column "${column}" (colIndex ${index}) at row ${rowIndex} after exhausting navigation strategies. Ensure navigation primitives are correctly implemented.`);
239
314
  }
240
- return null;
241
- });
315
+ // No horizontal strategies configured; assume table is 1D or fully rendered,
316
+ // and let standard Playwright auto-waiting handle any lazy-loading delays.
317
+ return getCellLocator();
318
+ };
242
319
  /**
243
320
  * Factory to create a SmartRow by extending a Playwright Locator.
244
321
  * We avoid Class/Proxy to ensure full compatibility with Playwright's expect(locator) matchers.
@@ -260,21 +337,44 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
260
337
  if (idx === undefined) {
261
338
  throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, Array.from(map.keys())));
262
339
  }
340
+ let baseLocator;
263
341
  if (config.strategies.getCellLocator) {
264
- return config.strategies.getCellLocator({
342
+ baseLocator = config.strategies.getCellLocator({
265
343
  row: rowLocator,
344
+ root: rootLocator,
266
345
  columnName: colName,
267
346
  columnIndex: idx,
268
347
  rowIndex: rowIndex,
269
- page: rootLocator.page()
348
+ page: rootLocator.page(),
349
+ config
270
350
  });
271
351
  }
272
- return resolve(config.cellSelector, rowLocator).nth(idx);
352
+ else {
353
+ baseLocator = resolve(config.cellSelector, rowLocator).nth(idx);
354
+ }
355
+ const smartCell = baseLocator;
356
+ smartCell.bringIntoView = async () => {
357
+ const navigatedCell = await _navigateToCell({
358
+ config,
359
+ rootLocator,
360
+ page: rootLocator.page(),
361
+ resolve,
362
+ column: colName,
363
+ index: idx,
364
+ rowLocator,
365
+ rowIndex,
366
+ barrier: smart._barrier
367
+ });
368
+ if (navigatedCell && navigatedCell._locator) {
369
+ smartCell._locator = navigatedCell._locator;
370
+ }
371
+ };
372
+ return smartCell;
273
373
  };
274
374
  smart.wasFound = () => {
275
375
  return !smart[sentinel_1.SENTINEL_ROW];
276
376
  };
277
- smart.toJSON = (options) => __awaiter(void 0, void 0, void 0, function* () {
377
+ smart.toJSON = async (options) => {
278
378
  var _a;
279
379
  const result = {};
280
380
  const page = rootLocator.page();
@@ -282,12 +382,12 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
282
382
  // Uses the table reference if available, otherwise falls back to index-based lookup.
283
383
  const getHeaderCell = (table === null || table === void 0 ? void 0 : table.getHeaderCell)
284
384
  ? table.getHeaderCell.bind(table)
285
- : (colName) => __awaiter(void 0, void 0, void 0, function* () {
385
+ : async (colName) => {
286
386
  const idx = map.get(colName);
287
387
  if (idx === undefined)
288
388
  throw new Error(`Column "${colName}" not found`);
289
389
  return resolve(config.headerSelector, rootLocator).nth(idx);
290
- });
390
+ };
291
391
  for (const [col, idx] of map.entries()) {
292
392
  if ((options === null || options === void 0 ? void 0 : options.columns) && !options.columns.includes(col)) {
293
393
  continue;
@@ -299,16 +399,18 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
299
399
  const cell = config.strategies.getCellLocator
300
400
  ? config.strategies.getCellLocator({
301
401
  row: rowLocator,
402
+ root: rootLocator,
302
403
  columnName: col,
303
404
  columnIndex: idx,
304
405
  rowIndex: rowIndex,
305
- page: page
406
+ page: page,
407
+ config
306
408
  })
307
409
  : resolve(config.cellSelector, rowLocator).nth(idx);
308
410
  let targetCell = cell;
309
411
  // Always call _navigateToCell to ensure Lock-Step synchronization
310
412
  // even if the cell is already present (it handles check-in inside)
311
- const navigatedCell = yield _navigateToCell({
413
+ const navigatedCell = await _navigateToCell({
312
414
  config,
313
415
  rootLocator,
314
416
  page,
@@ -326,7 +428,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
326
428
  // Call beforeCellRead hook if configured.
327
429
  // Fires for BOTH columnOverrides.read and the default innerText path.
328
430
  if (config.strategies.beforeCellRead) {
329
- yield config.strategies.beforeCellRead({
431
+ await config.strategies.beforeCellRead({
330
432
  cell: targetCell,
331
433
  columnName: col,
332
434
  columnIndex: idx,
@@ -338,18 +440,18 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
338
440
  }
339
441
  if (mapper) {
340
442
  // Apply mapper
341
- const mappedValue = yield mapper(targetCell);
443
+ const mappedValue = await mapper(targetCell);
342
444
  result[col] = mappedValue;
343
445
  }
344
446
  else {
345
447
  // Default string extraction
346
- const text = yield targetCell.innerText();
448
+ const text = await targetCell.innerText();
347
449
  result[col] = (text || '').trim();
348
450
  }
349
451
  }
350
452
  return result;
351
- });
352
- smart.smartFill = (data, fillOptions) => __awaiter(void 0, void 0, void 0, function* () {
453
+ };
454
+ smart.smartFill = async (data, fillOptions) => {
353
455
  var _a;
354
456
  (0, debugUtils_1.logDebug)(config, 'info', 'Filling row', data);
355
457
  for (const [colName, value] of Object.entries(data)) {
@@ -359,7 +461,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
359
461
  if (colIdx === undefined) {
360
462
  throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, Array.from(map.keys())));
361
463
  }
362
- yield _navigateToCell({
464
+ await _navigateToCell({
363
465
  config,
364
466
  rootLocator,
365
467
  page: rootLocator.page(),
@@ -375,9 +477,9 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
375
477
  const cellLocator = smart.getCell(colName);
376
478
  let currentValue;
377
479
  if (columnOverride.read) {
378
- currentValue = yield columnOverride.read(cellLocator);
480
+ currentValue = await columnOverride.read(cellLocator);
379
481
  }
380
- yield columnOverride.write({
482
+ await columnOverride.write({
381
483
  cell: cellLocator,
382
484
  targetValue: value,
383
485
  currentValue,
@@ -387,7 +489,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
387
489
  else {
388
490
  const strategy = config.strategies.fill || fill_1.FillStrategies.default;
389
491
  (0, debugUtils_1.logDebug)(config, 'verbose', `Filling cell "${colName}" with value`, value);
390
- yield strategy({
492
+ await strategy({
391
493
  row: smart,
392
494
  columnName: colName,
393
495
  value,
@@ -400,11 +502,11 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
400
502
  });
401
503
  }
402
504
  // Delay after filling
403
- yield (0, debugUtils_1.debugDelay)(config, 'getCell');
505
+ await (0, debugUtils_1.debugDelay)(config, 'getCell');
404
506
  }
405
507
  (0, debugUtils_1.logDebug)(config, 'info', 'Row fill complete');
406
- });
407
- smart.bringIntoView = () => __awaiter(void 0, void 0, void 0, function* () {
508
+ };
509
+ smart.bringIntoView = async () => {
408
510
  if (rowIndex === undefined) {
409
511
  throw new Error('Cannot bring row into view - row index is unknown. Use getRowByIndex() instead of getRow().');
410
512
  }
@@ -417,19 +519,25 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
417
519
  const setCurrent = (n) => { parentTable.currentPageIndex = n; };
418
520
  if (primitives.goToPage) {
419
521
  (0, debugUtils_1.logDebug)(config, 'info', `bringIntoView: Navigating to page ${tablePageIndex} (goToPage retry loop)`);
420
- yield (0, paginationPath_1.executeNavigationWithGoToPageRetry)(tablePageIndex, primitives, context, getCurrent, setCurrent);
522
+ await (0, paginationPath_1.executeNavigationWithGoToPageRetry)(tablePageIndex, primitives, context, getCurrent, setCurrent);
421
523
  }
422
524
  else {
423
- const path = (0, paginationPath_1.planNavigationPath)(getCurrent(), tablePageIndex, primitives);
525
+ let totalPages;
526
+ if (primitives.getTotalPages) {
527
+ const tp = await primitives.getTotalPages(context);
528
+ if (tp !== null)
529
+ totalPages = tp;
530
+ }
531
+ const path = (0, paginationPath_1.planNavigationPath)(getCurrent(), tablePageIndex, primitives, totalPages);
424
532
  if (path.length > 0) {
425
533
  (0, debugUtils_1.logDebug)(config, 'info', `bringIntoView: Executing navigation path to page ${tablePageIndex} (${path.length} step(s))`);
426
- yield (0, paginationPath_1.executeNavigationPath)(path, primitives, context, getCurrent, setCurrent);
534
+ await (0, paginationPath_1.executeNavigationPath)(path, primitives, context, getCurrent, setCurrent);
427
535
  }
428
536
  else if (primitives.goToFirst && primitives.goNext && tablePageIndex >= 0) {
429
537
  (0, debugUtils_1.logDebug)(config, 'info', `bringIntoView: going to first page and looping goNext until we reach page ${tablePageIndex}`);
430
- yield primitives.goToFirst(context);
538
+ await primitives.goToFirst(context);
431
539
  for (let i = 0; i < tablePageIndex; i++) {
432
- const ok = yield primitives.goNext(context);
540
+ const ok = await primitives.goNext(context);
433
541
  if (!ok)
434
542
  throw new Error(`bringIntoView: goNext failed before reaching page ${tablePageIndex}.`);
435
543
  }
@@ -442,10 +550,10 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
442
550
  }
443
551
  }
444
552
  // Delay after pagination/finding before scrolling
445
- yield (0, debugUtils_1.debugDelay)(config, 'findRow');
553
+ await (0, debugUtils_1.debugDelay)(config, 'findRow');
446
554
  // Scroll row into view using Playwright's built-in method
447
- yield rowLocator.scrollIntoViewIfNeeded();
448
- });
555
+ await rowLocator.scrollIntoViewIfNeeded();
556
+ };
449
557
  return smart;
450
558
  };
451
559
  exports.default = createSmartRow;
@@ -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.CellNavigationStrategies = void 0;
13
4
  exports.CellNavigationStrategies = {
@@ -15,7 +6,7 @@ exports.CellNavigationStrategies = {
15
6
  * Default strategy: Assumes column is accessible or standard scrolling works.
16
7
  * No specific action taken other than what Playwright's default locator handling does.
17
8
  */
18
- default: () => __awaiter(void 0, void 0, void 0, function* () {
9
+ default: async () => {
19
10
  // No-op
20
- })
11
+ }
21
12
  };
@@ -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.DedupeStrategies = void 0;
13
4
  exports.DedupeStrategies = {
@@ -16,12 +7,12 @@ exports.DedupeStrategies = {
16
7
  * Useful for virtualized tables where row DOM elements are reused but content changes.
17
8
  * @param tolerance Pixel tolerance for position comparison (default: 2)
18
9
  */
19
- byTopPosition: (tolerance = 2) => (row) => __awaiter(void 0, void 0, void 0, function* () {
20
- const box = yield row.boundingBox();
10
+ byTopPosition: (tolerance = 2) => async (row) => {
11
+ const box = await row.boundingBox();
21
12
  if (!box)
22
13
  return 'unknown';
23
14
  // Round to nearest tolerance
24
15
  const y = Math.round(box.y / tolerance) * tolerance;
25
16
  return `pos_${y}`;
26
- })
17
+ }
27
18
  };