@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.
- package/dist/actions/action-report.d.ts +10 -0
- package/dist/actions/action-report.js +59 -14
- package/dist/actions/actions-dom.d.ts +4 -0
- package/dist/actions/actions-dom.js +20 -4
- package/dist/actions/actions.d.ts +1 -0
- package/dist/actions/actions.js +94 -46
- package/dist/actions/appeared-text.js +2 -2
- package/dist/actions/click-target.d.ts +1 -0
- package/dist/actions/click-target.js +14 -0
- package/dist/actions/danger-context.d.ts +2 -1
- package/dist/actions/danger-context.js +43 -17
- package/dist/actions/scroll.d.ts +2 -0
- package/dist/actions/scroll.js +10 -2
- package/dist/activate.d.ts +14 -0
- package/dist/activate.js +43 -0
- package/dist/busy.d.ts +3 -0
- package/dist/busy.js +42 -0
- package/dist/commands/commands.js +45 -17
- package/dist/connect-options.d.ts +12 -1
- package/dist/connect-options.js +18 -1
- package/dist/dom/a11y.d.ts +0 -2
- package/dist/dom/a11y.js +103 -363
- package/dist/dom/chart.d.ts +3 -2
- package/dist/dom/chart.js +3 -2
- package/dist/dom/dom-ignore.d.ts +6 -0
- package/dist/dom/dom-ignore.js +60 -5
- package/dist/dom/layout-audit.d.ts +15 -0
- package/dist/dom/layout-audit.js +208 -0
- package/dist/dom/paint-context.d.ts +15 -0
- package/dist/dom/paint-context.js +78 -0
- package/dist/dom/query-finders.d.ts +6 -0
- package/dist/dom/query-finders.js +216 -0
- package/dist/dom/query.d.ts +1 -1
- package/dist/dom/query.js +154 -227
- package/dist/dom/shadow-registry.d.ts +1 -0
- package/dist/dom/shadow-registry.js +27 -0
- package/dist/dom/snapshot.d.ts +5 -0
- package/dist/dom/snapshot.js +87 -35
- package/dist/dom/stable-selector.d.ts +1 -0
- package/dist/dom/stable-selector.js +19 -0
- package/dist/dom/text-match.d.ts +12 -0
- package/dist/dom/text-match.js +115 -0
- package/dist/dom/theme.d.ts +1 -0
- package/dist/dom/theme.js +21 -9
- package/dist/dom/virtualized.js +5 -1
- package/dist/dom/visibility.d.ts +7 -0
- package/dist/dom/visibility.js +322 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +7 -1
- package/dist/observers/blind-spots.js +3 -2
- package/dist/observers/canvas.d.ts +18 -0
- package/dist/observers/canvas.js +76 -0
- package/dist/observers/dom.js +68 -19
- package/dist/observers/field.d.ts +11 -0
- package/dist/observers/field.js +117 -13
- package/dist/observers/install-all.js +4 -0
- package/dist/observers/media.d.ts +2 -0
- package/dist/observers/media.js +32 -0
- package/dist/observers/net-detail/network-body.d.ts +2 -0
- package/dist/observers/net-detail/network-body.js +36 -9
- package/dist/observers/net-detail/network-event-stream.d.ts +5 -0
- package/dist/observers/net-detail/network-event-stream.js +55 -0
- package/dist/observers/net-detail/network-frames.d.ts +2 -0
- package/dist/observers/net-detail/network-frames.js +39 -0
- package/dist/observers/net-detail/network-response-body.d.ts +3 -0
- package/dist/observers/net-detail/network-response-body.js +97 -0
- package/dist/observers/network.js +111 -101
- package/dist/observers/route.d.ts +2 -0
- package/dist/observers/route.js +33 -4
- package/dist/presenter/chrome/presenter-report-copy.d.ts +0 -5
- package/dist/presenter/chrome/presenter-report-copy.js +0 -14
- package/dist/presenter/hud-telemetry.js +1 -1
- package/dist/presenter/presenter-chat-views.d.ts +3 -4
- package/dist/presenter/presenter-chat-views.js +47 -20
- package/dist/presenter/presenter-config.d.ts +1 -0
- package/dist/presenter/presenter-config.js +1 -0
- package/dist/presenter/presenter-frame.d.ts +3 -2
- package/dist/presenter/presenter-frame.js +24 -15
- package/dist/presenter/presenter-harness-row.d.ts +4 -15
- package/dist/presenter/presenter-harness-row.js +11 -50
- package/dist/presenter/presenter-report-styles.js +0 -17
- package/dist/presenter/presenter-report.d.ts +1 -2
- package/dist/presenter/presenter-report.js +4 -54
- package/dist/presenter/presenter-run-state.js +2 -1
- package/dist/presenter/presenter-settings.d.ts +2 -3
- package/dist/presenter/presenter-settings.js +14 -17
- package/dist/presenter/presenter-shell.d.ts +6 -4
- package/dist/presenter/presenter-shell.js +37 -7
- package/dist/presenter/presenter.js +32 -11
- package/dist/registry/store-adapters.d.ts +5 -2
- package/dist/registry/store-adapters.js +40 -10
- package/dist/reticle-inject.js +700 -645
- package/dist/reticle.d.ts +4 -2
- package/dist/reticle.js +36 -6
- package/dist/security/page-location.d.ts +2 -0
- package/dist/security/page-location.js +7 -0
- package/dist/security/serialization.js +1 -1
- package/dist/storage-keys.d.ts +1 -0
- package/dist/storage-keys.js +1 -0
- package/dist/timers/native/native-timers.d.ts +1 -0
- package/dist/timers/native/native-timers.js +5 -0
- package/dist/transport/transport.d.ts +1 -0
- package/dist/transport/transport.js +18 -0
- 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,
|
|
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
|
-
|
|
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
|
-
|
|
37
|
+
}
|
|
38
|
+
if (INPUT_TEXT_TYPES.has(type)) {
|
|
41
39
|
return 'textbox';
|
|
42
|
-
|
|
40
|
+
}
|
|
41
|
+
if ('checkbox' === type) {
|
|
43
42
|
return 'checkbox';
|
|
44
|
-
|
|
43
|
+
}
|
|
44
|
+
if ('radio' === type) {
|
|
45
45
|
return 'radio';
|
|
46
|
-
|
|
46
|
+
}
|
|
47
|
+
if ('range' === type) {
|
|
47
48
|
return 'slider';
|
|
48
|
-
|
|
49
|
+
}
|
|
50
|
+
if ('number' === type) {
|
|
49
51
|
return 'spinbutton';
|
|
50
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
313
|
+
}
|
|
314
|
+
if (true === ariaBool(el, 'aria-expanded') || isOpenDetailsSummary(el)) {
|
|
273
315
|
states.push(ElementState.EXPANDED);
|
|
274
|
-
|
|
316
|
+
}
|
|
317
|
+
if (true === ariaBool(el, 'aria-pressed')) {
|
|
275
318
|
states.push(ElementState.PRESSED);
|
|
276
|
-
|
|
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
|
-
|
|
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
|
}
|
package/dist/dom/chart.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface CanvasChartData {
|
|
|
17
17
|
library: 'chartjs' | 'echarts';
|
|
18
18
|
data: unknown;
|
|
19
19
|
}
|
|
20
|
-
export
|
|
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
|
-
}
|
|
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
|
|
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 =
|
|
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
|
}
|
package/dist/dom/dom-ignore.d.ts
CHANGED
|
@@ -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;
|