accented 0.0.0-20250303013509 → 0.0.0-20250404114312
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/NOTICE +14 -0
- package/README.md +7 -3
- package/dist/accented.d.ts +2 -2
- package/dist/accented.d.ts.map +1 -1
- package/dist/accented.js +5 -2
- package/dist/accented.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/dom-updater.d.ts.map +1 -1
- package/dist/dom-updater.js +38 -23
- package/dist/dom-updater.js.map +1 -1
- package/dist/elements/accented-dialog.d.ts.map +1 -1
- package/dist/elements/accented-dialog.js +50 -22
- package/dist/elements/accented-dialog.js.map +1 -1
- package/dist/elements/accented-trigger.d.ts.map +1 -1
- package/dist/elements/accented-trigger.js +32 -9
- package/dist/elements/accented-trigger.js.map +1 -1
- package/dist/fullscreen-listener.d.ts +2 -0
- package/dist/fullscreen-listener.d.ts.map +1 -0
- package/dist/fullscreen-listener.js +18 -0
- package/dist/fullscreen-listener.js.map +1 -0
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +15 -6
- package/dist/scanner.js.map +1 -1
- package/dist/state.d.ts +2 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +3 -0
- package/dist/state.js.map +1 -1
- package/dist/types.d.ts +17 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/are-elements-with-issues-equal.d.ts +3 -0
- package/dist/utils/are-elements-with-issues-equal.d.ts.map +1 -0
- package/dist/utils/are-elements-with-issues-equal.js +5 -0
- package/dist/utils/are-elements-with-issues-equal.js.map +1 -0
- package/dist/utils/dom-helpers.d.ts +6 -0
- package/dist/utils/dom-helpers.d.ts.map +1 -0
- package/dist/utils/dom-helpers.js +19 -0
- package/dist/utils/dom-helpers.js.map +1 -0
- package/dist/utils/get-element-position.d.ts.map +1 -1
- package/dist/utils/get-element-position.js +5 -4
- package/dist/utils/get-element-position.js.map +1 -1
- package/dist/utils/get-parent.d.ts +2 -0
- package/dist/utils/get-parent.d.ts.map +1 -0
- package/dist/utils/get-parent.js +12 -0
- package/dist/utils/get-parent.js.map +1 -0
- package/dist/utils/get-scrollable-ancestors.d.ts +1 -1
- package/dist/utils/get-scrollable-ancestors.d.ts.map +1 -1
- package/dist/utils/get-scrollable-ancestors.js +6 -2
- package/dist/utils/get-scrollable-ancestors.js.map +1 -1
- package/dist/utils/shadow-dom-aware-mutation-observer.d.ts +10 -0
- package/dist/utils/shadow-dom-aware-mutation-observer.d.ts.map +1 -0
- package/dist/utils/shadow-dom-aware-mutation-observer.js +64 -0
- package/dist/utils/shadow-dom-aware-mutation-observer.js.map +1 -0
- package/dist/utils/transform-violations.d.ts +1 -1
- package/dist/utils/transform-violations.d.ts.map +1 -1
- package/dist/utils/transform-violations.js +18 -5
- package/dist/utils/transform-violations.js.map +1 -1
- package/dist/utils/update-elements-with-issues.d.ts.map +1 -1
- package/dist/utils/update-elements-with-issues.js +9 -5
- package/dist/utils/update-elements-with-issues.js.map +1 -1
- package/package.json +4 -3
- package/src/accented.ts +5 -2
- package/src/constants.ts +1 -0
- package/src/dom-updater.ts +38 -22
- package/src/elements/accented-dialog.ts +50 -22
- package/src/elements/accented-trigger.ts +33 -10
- package/src/fullscreen-listener.ts +17 -0
- package/src/scanner.ts +17 -6
- package/src/state.ts +10 -2
- package/src/types.ts +19 -6
- package/src/utils/are-elements-with-issues-equal.ts +9 -0
- package/src/utils/dom-helpers.ts +22 -0
- package/src/utils/get-element-position.ts +5 -4
- package/src/utils/get-parent.ts +14 -0
- package/src/utils/get-scrollable-ancestors.ts +10 -5
- package/src/utils/shadow-dom-aware-mutation-observer.ts +78 -0
- package/src/utils/transform-violations.test.ts +10 -8
- package/src/utils/transform-violations.ts +20 -6
- package/src/utils/update-elements-with-issues.test.ts +42 -8
- package/src/utils/update-elements-with-issues.ts +10 -5
- package/dist/utils/is-html-element.d.ts +0 -2
- package/dist/utils/is-html-element.d.ts.map +0 -1
- package/dist/utils/is-html-element.js +0 -7
- package/dist/utils/is-html-element.js.map +0 -1
- package/src/utils/is-html-element.ts +0 -6
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { isElement, isDocument, isDocumentFragment } from './dom-helpers.js';
|
|
2
|
+
import { getAccentedElementNames } from '../constants.js';
|
|
3
|
+
|
|
4
|
+
export default function createShadowDOMAwareMutationObserver (name: string, callback: MutationCallback) {
|
|
5
|
+
class ShadowDOMAwareMutationObserver extends MutationObserver {
|
|
6
|
+
#shadowRoots = new Set();
|
|
7
|
+
|
|
8
|
+
#options: MutationObserverInit | undefined;
|
|
9
|
+
|
|
10
|
+
constructor(callback: MutationCallback) {
|
|
11
|
+
super((mutations, observer) => {
|
|
12
|
+
const accentedElementNames = getAccentedElementNames(name);
|
|
13
|
+
const childListMutations = mutations
|
|
14
|
+
.filter(mutation => mutation.type === 'childList')
|
|
15
|
+
|
|
16
|
+
const newElements = childListMutations
|
|
17
|
+
.map(mutation => [...mutation.addedNodes])
|
|
18
|
+
.flat()
|
|
19
|
+
.filter(node => isElement(node))
|
|
20
|
+
.filter(node => !accentedElementNames.includes(node.nodeName.toLowerCase()));
|
|
21
|
+
|
|
22
|
+
this.#observeShadowRoots(newElements);
|
|
23
|
+
|
|
24
|
+
const removedElements = childListMutations
|
|
25
|
+
.map(mutation => [...mutation.removedNodes])
|
|
26
|
+
.flat()
|
|
27
|
+
.filter(node => isElement(node))
|
|
28
|
+
.filter(node => !accentedElementNames.includes(node.nodeName.toLowerCase()));
|
|
29
|
+
|
|
30
|
+
// Mutation observer has no "unobserve" method, so we're simply deleting
|
|
31
|
+
// the elements from the set of shadow roots.
|
|
32
|
+
this.#deleteShadowRoots(removedElements);
|
|
33
|
+
|
|
34
|
+
callback(mutations, observer);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
override observe(target: Node, options?: MutationObserverInit): void {
|
|
39
|
+
this.#options ??= options;
|
|
40
|
+
if (isElement(target) || isDocument(target) || isDocumentFragment(target)) {
|
|
41
|
+
this.#observeShadowRoots([target]);
|
|
42
|
+
}
|
|
43
|
+
super.observe(target, options);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override disconnect(): void {
|
|
47
|
+
this.#shadowRoots.clear();
|
|
48
|
+
super.disconnect();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
#observeShadowRoots = (elements: Array<Element | Document | DocumentFragment>) => {
|
|
52
|
+
const shadowRoots = elements
|
|
53
|
+
.map(element => [...element.querySelectorAll('*')])
|
|
54
|
+
.flat()
|
|
55
|
+
.filter(element => element.shadowRoot)
|
|
56
|
+
.map(element => element.shadowRoot!);
|
|
57
|
+
|
|
58
|
+
for (const shadowRoot of shadowRoots) {
|
|
59
|
+
this.#shadowRoots.add(shadowRoot);
|
|
60
|
+
this.observe(shadowRoot, this.#options);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#deleteShadowRoots = (elements: Array<Element | Document | DocumentFragment>) => {
|
|
65
|
+
const shadowRoots = elements
|
|
66
|
+
.map(element => [...element.querySelectorAll('*')])
|
|
67
|
+
.flat()
|
|
68
|
+
.filter(element => element.shadowRoot)
|
|
69
|
+
.map(element => element.shadowRoot!);
|
|
70
|
+
|
|
71
|
+
for (const shadowRoot of shadowRoots) {
|
|
72
|
+
this.#shadowRoots.delete(shadowRoot);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return new ShadowDOMAwareMutationObserver(callback);
|
|
78
|
+
}
|
|
@@ -24,12 +24,14 @@ const commonViolationProps2: Omit<Violation, 'nodes'> = {
|
|
|
24
24
|
impact: 'serious'
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
const getRootNode = (): Node => ({} as Node);
|
|
28
|
+
|
|
27
29
|
// @ts-expect-error element is not HTMLElement
|
|
28
|
-
const element1: HTMLElement = {};
|
|
30
|
+
const element1: HTMLElement = {getRootNode};
|
|
29
31
|
// @ts-expect-error element is not HTMLElement
|
|
30
|
-
const element2: HTMLElement = {};
|
|
32
|
+
const element2: HTMLElement = {getRootNode};
|
|
31
33
|
// @ts-expect-error element is not HTMLElement
|
|
32
|
-
const element3: HTMLElement = {};
|
|
34
|
+
const element3: HTMLElement = {getRootNode};
|
|
33
35
|
|
|
34
36
|
const commonNodeProps = {
|
|
35
37
|
html: '<div></div>',
|
|
@@ -65,7 +67,7 @@ suite('transformViolations', () => {
|
|
|
65
67
|
...commonViolationProps1,
|
|
66
68
|
nodes: [node1]
|
|
67
69
|
};
|
|
68
|
-
const elementsWithIssues = transformViolations([violation]);
|
|
70
|
+
const elementsWithIssues = transformViolations([violation], 'accented');
|
|
69
71
|
assert.equal(elementsWithIssues.length, 1);
|
|
70
72
|
assert.equal(elementsWithIssues[0]?.element, element1);
|
|
71
73
|
assert.equal(elementsWithIssues[0].issues.length, 1);
|
|
@@ -82,7 +84,7 @@ suite('transformViolations', () => {
|
|
|
82
84
|
...commonViolationProps2,
|
|
83
85
|
nodes: [node1, node3]
|
|
84
86
|
};
|
|
85
|
-
const elementsWithIssues = transformViolations([violation1, violation2]);
|
|
87
|
+
const elementsWithIssues = transformViolations([violation1, violation2], 'accented');
|
|
86
88
|
assert.equal(elementsWithIssues.length, 3);
|
|
87
89
|
const elementWithTwoIssues = elementsWithIssues.find(elementWithIssues => elementWithIssues.element === element1);
|
|
88
90
|
assert.equal(elementWithTwoIssues?.issues.length, 2);
|
|
@@ -101,7 +103,7 @@ suite('transformViolations', () => {
|
|
|
101
103
|
nodes: [node]
|
|
102
104
|
};
|
|
103
105
|
|
|
104
|
-
const elementsWithIssues = transformViolations([violation]);
|
|
106
|
+
const elementsWithIssues = transformViolations([violation], 'accented');
|
|
105
107
|
assert.equal(elementsWithIssues.length, 0);
|
|
106
108
|
});
|
|
107
109
|
|
|
@@ -118,7 +120,7 @@ suite('transformViolations', () => {
|
|
|
118
120
|
nodes: [node]
|
|
119
121
|
};
|
|
120
122
|
|
|
121
|
-
const elementsWithIssues = transformViolations([violation]);
|
|
122
|
-
assert.equal(elementsWithIssues.length,
|
|
123
|
+
const elementsWithIssues = transformViolations([violation], 'accented');
|
|
124
|
+
assert.equal(elementsWithIssues.length, 1);
|
|
123
125
|
});
|
|
124
126
|
});
|
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import type { AxeResults, ImpactValue } from 'axe-core';
|
|
2
2
|
import type { Issue, ElementWithIssues } from '../types';
|
|
3
3
|
|
|
4
|
+
// This is a list of axe-core violations (their ids) that may be flagged by axe-core
|
|
5
|
+
// as false positives if an Accented trigger is a descendant of the element with the issue.
|
|
6
|
+
const violationsAffectedByAccentedTriggers = [
|
|
7
|
+
'aria-hidden-focus',
|
|
8
|
+
'aria-text',
|
|
9
|
+
'definition-list',
|
|
10
|
+
'label-content-name-mismatch',
|
|
11
|
+
'list',
|
|
12
|
+
'nested-interactive',
|
|
13
|
+
'scrollable-region-focusable' // The Accented trigger might make the content grow such that scrolling is required.
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
function maybeCausedByAccented(violationId: string, element: HTMLElement, name: string) {
|
|
17
|
+
return violationsAffectedByAccentedTriggers.includes(violationId)
|
|
18
|
+
&& Boolean(element.querySelector(`${name}-trigger`));
|
|
19
|
+
}
|
|
20
|
+
|
|
4
21
|
function impactCompare(a: ImpactValue, b: ImpactValue) {
|
|
5
22
|
const impactOrder = [null, 'minor', 'moderate', 'serious', 'critical'];
|
|
6
23
|
return impactOrder.indexOf(a) - impactOrder.indexOf(b);
|
|
7
24
|
}
|
|
8
25
|
|
|
9
|
-
export default function transformViolations(violations: typeof AxeResults.violations) {
|
|
26
|
+
export default function transformViolations(violations: typeof AxeResults.violations, name: string) {
|
|
10
27
|
const elementsWithIssues: Array<ElementWithIssues> = [];
|
|
11
28
|
|
|
12
29
|
for (const violation of violations) {
|
|
@@ -21,11 +38,7 @@ export default function transformViolations(violations: typeof AxeResults.violat
|
|
|
21
38
|
// A consumer of Accented can instead scan the iframed document by calling Accented initialization from that document.
|
|
22
39
|
const isInIframe = target.length > 1;
|
|
23
40
|
|
|
24
|
-
|
|
25
|
-
// Until then, we don’t want such elements to be added to the set.
|
|
26
|
-
const isInShadowDOM = Array.isArray(target[0]);
|
|
27
|
-
|
|
28
|
-
if (element && !isInIframe && !isInShadowDOM) {
|
|
41
|
+
if (element && !isInIframe && !maybeCausedByAccented(violation.id, element, name)) {
|
|
29
42
|
const issue: Issue = {
|
|
30
43
|
id: violation.id,
|
|
31
44
|
title: violation.help,
|
|
@@ -37,6 +50,7 @@ export default function transformViolations(violations: typeof AxeResults.violat
|
|
|
37
50
|
if (existingElementIndex === -1) {
|
|
38
51
|
elementsWithIssues.push({
|
|
39
52
|
element,
|
|
53
|
+
rootNode: element.getRootNode(),
|
|
40
54
|
issues: [issue]
|
|
41
55
|
});
|
|
42
56
|
} else {
|
|
@@ -8,7 +8,7 @@ import updateElementsWithIssues from './update-elements-with-issues';
|
|
|
8
8
|
import type { AxeResults, ImpactValue } from 'axe-core';
|
|
9
9
|
import type { AccentedTrigger } from '../elements/accented-trigger';
|
|
10
10
|
type Violation = AxeResults['violations'][number];
|
|
11
|
-
type
|
|
11
|
+
type AxeNode = Violation['nodes'][number];
|
|
12
12
|
|
|
13
13
|
const win: Window & { CSS: typeof CSS } = {
|
|
14
14
|
document: {
|
|
@@ -23,7 +23,8 @@ const win: Window & { CSS: typeof CSS } = {
|
|
|
23
23
|
// @ts-expect-error we're missing a lot of properties
|
|
24
24
|
getComputedStyle: () => ({
|
|
25
25
|
zIndex: '',
|
|
26
|
-
direction: 'ltr'
|
|
26
|
+
direction: 'ltr',
|
|
27
|
+
getPropertyValue: () => 'none'
|
|
27
28
|
}),
|
|
28
29
|
// @ts-expect-error we're missing a lot of properties
|
|
29
30
|
CSS: {
|
|
@@ -33,12 +34,25 @@ const win: Window & { CSS: typeof CSS } = {
|
|
|
33
34
|
|
|
34
35
|
const getBoundingClientRect = () => ({});
|
|
35
36
|
|
|
37
|
+
const getRootNode = (): Node => ({} as Node);
|
|
38
|
+
|
|
39
|
+
const baseElement = {
|
|
40
|
+
getBoundingClientRect,
|
|
41
|
+
getRootNode,
|
|
42
|
+
style: {
|
|
43
|
+
getPropertyValue: () => ''
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
36
47
|
// @ts-expect-error element is not HTMLElement
|
|
37
|
-
const element1: HTMLElement = {
|
|
48
|
+
const element1: HTMLElement = {...baseElement, isConnected: true};
|
|
38
49
|
// @ts-expect-error element is not HTMLElement
|
|
39
|
-
const element2: HTMLElement = {
|
|
50
|
+
const element2: HTMLElement = {...baseElement, isConnected: true};
|
|
40
51
|
// @ts-expect-error element is not HTMLElement
|
|
41
|
-
const element3: HTMLElement = {
|
|
52
|
+
const element3: HTMLElement = {...baseElement, isConnected: false};
|
|
53
|
+
|
|
54
|
+
// @ts-expect-error rootNode is not Node
|
|
55
|
+
const rootNode: Node = {};
|
|
42
56
|
|
|
43
57
|
const trigger = win.document.createElement('accented-trigger') as AccentedTrigger;
|
|
44
58
|
|
|
@@ -61,17 +75,17 @@ const commonNodeProps = {
|
|
|
61
75
|
target: ['div']
|
|
62
76
|
};
|
|
63
77
|
|
|
64
|
-
const node1:
|
|
78
|
+
const node1: AxeNode = {
|
|
65
79
|
...commonNodeProps,
|
|
66
80
|
element: element1,
|
|
67
81
|
};
|
|
68
82
|
|
|
69
|
-
const node2:
|
|
83
|
+
const node2: AxeNode = {
|
|
70
84
|
...commonNodeProps,
|
|
71
85
|
element: element2,
|
|
72
86
|
};
|
|
73
87
|
|
|
74
|
-
const node3:
|
|
88
|
+
const node3: AxeNode = {
|
|
75
89
|
...commonNodeProps,
|
|
76
90
|
element: element3,
|
|
77
91
|
};
|
|
@@ -136,18 +150,22 @@ suite('updateElementsWithIssues', () => {
|
|
|
136
150
|
{
|
|
137
151
|
id: 1,
|
|
138
152
|
element: element1,
|
|
153
|
+
rootNode,
|
|
139
154
|
position,
|
|
140
155
|
visible,
|
|
141
156
|
trigger,
|
|
157
|
+
anchorNameValue: 'none',
|
|
142
158
|
scrollableAncestors,
|
|
143
159
|
issues: signal([issue1])
|
|
144
160
|
},
|
|
145
161
|
{
|
|
146
162
|
id: 2,
|
|
147
163
|
element: element2,
|
|
164
|
+
rootNode,
|
|
148
165
|
position,
|
|
149
166
|
visible,
|
|
150
167
|
trigger,
|
|
168
|
+
anchorNameValue: 'none',
|
|
151
169
|
scrollableAncestors,
|
|
152
170
|
issues: signal([issue2])
|
|
153
171
|
}
|
|
@@ -165,18 +183,22 @@ suite('updateElementsWithIssues', () => {
|
|
|
165
183
|
{
|
|
166
184
|
id: 1,
|
|
167
185
|
element: element1,
|
|
186
|
+
rootNode,
|
|
168
187
|
position,
|
|
169
188
|
visible,
|
|
170
189
|
trigger,
|
|
190
|
+
anchorNameValue: 'none',
|
|
171
191
|
scrollableAncestors,
|
|
172
192
|
issues: signal([issue1])
|
|
173
193
|
},
|
|
174
194
|
{
|
|
175
195
|
id: 2,
|
|
176
196
|
element: element2,
|
|
197
|
+
rootNode,
|
|
177
198
|
position,
|
|
178
199
|
visible,
|
|
179
200
|
trigger,
|
|
201
|
+
anchorNameValue: 'none',
|
|
180
202
|
scrollableAncestors,
|
|
181
203
|
issues: signal([issue2])
|
|
182
204
|
}
|
|
@@ -194,18 +216,22 @@ suite('updateElementsWithIssues', () => {
|
|
|
194
216
|
{
|
|
195
217
|
id: 1,
|
|
196
218
|
element: element1,
|
|
219
|
+
rootNode,
|
|
197
220
|
position,
|
|
198
221
|
visible,
|
|
199
222
|
trigger,
|
|
223
|
+
anchorNameValue: 'none',
|
|
200
224
|
scrollableAncestors,
|
|
201
225
|
issues: signal([issue1])
|
|
202
226
|
},
|
|
203
227
|
{
|
|
204
228
|
id: 2,
|
|
205
229
|
element: element2,
|
|
230
|
+
rootNode,
|
|
206
231
|
position,
|
|
207
232
|
visible,
|
|
208
233
|
trigger,
|
|
234
|
+
anchorNameValue: 'none',
|
|
209
235
|
scrollableAncestors,
|
|
210
236
|
issues: signal([issue2, issue3])
|
|
211
237
|
}
|
|
@@ -223,9 +249,11 @@ suite('updateElementsWithIssues', () => {
|
|
|
223
249
|
{
|
|
224
250
|
id: 1,
|
|
225
251
|
element: element1,
|
|
252
|
+
rootNode,
|
|
226
253
|
position,
|
|
227
254
|
visible,
|
|
228
255
|
trigger,
|
|
256
|
+
anchorNameValue: 'none',
|
|
229
257
|
scrollableAncestors,
|
|
230
258
|
issues: signal([issue1])
|
|
231
259
|
}
|
|
@@ -243,9 +271,11 @@ suite('updateElementsWithIssues', () => {
|
|
|
243
271
|
{
|
|
244
272
|
id: 1,
|
|
245
273
|
element: element1,
|
|
274
|
+
rootNode,
|
|
246
275
|
position,
|
|
247
276
|
visible,
|
|
248
277
|
trigger,
|
|
278
|
+
anchorNameValue: 'none',
|
|
249
279
|
scrollableAncestors,
|
|
250
280
|
issues: signal([issue1])
|
|
251
281
|
}
|
|
@@ -260,18 +290,22 @@ suite('updateElementsWithIssues', () => {
|
|
|
260
290
|
{
|
|
261
291
|
id: 1,
|
|
262
292
|
element: element1,
|
|
293
|
+
rootNode,
|
|
263
294
|
position,
|
|
264
295
|
visible,
|
|
265
296
|
trigger,
|
|
297
|
+
anchorNameValue: 'none',
|
|
266
298
|
scrollableAncestors,
|
|
267
299
|
issues: signal([issue1])
|
|
268
300
|
},
|
|
269
301
|
{
|
|
270
302
|
id: 2,
|
|
271
303
|
element: element2,
|
|
304
|
+
rootNode,
|
|
272
305
|
position,
|
|
273
306
|
visible,
|
|
274
307
|
trigger,
|
|
308
|
+
anchorNameValue: 'none',
|
|
275
309
|
scrollableAncestors,
|
|
276
310
|
issues: signal([issue2])
|
|
277
311
|
}
|
|
@@ -3,6 +3,7 @@ import type { Signal } from '@preact/signals-core';
|
|
|
3
3
|
import { batch, signal } from '@preact/signals-core';
|
|
4
4
|
import type { ExtendedElementWithIssues } from '../types';
|
|
5
5
|
import transformViolations from './transform-violations.js';
|
|
6
|
+
import areElementsWithIssuesEqual from './are-elements-with-issues-equal.js';
|
|
6
7
|
import areIssueSetsEqual from './are-issue-sets-equal.js';
|
|
7
8
|
import type { AccentedTrigger } from '../elements/accented-trigger';
|
|
8
9
|
import type { AccentedDialog } from '../elements/accented-dialog';
|
|
@@ -13,28 +14,28 @@ import supportsAnchorPositioning from './supports-anchor-positioning.js';
|
|
|
13
14
|
let count = 0;
|
|
14
15
|
|
|
15
16
|
export default function updateElementsWithIssues(extendedElementsWithIssues: Signal<Array<ExtendedElementWithIssues>>, violations: typeof AxeResults.violations, win: Window & { CSS: typeof CSS }, name: string) {
|
|
16
|
-
const updatedElementsWithIssues = transformViolations(violations);
|
|
17
|
+
const updatedElementsWithIssues = transformViolations(violations, name);
|
|
17
18
|
|
|
18
19
|
batch(() => {
|
|
19
20
|
for (const updatedElementWithIssues of updatedElementsWithIssues) {
|
|
20
|
-
const existingElementIndex = extendedElementsWithIssues.value.findIndex(extendedElementWithIssues => extendedElementWithIssues
|
|
21
|
+
const existingElementIndex = extendedElementsWithIssues.value.findIndex(extendedElementWithIssues => areElementsWithIssuesEqual(extendedElementWithIssues, updatedElementWithIssues));
|
|
21
22
|
if (existingElementIndex > -1 && extendedElementsWithIssues.value[existingElementIndex] && !areIssueSetsEqual(extendedElementsWithIssues.value[existingElementIndex].issues.value, updatedElementWithIssues.issues)) {
|
|
22
23
|
extendedElementsWithIssues.value[existingElementIndex].issues.value = updatedElementWithIssues.issues;
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
const addedElementsWithIssues = updatedElementsWithIssues.filter(updatedElementWithIssues => {
|
|
27
|
-
return !extendedElementsWithIssues.value.some(extendedElementWithIssues => extendedElementWithIssues
|
|
28
|
+
return !extendedElementsWithIssues.value.some(extendedElementWithIssues => areElementsWithIssuesEqual(extendedElementWithIssues, updatedElementWithIssues));
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
const removedElementsWithIssues = extendedElementsWithIssues.value.filter(extendedElementWithIssues => {
|
|
31
|
-
return !updatedElementsWithIssues.some(updatedElementWithIssues => updatedElementWithIssues
|
|
32
|
+
return !updatedElementsWithIssues.some(updatedElementWithIssues => areElementsWithIssuesEqual(updatedElementWithIssues, extendedElementWithIssues));
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
if (addedElementsWithIssues.length > 0 || removedElementsWithIssues.length > 0) {
|
|
35
36
|
extendedElementsWithIssues.value = [...extendedElementsWithIssues.value]
|
|
36
37
|
.filter(extendedElementWithIssues => {
|
|
37
|
-
return !removedElementsWithIssues.some(removedElementWithIssues => removedElementWithIssues
|
|
38
|
+
return !removedElementsWithIssues.some(removedElementWithIssues => areElementsWithIssuesEqual(removedElementWithIssues, extendedElementWithIssues));
|
|
38
39
|
})
|
|
39
40
|
.concat(addedElementsWithIssues
|
|
40
41
|
.filter(addedElementWithIssues => addedElementWithIssues.element.isConnected)
|
|
@@ -62,9 +63,13 @@ export default function updateElementsWithIssues(extendedElementsWithIssues: Sig
|
|
|
62
63
|
return {
|
|
63
64
|
id,
|
|
64
65
|
element: addedElementWithIssues.element,
|
|
66
|
+
rootNode: addedElementWithIssues.rootNode,
|
|
65
67
|
visible: trigger.visible,
|
|
66
68
|
position: trigger.position,
|
|
67
69
|
scrollableAncestors: signal(scrollableAncestors),
|
|
70
|
+
anchorNameValue:
|
|
71
|
+
addedElementWithIssues.element.style.getPropertyValue('anchor-name')
|
|
72
|
+
|| win.getComputedStyle(addedElementWithIssues.element).getPropertyValue('anchor-name'),
|
|
68
73
|
trigger,
|
|
69
74
|
issues
|
|
70
75
|
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is-html-element.d.ts","sourceRoot":"","sources":["../../src/utils/is-html-element.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,WAAW,CAK9E"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export default function isHtmlElement(element) {
|
|
2
|
-
// We can't use instanceof because it may not work across contexts
|
|
3
|
-
// (such as when an element is moved from an iframe).
|
|
4
|
-
// This heuristic seems to be the most robust and fastest that I could think of.
|
|
5
|
-
return element.constructor.name.startsWith('HTML');
|
|
6
|
-
}
|
|
7
|
-
//# sourceMappingURL=is-html-element.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is-html-element.js","sourceRoot":"","sources":["../../src/utils/is-html-element.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,OAAgB;IACpD,kEAAkE;IAClE,qDAAqD;IACrD,gFAAgF;IAChF,OAAO,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export default function isHtmlElement(element: Element): element is HTMLElement {
|
|
2
|
-
// We can't use instanceof because it may not work across contexts
|
|
3
|
-
// (such as when an element is moved from an iframe).
|
|
4
|
-
// This heuristic seems to be the most robust and fastest that I could think of.
|
|
5
|
-
return element.constructor.name.startsWith('HTML');
|
|
6
|
-
}
|