@reticlehq/browser 3.7.0 → 3.8.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 (104) hide show
  1. package/dist/actions/action-report.d.ts +10 -0
  2. package/dist/actions/action-report.js +59 -14
  3. package/dist/actions/actions-dom.d.ts +4 -0
  4. package/dist/actions/actions-dom.js +20 -4
  5. package/dist/actions/actions.d.ts +1 -0
  6. package/dist/actions/actions.js +94 -46
  7. package/dist/actions/appeared-text.js +2 -2
  8. package/dist/actions/click-target.d.ts +1 -0
  9. package/dist/actions/click-target.js +14 -0
  10. package/dist/actions/danger-context.d.ts +2 -1
  11. package/dist/actions/danger-context.js +43 -17
  12. package/dist/actions/scroll.d.ts +2 -0
  13. package/dist/actions/scroll.js +10 -2
  14. package/dist/activate.d.ts +14 -0
  15. package/dist/activate.js +43 -0
  16. package/dist/busy.d.ts +3 -0
  17. package/dist/busy.js +42 -0
  18. package/dist/commands/commands.js +45 -17
  19. package/dist/connect-options.d.ts +12 -1
  20. package/dist/connect-options.js +18 -1
  21. package/dist/dom/a11y.d.ts +0 -2
  22. package/dist/dom/a11y.js +103 -363
  23. package/dist/dom/chart.d.ts +3 -2
  24. package/dist/dom/chart.js +3 -2
  25. package/dist/dom/dom-ignore.d.ts +6 -0
  26. package/dist/dom/dom-ignore.js +60 -5
  27. package/dist/dom/layout-audit.d.ts +15 -0
  28. package/dist/dom/layout-audit.js +208 -0
  29. package/dist/dom/paint-context.d.ts +15 -0
  30. package/dist/dom/paint-context.js +78 -0
  31. package/dist/dom/query-finders.d.ts +6 -0
  32. package/dist/dom/query-finders.js +216 -0
  33. package/dist/dom/query.d.ts +1 -1
  34. package/dist/dom/query.js +154 -227
  35. package/dist/dom/shadow-registry.d.ts +1 -0
  36. package/dist/dom/shadow-registry.js +27 -0
  37. package/dist/dom/snapshot.d.ts +5 -0
  38. package/dist/dom/snapshot.js +87 -35
  39. package/dist/dom/stable-selector.d.ts +1 -0
  40. package/dist/dom/stable-selector.js +19 -0
  41. package/dist/dom/text-match.d.ts +12 -0
  42. package/dist/dom/text-match.js +115 -0
  43. package/dist/dom/theme.d.ts +1 -0
  44. package/dist/dom/theme.js +21 -9
  45. package/dist/dom/virtualized.js +5 -1
  46. package/dist/dom/visibility.d.ts +7 -0
  47. package/dist/dom/visibility.js +322 -0
  48. package/dist/index.d.ts +4 -2
  49. package/dist/index.js +7 -1
  50. package/dist/observers/blind-spots.js +3 -2
  51. package/dist/observers/canvas.d.ts +18 -0
  52. package/dist/observers/canvas.js +76 -0
  53. package/dist/observers/dom.js +68 -19
  54. package/dist/observers/field.d.ts +11 -0
  55. package/dist/observers/field.js +117 -13
  56. package/dist/observers/install-all.js +4 -0
  57. package/dist/observers/media.d.ts +2 -0
  58. package/dist/observers/media.js +32 -0
  59. package/dist/observers/net-detail/network-body.d.ts +2 -0
  60. package/dist/observers/net-detail/network-body.js +36 -9
  61. package/dist/observers/net-detail/network-event-stream.d.ts +5 -0
  62. package/dist/observers/net-detail/network-event-stream.js +55 -0
  63. package/dist/observers/net-detail/network-frames.d.ts +2 -0
  64. package/dist/observers/net-detail/network-frames.js +39 -0
  65. package/dist/observers/net-detail/network-response-body.d.ts +3 -0
  66. package/dist/observers/net-detail/network-response-body.js +97 -0
  67. package/dist/observers/network.js +111 -101
  68. package/dist/observers/route.d.ts +2 -0
  69. package/dist/observers/route.js +33 -4
  70. package/dist/presenter/chrome/presenter-report-copy.d.ts +0 -5
  71. package/dist/presenter/chrome/presenter-report-copy.js +0 -14
  72. package/dist/presenter/hud-telemetry.js +1 -1
  73. package/dist/presenter/presenter-chat-views.d.ts +3 -4
  74. package/dist/presenter/presenter-chat-views.js +47 -20
  75. package/dist/presenter/presenter-config.d.ts +1 -0
  76. package/dist/presenter/presenter-config.js +1 -0
  77. package/dist/presenter/presenter-frame.d.ts +3 -2
  78. package/dist/presenter/presenter-frame.js +24 -15
  79. package/dist/presenter/presenter-harness-row.d.ts +4 -15
  80. package/dist/presenter/presenter-harness-row.js +11 -50
  81. package/dist/presenter/presenter-report-styles.js +0 -17
  82. package/dist/presenter/presenter-report.d.ts +1 -2
  83. package/dist/presenter/presenter-report.js +4 -54
  84. package/dist/presenter/presenter-run-state.js +2 -1
  85. package/dist/presenter/presenter-settings.d.ts +2 -3
  86. package/dist/presenter/presenter-settings.js +14 -17
  87. package/dist/presenter/presenter-shell.d.ts +6 -4
  88. package/dist/presenter/presenter-shell.js +37 -7
  89. package/dist/presenter/presenter.js +32 -11
  90. package/dist/registry/store-adapters.d.ts +5 -2
  91. package/dist/registry/store-adapters.js +40 -10
  92. package/dist/reticle-inject.js +700 -645
  93. package/dist/reticle.d.ts +4 -2
  94. package/dist/reticle.js +36 -6
  95. package/dist/security/page-location.d.ts +2 -0
  96. package/dist/security/page-location.js +7 -0
  97. package/dist/security/serialization.js +1 -1
  98. package/dist/storage-keys.d.ts +1 -0
  99. package/dist/storage-keys.js +1 -0
  100. package/dist/timers/native/native-timers.d.ts +1 -0
  101. package/dist/timers/native/native-timers.js +5 -0
  102. package/dist/transport/transport.d.ts +1 -0
  103. package/dist/transport/transport.js +18 -0
  104. package/package.json +6 -2
package/dist/dom/a11y.js CHANGED
@@ -1,14 +1,11 @@
1
1
  import { readTestId } from './addressing/testid-attr.js';
2
2
  import { DEFAULT_TESTID_ATTR, ElementState, REDACTED_VALUE, } from '@reticlehq/core';
3
- import { isButton, isHtmlElement, isImage, isInput, isMeter, isOutput, isProgress, isSelect, isTextArea, } from './realm.js';
3
+ import { isButton, isImage, isInput, isMeter, isOutput, isProgress, isSelect, isTextArea, } from './realm.js';
4
4
  import { refs } from './addressing/refs.js';
5
- import { capturedRootOf } from './shadow-registry.js';
6
5
  import { inspectChart } from './chart.js';
7
6
  import { isSensitiveKey } from '../security/serialization.js';
8
7
  import { formatSource, sourceFromDom } from './addressing/source.js';
9
- const HTML_DETAILS_TAG = 'details';
10
- const HTML_DETAILS_OPEN_ATTRIBUTE = 'open';
11
- const HTML_SUMMARY_TAG = 'summary';
8
+ import { HTML_DETAILS_OPEN_ATTRIBUTE, HTML_DETAILS_TAG, HTML_SUMMARY_TAG, isVisible, } from './visibility.js';
12
9
  const NAME_FROM_CONTENT = new Set([
13
10
  'button',
14
11
  'link',
@@ -35,36 +32,46 @@ const NAME_FROM_CONTENT = new Set([
35
32
  const INPUT_TEXT_TYPES = new Set(['text', 'email', 'tel', 'url', 'password', '']);
36
33
  function inputRole(input) {
37
34
  const type = input.type.toLowerCase();
38
- if ('search' === type)
35
+ if ('search' === type) {
39
36
  return 'searchbox';
40
- if (INPUT_TEXT_TYPES.has(type))
37
+ }
38
+ if (INPUT_TEXT_TYPES.has(type)) {
41
39
  return 'textbox';
42
- if ('checkbox' === type)
40
+ }
41
+ if ('checkbox' === type) {
43
42
  return 'checkbox';
44
- if ('radio' === type)
43
+ }
44
+ if ('radio' === type) {
45
45
  return 'radio';
46
- if ('range' === type)
46
+ }
47
+ if ('range' === type) {
47
48
  return 'slider';
48
- if ('number' === type)
49
+ }
50
+ if ('number' === type) {
49
51
  return 'spinbutton';
50
- if ('submit' === type || 'button' === type || 'reset' === type)
52
+ }
53
+ if ('submit' === type || 'button' === type || 'reset' === type) {
51
54
  return 'button';
55
+ }
52
56
  return 'textbox';
53
57
  }
54
58
  function hasAuthorNaming(el) {
55
59
  const label = el.getAttribute('aria-label');
56
- if (label !== null && label.trim().length > 0)
60
+ if (label !== null && label.trim().length > 0) {
57
61
  return true;
62
+ }
58
63
  const labelledby = el.getAttribute('aria-labelledby');
59
- if (labelledby !== null && labelledby.trim().length > 0)
64
+ if (labelledby !== null && labelledby.trim().length > 0) {
60
65
  return true;
66
+ }
61
67
  const title = el.getAttribute('title');
62
68
  return title !== null && title.trim().length > 0;
63
69
  }
64
70
  export function getRole(el) {
65
71
  const explicit = el.getAttribute('role');
66
- if (explicit !== null && explicit.trim().length > 0)
72
+ if (explicit !== null && explicit.trim().length > 0) {
67
73
  return explicit.trim();
74
+ }
68
75
  const tag = el.tagName.toLowerCase();
69
76
  switch (tag) {
70
77
  case 'a':
@@ -154,25 +161,30 @@ function collapse(text) {
154
161
  }
155
162
  function labelledByText(el) {
156
163
  const ids = el.getAttribute('aria-labelledby');
157
- if (null === ids)
164
+ if (null === ids) {
158
165
  return null;
166
+ }
159
167
  const parts = [];
160
168
  for (const id of ids.split(/\s+/)) {
161
169
  const ref = el.ownerDocument.getElementById(id);
162
- if (ref !== null)
170
+ if (ref !== null) {
163
171
  parts.push(collapse(textWithoutHidden(ref)));
172
+ }
164
173
  }
165
174
  const joined = parts.join(' ').trim();
166
175
  return joined.length > 0 ? joined : null;
167
176
  }
168
177
  function textWithoutHidden(node) {
169
- if (node.nodeType === Node.TEXT_NODE)
178
+ if (node.nodeType === Node.TEXT_NODE) {
170
179
  return node.textContent ?? '';
171
- if (node.nodeType !== Node.ELEMENT_NODE)
180
+ }
181
+ if (node.nodeType !== Node.ELEMENT_NODE) {
172
182
  return '';
183
+ }
173
184
  const el = node;
174
- if ('true' === el.getAttribute('aria-hidden'))
185
+ if ('true' === el.getAttribute('aria-hidden')) {
175
186
  return '';
187
+ }
176
188
  if (isImage(el)) {
177
189
  const alt = el.getAttribute('alt');
178
190
  return null === alt ? '' : alt;
@@ -181,11 +193,13 @@ function textWithoutHidden(node) {
181
193
  let lastWasElement = false;
182
194
  for (const child of el.childNodes) {
183
195
  const piece = textWithoutHidden(child);
184
- if (0 === piece.length)
196
+ if (0 === piece.length) {
185
197
  continue;
198
+ }
186
199
  const isEl = Node.ELEMENT_NODE === child.nodeType;
187
- if (result.length > 0 && (isEl || lastWasElement))
200
+ if (result.length > 0 && (isEl || lastWasElement)) {
188
201
  result += ' ';
202
+ }
189
203
  result += piece;
190
204
  lastWasElement = isEl;
191
205
  }
@@ -193,15 +207,18 @@ function textWithoutHidden(node) {
193
207
  }
194
208
  export function getAccessibleName(el) {
195
209
  const labelled = labelledByText(el);
196
- if (labelled !== null)
210
+ if (labelled !== null) {
197
211
  return labelled;
212
+ }
198
213
  const ariaLabel = el.getAttribute('aria-label');
199
- if (ariaLabel !== null && ariaLabel.trim().length > 0)
214
+ if (ariaLabel !== null && ariaLabel.trim().length > 0) {
200
215
  return ariaLabel.trim();
216
+ }
201
217
  if (isImage(el)) {
202
218
  const alt = el.getAttribute('alt');
203
- if (alt !== null)
219
+ if (alt !== null) {
204
220
  return alt.trim();
221
+ }
205
222
  }
206
223
  const isLabelable = isInput(el) ||
207
224
  isTextArea(el) ||
@@ -217,16 +234,36 @@ export function getAccessibleName(el) {
217
234
  .map((l) => collapse(textWithoutHidden(l)))
218
235
  .join(' ')
219
236
  .trim();
220
- if (text.length > 0)
237
+ if (text.length > 0) {
221
238
  return text;
239
+ }
222
240
  }
223
241
  }
224
242
  if ('fieldset' === el.tagName.toLowerCase()) {
225
243
  const legend = [...el.children].find((child) => 'legend' === child.tagName.toLowerCase());
226
244
  if (legend !== undefined) {
227
245
  const text = collapse(textWithoutHidden(legend));
228
- if (text.length > 0)
246
+ if (text.length > 0) {
247
+ return text;
248
+ }
249
+ }
250
+ }
251
+ if ('table' === el.tagName.toLowerCase()) {
252
+ const caption = [...el.children].find((child) => 'caption' === child.tagName.toLowerCase());
253
+ if (caption !== undefined) {
254
+ const text = collapse(textWithoutHidden(caption));
255
+ if (text.length > 0) {
256
+ return text;
257
+ }
258
+ }
259
+ }
260
+ if ('figure' === el.tagName.toLowerCase()) {
261
+ const figcaption = [...el.children].find((child) => 'figcaption' === child.tagName.toLowerCase());
262
+ if (figcaption !== undefined) {
263
+ const text = collapse(textWithoutHidden(figcaption));
264
+ if (text.length > 0) {
229
265
  return text;
266
+ }
230
267
  }
231
268
  }
232
269
  if (isInput(el) || isTextArea(el) || isSelect(el)) {
@@ -234,49 +271,67 @@ export function getAccessibleName(el) {
234
271
  const type = el.type.toLowerCase();
235
272
  if ('submit' === type || 'button' === type || 'reset' === type) {
236
273
  const value = collapse(el.value);
237
- if (value.length > 0)
274
+ if (value.length > 0) {
238
275
  return value;
276
+ }
239
277
  }
240
278
  }
241
279
  if (isInput(el) || isTextArea(el)) {
242
280
  const placeholder = el.getAttribute('placeholder');
243
- if (placeholder !== null && placeholder.trim().length > 0)
281
+ if (placeholder !== null && placeholder.trim().length > 0) {
244
282
  return placeholder.trim();
283
+ }
245
284
  }
246
285
  }
247
286
  if (NAME_FROM_CONTENT.has(getRole(el))) {
248
287
  const text = collapse(textWithoutHidden(el));
249
- if (text.length > 0)
288
+ if (text.length > 0) {
250
289
  return text;
290
+ }
251
291
  }
252
292
  const title = el.getAttribute('title');
253
- if (title !== null && title.trim().length > 0)
293
+ if (title !== null && title.trim().length > 0) {
254
294
  return title.trim();
295
+ }
255
296
  return '';
256
297
  }
257
298
  function ariaBool(el, attr) {
258
299
  const value = el.getAttribute(attr);
259
- if (null === value)
300
+ if (null === value) {
260
301
  return undefined;
302
+ }
261
303
  return 'true' === value;
262
304
  }
263
305
  export function getStates(el, visible = isVisible(el)) {
264
306
  const states = [ElementState.PRESENT];
265
307
  states.push(visible ? ElementState.VISIBLE : ElementState.HIDDEN);
266
- const disabledProp = (isButton(el) || isInput(el) || isSelect(el) || isTextArea(el)) && el.disabled;
267
- const disabled = disabledProp || true === ariaBool(el, 'aria-disabled');
308
+ const disabled = el.matches(':disabled') || true === ariaBool(el, 'aria-disabled');
268
309
  states.push(disabled ? ElementState.DISABLED : ElementState.ENABLED);
269
310
  const checkedProp = isInput(el) && ('checkbox' === el.type || 'radio' === el.type) && el.checked;
270
- if (checkedProp || true === ariaBool(el, 'aria-checked'))
311
+ if (checkedProp || true === ariaBool(el, 'aria-checked')) {
271
312
  states.push(ElementState.CHECKED);
272
- if (true === ariaBool(el, 'aria-expanded'))
313
+ }
314
+ if (true === ariaBool(el, 'aria-expanded') || isOpenDetailsSummary(el)) {
273
315
  states.push(ElementState.EXPANDED);
274
- if (true === ariaBool(el, 'aria-pressed'))
316
+ }
317
+ if (true === ariaBool(el, 'aria-pressed')) {
275
318
  states.push(ElementState.PRESSED);
276
- if (el.ownerDocument.activeElement === el)
319
+ }
320
+ if (el.ownerDocument.activeElement === el) {
277
321
  states.push(ElementState.FOCUSED);
322
+ }
278
323
  return states;
279
324
  }
325
+ function isOpenDetailsSummary(el) {
326
+ const details = el.parentElement;
327
+ if (HTML_SUMMARY_TAG !== el.localName ||
328
+ null === details ||
329
+ HTML_DETAILS_TAG !== details.localName) {
330
+ return false;
331
+ }
332
+ const summary = Array.from(details.children).find((child) => HTML_SUMMARY_TAG === child.localName);
333
+ return summary === el && details.hasAttribute(HTML_DETAILS_OPEN_ATTRIBUTE);
334
+ }
280
335
  const SENSITIVE_AUTOCOMPLETE = /\b(cc-|current-password|new-password|one-time-code)/i;
281
336
  export function isSensitiveField(el) {
282
337
  if (!isInput(el) && !isTextArea(el) && !isSelect(el)) {
@@ -297,333 +352,14 @@ export function isSensitiveField(el) {
297
352
  }
298
353
  export function getValue(el) {
299
354
  if (isInput(el) || isTextArea(el) || isSelect(el)) {
300
- if (isSensitiveField(el))
355
+ if (isSensitiveField(el)) {
301
356
  return '' === el.value ? '' : REDACTED_VALUE;
357
+ }
302
358
  return el.value;
303
359
  }
304
360
  const valueNow = el.getAttribute('aria-valuenow');
305
361
  return valueNow ?? undefined;
306
362
  }
307
- function hiddenInsideClosedDetails(el) {
308
- const parent = el.parentElement;
309
- if (null === parent)
310
- return false;
311
- const details = parent.closest(HTML_DETAILS_TAG);
312
- if (null === details || details.hasAttribute(HTML_DETAILS_OPEN_ATTRIBUTE))
313
- return false;
314
- const summary = Array.from(details.children).find((child) => HTML_SUMMARY_TAG === child.localName);
315
- return summary === undefined || !summary.contains(el);
316
- }
317
- function stalledFade(el) {
318
- if (!el.ownerDocument.hidden || !('getAnimations' in el))
319
- return false;
320
- return el.getAnimations().some((a) => 'running' === a.playState || a.pending);
321
- }
322
- const OVERLAY_ARIA_HIDDEN = 'data-aria-hidden';
323
- function hiddenByAnOverlay(el) {
324
- return el.hasAttribute(OVERLAY_ARIA_HIDDEN);
325
- }
326
- function selfHidden(el, style) {
327
- if ('true' === el.getAttribute('aria-hidden') && !hiddenByAnOverlay(el))
328
- return true;
329
- if (isHtmlElement(el) && el.hidden)
330
- return true;
331
- if (hiddenInsideClosedDetails(el))
332
- return true;
333
- if (style !== null) {
334
- if ('none' === style.display ||
335
- 'hidden' === style.visibility ||
336
- 'collapse' === style.visibility) {
337
- return true;
338
- }
339
- if (0 === Number.parseFloat(style.opacity || '1') && !stalledFade(el))
340
- return true;
341
- }
342
- return false;
343
- }
344
- function slotInCapturedClosedRoot(el) {
345
- const host = el.parentElement;
346
- if (null === host || null !== host.shadowRoot)
347
- return null;
348
- const root = capturedRootOf(host);
349
- if (null === root)
350
- return null;
351
- for (const slot of Array.from(root.querySelectorAll('slot'))) {
352
- if (slot.assignedElements().includes(el))
353
- return slot;
354
- }
355
- return null;
356
- }
357
- function parentAcrossShadowBoundary(el) {
358
- const slot = el.assignedSlot ?? slotInCapturedClosedRoot(el);
359
- if (null !== slot)
360
- return slot;
361
- if (null !== el.parentElement)
362
- return el.parentElement;
363
- const host = el.getRootNode().host;
364
- return host ?? null;
365
- }
366
- const CLIPPING_OVERFLOW = new Set(['hidden', 'clip']);
367
- const SCROLLING_OVERFLOW = new Set(['auto', 'scroll']);
368
- const NON_CLIPPING_DISPLAY = new Set([
369
- 'contents',
370
- 'table-row',
371
- 'table-row-group',
372
- 'table-header-group',
373
- 'table-footer-group',
374
- 'table-column',
375
- 'table-column-group',
376
- ]);
377
- const TRANSFORM_CONTAINING_BLOCK_PROPERTIES = new Set([
378
- 'transform',
379
- 'translate',
380
- 'rotate',
381
- 'scale',
382
- 'perspective',
383
- ]);
384
- const CONTAINING_BLOCK_PROPERTIES = new Set([
385
- ...TRANSFORM_CONTAINING_BLOCK_PROPERTIES,
386
- 'filter',
387
- 'backdrop-filter',
388
- ]);
389
- const CONTAINING_BLOCK_CONTAIN = new Set(['layout', 'paint', 'strict', 'content']);
390
- const REPLACED_INLINE_TAGS = new Set([
391
- 'img',
392
- 'video',
393
- 'audio',
394
- 'canvas',
395
- 'iframe',
396
- 'embed',
397
- 'object',
398
- 'input',
399
- 'textarea',
400
- 'select',
401
- ]);
402
- const visibilityInfoMemos = new WeakMap();
403
- function visibilityInfoMemo(memo) {
404
- if (memo === undefined)
405
- return new Map();
406
- let info = visibilityInfoMemos.get(memo);
407
- if (info === undefined) {
408
- info = new Map();
409
- visibilityInfoMemos.set(memo, info);
410
- }
411
- return info;
412
- }
413
- function ownVisibilityInfo(el, memo) {
414
- let info = memo.get(el);
415
- if (info === undefined) {
416
- const style = el.ownerDocument.defaultView?.getComputedStyle(el) ?? null;
417
- if (selfHidden(el, style)) {
418
- info = {
419
- hidden: true,
420
- style,
421
- parent: null,
422
- clipX: false,
423
- clipY: false,
424
- scrollX: false,
425
- scrollY: false,
426
- hasClipping: false,
427
- };
428
- memo.set(el, info);
429
- return info;
430
- }
431
- const parent = parentAcrossShadowBoundary(el);
432
- const inherited = null === parent ? undefined : ownVisibilityInfo(parent, memo);
433
- const [overflowX, overflowY] = overflowAxes(style);
434
- const root = el.ownerDocument.documentElement;
435
- const viewportOverflow = el === root ||
436
- (el === el.ownerDocument.body &&
437
- overflowAxes(ownVisibilityInfo(root, memo).style).every((axis) => 'visible' === axis));
438
- const hasClipBox = !viewportOverflow &&
439
- !NON_CLIPPING_DISPLAY.has(style?.display ?? '') &&
440
- !(isHtmlElement(el) && 'inline' === style?.display);
441
- const clipX = hasClipBox && CLIPPING_OVERFLOW.has(overflowX);
442
- const clipY = hasClipBox && CLIPPING_OVERFLOW.has(overflowY);
443
- info = {
444
- hidden: true === inherited?.hidden,
445
- style,
446
- parent,
447
- clipX,
448
- clipY,
449
- scrollX: hasClipBox && SCROLLING_OVERFLOW.has(overflowX),
450
- scrollY: hasClipBox && SCROLLING_OVERFLOW.has(overflowY),
451
- hasClipping: clipX || clipY || true === inherited?.hasClipping,
452
- };
453
- memo.set(el, info);
454
- }
455
- return info;
456
- }
457
- function overflowAxes(style) {
458
- const shorthand = style?.overflow ?? '';
459
- const [x = 'visible', y = x] = ('' === shorthand ? 'visible' : shorthand).split(/\s+/);
460
- return [
461
- null === style || '' === style.overflowX ? x : style.overflowX,
462
- null === style || '' === style.overflowY ? y : style.overflowY,
463
- ];
464
- }
465
- function positionedContainingBlock(el, fixed, memo) {
466
- for (let parent = ownVisibilityInfo(el, memo).parent; parent !== null; parent = ownVisibilityInfo(parent, memo).parent) {
467
- const style = ownVisibilityInfo(parent, memo).style;
468
- if (null === style || 'contents' === style.display)
469
- continue;
470
- if (!fixed && '' !== style.position && 'static' !== style.position)
471
- return parent;
472
- const transformable = !('inline' === style.display &&
473
- isHtmlElement(parent) &&
474
- !REPLACED_INLINE_TAGS.has(parent.localName)) &&
475
- 'table-column' !== style.display &&
476
- 'table-column-group' !== style.display;
477
- const applies = (property) => transformable || !TRANSFORM_CONTAINING_BLOCK_PROPERTIES.has(property);
478
- if ([...CONTAINING_BLOCK_PROPERTIES].some((property) => {
479
- const value = style.getPropertyValue(property);
480
- return applies(property) && '' !== value && 'none' !== value;
481
- }) ||
482
- style.willChange
483
- .split(',')
484
- .some((property) => CONTAINING_BLOCK_PROPERTIES.has(property.trim()) && applies(property.trim())) ||
485
- (transformable &&
486
- !NON_CLIPPING_DISPLAY.has(style.display) &&
487
- (style.contain.split(/\s+/).some((value) => CONTAINING_BLOCK_CONTAIN.has(value)) ||
488
- 'auto' === style.contentVisibility)))
489
- return parent;
490
- }
491
- return null;
492
- }
493
- function clippingBox(el, info) {
494
- if (info.clipBox !== undefined)
495
- return info.clipBox;
496
- const rect = el.getBoundingClientRect();
497
- const style = info.style;
498
- const px = (value) => Number.parseFloat(value ?? '') || 0;
499
- const border = (value, kind) => kind === undefined || '' === kind || 'none' === kind || 'hidden' === kind ? 0 : px(value);
500
- const scaleX = isHtmlElement(el) && el.offsetWidth > 0 ? rect.width / el.offsetWidth : 1;
501
- const scaleY = isHtmlElement(el) && el.offsetHeight > 0 ? rect.height / el.offsetHeight : 1;
502
- const left = isHtmlElement(el) && el.offsetWidth > 0
503
- ? rect.left + el.clientLeft * scaleX
504
- : rect.left + border(style?.borderLeftWidth, style?.borderLeftStyle);
505
- const top = isHtmlElement(el) && el.offsetHeight > 0
506
- ? rect.top + el.clientTop * scaleY
507
- : rect.top + border(style?.borderTopWidth, style?.borderTopStyle);
508
- const right = isHtmlElement(el) && el.offsetWidth > 0
509
- ? left + el.clientWidth * scaleX
510
- : rect.right - border(style?.borderRightWidth, style?.borderRightStyle);
511
- const bottom = isHtmlElement(el) && el.offsetHeight > 0
512
- ? top + el.clientHeight * scaleY
513
- : rect.bottom - border(style?.borderBottomWidth, style?.borderBottomStyle);
514
- const margin = (style?.overflowClipMargin ?? '').split(/\s+/);
515
- const outset = px(margin.at(-1));
516
- const borderBox = margin.includes('border-box');
517
- const contentBox = margin.includes('content-box');
518
- const [x, y] = overflowAxes(style);
519
- const clipLeft = 'clip' === x
520
- ? (borderBox ? rect.left : left + (contentBox ? px(style?.paddingLeft) * scaleX : 0)) -
521
- outset * scaleX
522
- : left;
523
- const clipRight = 'clip' === x
524
- ? (borderBox ? rect.right : right - (contentBox ? px(style?.paddingRight) * scaleX : 0)) +
525
- outset * scaleX
526
- : right;
527
- const clipTop = 'clip' === y
528
- ? (borderBox ? rect.top : top + (contentBox ? px(style?.paddingTop) * scaleY : 0)) -
529
- outset * scaleY
530
- : top;
531
- const clipBottom = 'clip' === y
532
- ? (borderBox ? rect.bottom : bottom - (contentBox ? px(style?.paddingBottom) * scaleY : 0)) +
533
- outset * scaleY
534
- : bottom;
535
- info.clipBox = {
536
- left: clipLeft,
537
- right: clipRight,
538
- top: clipTop,
539
- bottom: clipBottom,
540
- width: clipRight - clipLeft,
541
- height: clipBottom - clipTop,
542
- };
543
- return info.clipBox;
544
- }
545
- function scrolledInto(b, port, alongX, alongY) {
546
- const axis = (lo, hi, size, from, to) => {
547
- if (hi > from && lo < to)
548
- return [lo, hi];
549
- const span = Math.min(size, to - from);
550
- return lo >= to ? [to - span, to] : [from, from + span];
551
- };
552
- const [left, right] = alongX
553
- ? axis(b.left, b.right, b.width, port.left, port.right)
554
- : [b.left, b.right];
555
- const [top, bottom] = alongY
556
- ? axis(b.top, b.bottom, b.height, port.top, port.bottom)
557
- : [b.top, b.bottom];
558
- return { left, right, top, bottom, width: right - left, height: bottom - top };
559
- }
560
- function visibleBounds(el, memo, initial, throughScrollers = false) {
561
- let bounds = initial;
562
- const target = ownVisibilityInfo(el, memo);
563
- if (target.hidden)
564
- return null;
565
- if (null === target.parent || !ownVisibilityInfo(target.parent, memo).hasClipping)
566
- return bounds;
567
- let clipFrom;
568
- for (let current = el; current !== null; current = ownVisibilityInfo(current, memo).parent) {
569
- const info = ownVisibilityInfo(current, memo);
570
- if (info.hidden)
571
- return null;
572
- if (current === clipFrom)
573
- clipFrom = undefined;
574
- const style = info.style;
575
- if (throughScrollers &&
576
- current !== el &&
577
- undefined === clipFrom &&
578
- (info.scrollX || info.scrollY)) {
579
- bounds ??= el.getBoundingClientRect();
580
- if (bounds.width > 0 && bounds.height > 0) {
581
- bounds = scrolledInto(bounds, clippingBox(current, info), info.scrollX, info.scrollY);
582
- }
583
- }
584
- if (current !== el && undefined === clipFrom && (info.clipX || info.clipY)) {
585
- bounds ??= el.getBoundingClientRect();
586
- if (bounds.width > 0 && bounds.height > 0) {
587
- const clip = clippingBox(current, info);
588
- const left = info.clipX ? Math.max(bounds.left, clip.left) : bounds.left;
589
- const right = info.clipX ? Math.min(bounds.right, clip.right) : bounds.right;
590
- const top = info.clipY ? Math.max(bounds.top, clip.top) : bounds.top;
591
- const bottom = info.clipY ? Math.min(bounds.bottom, clip.bottom) : bounds.bottom;
592
- if (right <= left || bottom <= top)
593
- return null;
594
- bounds = { left, right, top, bottom, width: right - left, height: bottom - top };
595
- }
596
- }
597
- if (clipFrom === undefined && ('absolute' === style?.position || 'fixed' === style?.position)) {
598
- clipFrom = positionedContainingBlock(current, 'fixed' === style?.position, memo);
599
- }
600
- }
601
- return bounds;
602
- }
603
- export function isInViewport(el, memo) {
604
- if (!isVisible(el, memo))
605
- return false;
606
- const view = el.ownerDocument.defaultView;
607
- if (null === view)
608
- return false;
609
- const r = visibleBounds(el, visibilityInfoMemo(memo), el.getBoundingClientRect());
610
- if (null === r || undefined === r)
611
- return false;
612
- if (r.width <= 0 || r.height <= 0)
613
- return false;
614
- return r.bottom > 0 && r.right > 0 && r.top < view.innerHeight && r.left < view.innerWidth;
615
- }
616
- export function isVisible(el, memo) {
617
- if (!el.isConnected)
618
- return false;
619
- const cached = memo?.get(el);
620
- if (cached !== undefined)
621
- return cached;
622
- const result = visibleBounds(el, visibilityInfoMemo(memo), undefined, true) !== null;
623
- if (memo !== undefined)
624
- memo.set(el, result);
625
- return result;
626
- }
627
363
  const MAX_TEXT = 80;
628
364
  function getVisibleText(el) {
629
365
  const text = collapse(el.textContent ?? '');
@@ -641,17 +377,21 @@ export function describe(el, memo) {
641
377
  states: getStates(el, visible),
642
378
  visible,
643
379
  };
644
- if (value !== undefined && value.length > 0)
380
+ if (value !== undefined && value.length > 0) {
645
381
  base.value = value;
646
- if (text.length > 0 && text !== name)
382
+ }
383
+ if (text.length > 0 && text !== name) {
647
384
  base.text = text;
385
+ }
648
386
  const source = formatSource(sourceFromDom(el));
649
- if (source !== undefined)
387
+ if (source !== undefined) {
650
388
  base.source = source;
389
+ }
651
390
  if (el.querySelector('path, polyline, polygon') !== null) {
652
391
  const faults = inspectChart(el).findings;
653
- if (faults.length > 0)
392
+ if (faults.length > 0) {
654
393
  base.chart = faults;
394
+ }
655
395
  }
656
396
  return base;
657
397
  }
@@ -17,7 +17,7 @@ export interface CanvasChartData {
17
17
  library: 'chartjs' | 'echarts';
18
18
  data: unknown;
19
19
  }
20
- export declare function canvasChartData(canvas: Element, globals: {
20
+ export interface ChartGlobals {
21
21
  Chart?: {
22
22
  getChart?: (el: Element) => {
23
23
  data?: unknown;
@@ -28,4 +28,5 @@ export declare function canvasChartData(canvas: Element, globals: {
28
28
  getOption?: () => unknown;
29
29
  } | undefined;
30
30
  };
31
- }): CanvasChartData | null;
31
+ }
32
+ export declare function canvasChartData(canvas: Element, globals: ChartGlobals | Window): CanvasChartData | null;
package/dist/dom/chart.js CHANGED
@@ -46,11 +46,12 @@ export function inspectChart(root) {
46
46
  return { examined, findings, canvas };
47
47
  }
48
48
  export function canvasChartData(canvas, globals) {
49
- const chartjs = globals.Chart?.getChart?.(canvas);
49
+ const libs = globals;
50
+ const chartjs = libs.Chart?.getChart?.(canvas);
50
51
  if (chartjs !== undefined && chartjs !== null) {
51
52
  return { library: 'chartjs', data: chartjs.data ?? null };
52
53
  }
53
- const echart = globals.echarts?.getInstanceByDom?.(canvas);
54
+ const echart = libs.echarts?.getInstanceByDom?.(canvas);
54
55
  if (echart !== undefined && echart !== null) {
55
56
  return { library: 'echarts', data: echart.getOption?.() ?? null };
56
57
  }
@@ -7,4 +7,10 @@ export declare function isReticleOverlay(el: Element): boolean;
7
7
  export declare function isUnobserved(el: Element): boolean;
8
8
  export declare function isReticleUi(node: Element | null): boolean;
9
9
  export declare function isIgnored(el: Element): boolean;
10
+ export declare function isWordsIgnored(el: Element): boolean;
11
+ export declare const FrameworkErrorDialog: {
12
+ readonly NEXT: "Next.js error dialog";
13
+ readonly VITE: "Vite error overlay";
14
+ };
15
+ export declare function dialogCovering(matches: readonly Element[]): string | undefined;
10
16
  export declare function appModalOpen(doc: Document): boolean;