accented 0.0.0-20250223121749 → 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 +60 -22
- package/dist/elements/accented-dialog.js.map +1 -1
- package/dist/elements/accented-trigger.d.ts +2 -0
- package/dist/elements/accented-trigger.d.ts.map +1 -1
- package/dist/elements/accented-trigger.js +64 -12
- 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 +21 -8
- 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 +53 -16
- 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 +60 -22
- package/src/elements/accented-trigger.ts +70 -12
- package/src/fullscreen-listener.ts +17 -0
- package/src/scanner.ts +17 -6
- package/src/state.ts +10 -2
- package/src/types.ts +23 -9
- 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 +54 -15
- 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 +46 -11
- package/src/utils/update-elements-with-issues.ts +10 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform-violations.js","sourceRoot":"","sources":["../../src/utils/transform-violations.ts"],"names":[],"mappings":"AAGA,SAAS,aAAa,CAAC,CAAc,EAAE,CAAc;IACnD,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACvE,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,UAAwC;
|
|
1
|
+
{"version":3,"file":"transform-violations.js","sourceRoot":"","sources":["../../src/utils/transform-violations.ts"],"names":[],"mappings":"AAGA,oFAAoF;AACpF,2FAA2F;AAC3F,MAAM,oCAAoC,GAAG;IAC3C,mBAAmB;IACnB,WAAW;IACX,iBAAiB;IACjB,6BAA6B;IAC7B,MAAM;IACN,oBAAoB;IACpB,6BAA6B,CAAC,oFAAoF;CACnH,CAAC;AAEF,SAAS,qBAAqB,CAAC,WAAmB,EAAE,OAAoB,EAAE,IAAY;IACpF,OAAO,oCAAoC,CAAC,QAAQ,CAAC,WAAW,CAAC;WAC5D,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,aAAa,CAAC,CAAc,EAAE,CAAc;IACnD,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACvE,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,UAAwC,EAAE,IAAY;IAChG,MAAM,kBAAkB,GAA6B,EAAE,CAAC;IAExD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACnC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;YAEjC,4EAA4E;YAC5E,8EAA8E;YAC9E,2CAA2C;YAC3C,mGAAmG;YACnG,yEAAyE;YACzE,sHAAsH;YACtH,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YAErC,IAAI,OAAO,IAAI,CAAC,UAAU,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;gBAClF,MAAM,KAAK,GAAU;oBACnB,EAAE,EAAE,SAAS,CAAC,EAAE;oBAChB,KAAK,EAAE,SAAS,CAAC,IAAI;oBACrB,WAAW,EAAE,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC,WAAW;oBACzD,GAAG,EAAE,SAAS,CAAC,OAAO;oBACtB,MAAM,EAAE,SAAS,CAAC,MAAM,IAAI,IAAI;iBACjC,CAAC;gBACF,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,SAAS,CAAC,iBAAiB,CAAC,EAAE,CAAC,iBAAiB,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;gBACtH,IAAI,oBAAoB,KAAK,CAAC,CAAC,EAAE,CAAC;oBAChC,kBAAkB,CAAC,IAAI,CAAC;wBACtB,OAAO;wBACP,QAAQ,EAAE,OAAO,CAAC,WAAW,EAAE;wBAC/B,MAAM,EAAE,CAAC,KAAK,CAAC;qBAChB,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,kBAAkB,CAAC,oBAAoB,CAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC/D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,MAAM,iBAAiB,IAAI,kBAAkB,EAAE,CAAC;QACnD,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACrC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,kBAAkB,CAAC;AAC5B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-elements-with-issues.d.ts","sourceRoot":"","sources":["../../src/utils/update-elements-with-issues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"update-elements-with-issues.d.ts","sourceRoot":"","sources":["../../src/utils/update-elements-with-issues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAY1D,MAAM,CAAC,OAAO,UAAU,wBAAwB,CAAC,0BAA0B,EAAE,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,UAAU,CAAC,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,OAAO,GAAG,CAAA;CAAE,EAAE,IAAI,EAAE,MAAM,QAgE/M"}
|
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
import { batch, signal } from '@preact/signals-core';
|
|
2
2
|
import transformViolations from './transform-violations.js';
|
|
3
|
+
import areElementsWithIssuesEqual from './are-elements-with-issues-equal.js';
|
|
3
4
|
import areIssueSetsEqual from './are-issue-sets-equal.js';
|
|
4
5
|
import getElementPosition from './get-element-position.js';
|
|
5
6
|
import getScrollableAncestors from './get-scrollable-ancestors.js';
|
|
6
7
|
import supportsAnchorPositioning from './supports-anchor-positioning.js';
|
|
7
8
|
let count = 0;
|
|
8
9
|
export default function updateElementsWithIssues(extendedElementsWithIssues, violations, win, name) {
|
|
9
|
-
const updatedElementsWithIssues = transformViolations(violations);
|
|
10
|
+
const updatedElementsWithIssues = transformViolations(violations, name);
|
|
10
11
|
batch(() => {
|
|
11
12
|
for (const updatedElementWithIssues of updatedElementsWithIssues) {
|
|
12
|
-
const existingElementIndex = extendedElementsWithIssues.value.findIndex(extendedElementWithIssues => extendedElementWithIssues
|
|
13
|
+
const existingElementIndex = extendedElementsWithIssues.value.findIndex(extendedElementWithIssues => areElementsWithIssuesEqual(extendedElementWithIssues, updatedElementWithIssues));
|
|
13
14
|
if (existingElementIndex > -1 && extendedElementsWithIssues.value[existingElementIndex] && !areIssueSetsEqual(extendedElementsWithIssues.value[existingElementIndex].issues.value, updatedElementWithIssues.issues)) {
|
|
14
15
|
extendedElementsWithIssues.value[existingElementIndex].issues.value = updatedElementWithIssues.issues;
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
const addedElementsWithIssues = updatedElementsWithIssues.filter(updatedElementWithIssues => {
|
|
18
|
-
return !extendedElementsWithIssues.value.some(extendedElementWithIssues => extendedElementWithIssues
|
|
19
|
+
return !extendedElementsWithIssues.value.some(extendedElementWithIssues => areElementsWithIssuesEqual(extendedElementWithIssues, updatedElementWithIssues));
|
|
19
20
|
});
|
|
20
21
|
const removedElementsWithIssues = extendedElementsWithIssues.value.filter(extendedElementWithIssues => {
|
|
21
|
-
return !updatedElementsWithIssues.some(updatedElementWithIssues => updatedElementWithIssues
|
|
22
|
+
return !updatedElementsWithIssues.some(updatedElementWithIssues => areElementsWithIssuesEqual(updatedElementWithIssues, extendedElementWithIssues));
|
|
22
23
|
});
|
|
23
24
|
if (addedElementsWithIssues.length > 0 || removedElementsWithIssues.length > 0) {
|
|
24
25
|
extendedElementsWithIssues.value = [...extendedElementsWithIssues.value]
|
|
25
26
|
.filter(extendedElementWithIssues => {
|
|
26
|
-
return !removedElementsWithIssues.some(removedElementWithIssues => removedElementWithIssues
|
|
27
|
+
return !removedElementsWithIssues.some(removedElementWithIssues => areElementsWithIssuesEqual(removedElementWithIssues, extendedElementWithIssues));
|
|
27
28
|
})
|
|
28
29
|
.concat(addedElementsWithIssues
|
|
29
30
|
.filter(addedElementWithIssues => addedElementWithIssues.element.isConnected)
|
|
@@ -51,9 +52,12 @@ export default function updateElementsWithIssues(extendedElementsWithIssues, vio
|
|
|
51
52
|
return {
|
|
52
53
|
id,
|
|
53
54
|
element: addedElementWithIssues.element,
|
|
55
|
+
rootNode: addedElementWithIssues.rootNode,
|
|
54
56
|
visible: trigger.visible,
|
|
55
57
|
position: trigger.position,
|
|
56
58
|
scrollableAncestors: signal(scrollableAncestors),
|
|
59
|
+
anchorNameValue: addedElementWithIssues.element.style.getPropertyValue('anchor-name')
|
|
60
|
+
|| win.getComputedStyle(addedElementWithIssues.element).getPropertyValue('anchor-name'),
|
|
57
61
|
trigger,
|
|
58
62
|
issues
|
|
59
63
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-elements-with-issues.js","sourceRoot":"","sources":["../../src/utils/update-elements-with-issues.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,mBAAmB,MAAM,2BAA2B,CAAC;AAC5D,OAAO,iBAAiB,MAAM,2BAA2B,CAAC;AAG1D,OAAO,kBAAkB,MAAM,2BAA2B,CAAC;AAC3D,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AACnE,OAAO,yBAAyB,MAAM,kCAAkC,CAAC;AAEzE,IAAI,KAAK,GAAG,CAAC,CAAC;AAEd,MAAM,CAAC,OAAO,UAAU,wBAAwB,CAAC,0BAAoE,EAAE,UAAwC,EAAE,GAAiC,EAAE,IAAY;IAC9M,MAAM,yBAAyB,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"update-elements-with-issues.js","sourceRoot":"","sources":["../../src/utils/update-elements-with-issues.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "accented",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-20250404114312",
|
|
4
4
|
"description": "Continuous accessibility testing and issue highlighting for web development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/accented.js",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
|
-
"src"
|
|
9
|
+
"src",
|
|
10
|
+
"NOTICE"
|
|
10
11
|
],
|
|
11
12
|
"repository": {
|
|
12
13
|
"type": "git",
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
"axe-core"
|
|
20
21
|
],
|
|
21
22
|
"author": "Pavel Pomerantsev",
|
|
22
|
-
"license": "MIT",
|
|
23
|
+
"license": "MIT AND MPL-2.0",
|
|
23
24
|
"bugs": {
|
|
24
25
|
"url": "https://github.com/pomerantsev/accented/issues"
|
|
25
26
|
},
|
package/src/accented.ts
CHANGED
|
@@ -5,6 +5,7 @@ import createLogger from './logger.js';
|
|
|
5
5
|
import createScanner from './scanner.js';
|
|
6
6
|
import setupScrollListeners from './scroll-listeners.js';
|
|
7
7
|
import setupResizeListener from './resize-listener.js';
|
|
8
|
+
import setupFullscreenListener from './fullscreen-listener.js';
|
|
8
9
|
import setupIntersectionObserver from './intersection-observer.js';
|
|
9
10
|
import { enabled, extendedElementsWithIssues } from './state.js';
|
|
10
11
|
import deepMerge from './utils/deep-merge.js';
|
|
@@ -34,9 +35,9 @@ export type { AccentedOptions, DisableAccented };
|
|
|
34
35
|
* wait: 500,
|
|
35
36
|
* leading: false
|
|
36
37
|
* },
|
|
37
|
-
* callback: ({ elementsWithIssues,
|
|
38
|
+
* callback: ({ elementsWithIssues, performance }) => {
|
|
38
39
|
* console.log('Elements with issues:', elementsWithIssues);
|
|
39
|
-
* console.log('
|
|
40
|
+
* console.log('Total blocking time:', performance.totalBlockingTime);
|
|
40
41
|
* }
|
|
41
42
|
* });
|
|
42
43
|
*/
|
|
@@ -95,6 +96,7 @@ export default function accented(options: AccentedOptions = {}): DisableAccented
|
|
|
95
96
|
const cleanupLogger = output.console ? createLogger() : () => {};
|
|
96
97
|
const cleanupScrollListeners = supportsAnchorPositioning(window) ? () => {} : setupScrollListeners();
|
|
97
98
|
const cleanupResizeListener = supportsAnchorPositioning(window) ? () => {} : setupResizeListener();
|
|
99
|
+
const cleanupFullscreenListener = supportsAnchorPositioning(window) ? () => {} : setupFullscreenListener();
|
|
98
100
|
|
|
99
101
|
return () => {
|
|
100
102
|
try {
|
|
@@ -105,6 +107,7 @@ export default function accented(options: AccentedOptions = {}): DisableAccented
|
|
|
105
107
|
cleanupLogger();
|
|
106
108
|
cleanupScrollListeners();
|
|
107
109
|
cleanupResizeListener();
|
|
110
|
+
cleanupFullscreenListener();
|
|
108
111
|
if (cleanupIntersectionObserver) {
|
|
109
112
|
cleanupIntersectionObserver();
|
|
110
113
|
}
|
package/src/constants.ts
CHANGED
package/src/dom-updater.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { effect } from '@preact/signals-core';
|
|
2
|
-
import { extendedElementsWithIssues } from './state.js';
|
|
2
|
+
import { extendedElementsWithIssues, rootNodes } from './state.js';
|
|
3
3
|
import type { ExtendedElementWithIssues } from './types';
|
|
4
|
+
import areElementsWithIssuesEqual from './utils/are-elements-with-issues-equal.js';
|
|
4
5
|
import supportsAnchorPositioning from './utils/supports-anchor-positioning.js';
|
|
6
|
+
import { isDocument, isDocumentFragment, isShadowRoot } from './utils/dom-helpers.js';
|
|
7
|
+
import getParent from './utils/get-parent.js';
|
|
5
8
|
|
|
6
9
|
export default function createDomUpdater(name: string, intersectionObserver?: IntersectionObserver) {
|
|
7
10
|
const attrName = `data-${name}`;
|
|
@@ -13,8 +16,8 @@ export default function createDomUpdater(name: string, intersectionObserver?: In
|
|
|
13
16
|
.filter(anchorName => anchorName.startsWith('--'));
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
function setAnchorName (
|
|
17
|
-
const anchorNameValue =
|
|
19
|
+
function setAnchorName (elementWithIssues: ExtendedElementWithIssues) {
|
|
20
|
+
const { element, id, anchorNameValue } = elementWithIssues;
|
|
18
21
|
const anchorNames = getAnchorNames(anchorNameValue);
|
|
19
22
|
if (anchorNames.length > 0) {
|
|
20
23
|
element.style.setProperty('anchor-name', `${anchorNameValue}, --${name}-anchor-${id}`);
|
|
@@ -23,14 +26,13 @@ export default function createDomUpdater(name: string, intersectionObserver?: In
|
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
function removeAnchorName (
|
|
27
|
-
const anchorNameValue =
|
|
29
|
+
function removeAnchorName (elementWithIssues: ExtendedElementWithIssues) {
|
|
30
|
+
const { element, anchorNameValue } = elementWithIssues;
|
|
28
31
|
const anchorNames = getAnchorNames(anchorNameValue);
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
if (anchorNames.length > 0) {
|
|
33
|
+
element.style.setProperty('anchor-name', anchorNames.join(', '));
|
|
34
|
+
} else {
|
|
31
35
|
element.style.removeProperty('anchor-name');
|
|
32
|
-
} else if (anchorNames.length > 1 && index > -1) {
|
|
33
|
-
element.style.setProperty('anchor-name', anchorNames.filter((_, i) => i !== index).join(', '));
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -38,10 +40,10 @@ export default function createDomUpdater(name: string, intersectionObserver?: In
|
|
|
38
40
|
for (const elementWithIssues of extendedElementsWithIssues) {
|
|
39
41
|
elementWithIssues.element.setAttribute(attrName, elementWithIssues.id.toString());
|
|
40
42
|
if (supportsAnchorPositioning(window)) {
|
|
41
|
-
setAnchorName(elementWithIssues
|
|
43
|
+
setAnchorName(elementWithIssues);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
if (elementWithIssues.element
|
|
46
|
+
if (getParent(elementWithIssues.element)) {
|
|
45
47
|
elementWithIssues.element.insertAdjacentElement('afterend', elementWithIssues.trigger);
|
|
46
48
|
} else {
|
|
47
49
|
elementWithIssues.element.insertAdjacentElement('beforeend', elementWithIssues.trigger);
|
|
@@ -56,7 +58,7 @@ export default function createDomUpdater(name: string, intersectionObserver?: In
|
|
|
56
58
|
for (const elementWithIssues of extendedElementsWithIssues) {
|
|
57
59
|
elementWithIssues.element.removeAttribute(attrName);
|
|
58
60
|
if (supportsAnchorPositioning(window)) {
|
|
59
|
-
removeAnchorName(elementWithIssues
|
|
61
|
+
removeAnchorName(elementWithIssues);
|
|
60
62
|
}
|
|
61
63
|
elementWithIssues.trigger.remove();
|
|
62
64
|
if (intersectionObserver) {
|
|
@@ -69,8 +71,10 @@ export default function createDomUpdater(name: string, intersectionObserver?: In
|
|
|
69
71
|
stylesheet.replaceSync(`
|
|
70
72
|
@layer ${name} {
|
|
71
73
|
:root {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
/* Ensure that the primary / secondary color combination meets WCAG 1.4.3 Contrast (Minimum) */
|
|
75
|
+
/* OKLCH stuff: https://oklch.com/ */
|
|
76
|
+
--${name}-primary-color: oklch(0.5 0.3 0);
|
|
77
|
+
--${name}-secondary-color: oklch(0.98 0 0);
|
|
74
78
|
--${name}-outline-width: 2px;
|
|
75
79
|
--${name}-outline-style: solid;
|
|
76
80
|
}
|
|
@@ -86,19 +90,31 @@ export default function createDomUpdater(name: string, intersectionObserver?: In
|
|
|
86
90
|
|
|
87
91
|
let previousExtendedElementsWithIssues: Array<ExtendedElementWithIssues> = [];
|
|
88
92
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
let previousRootNodes: Set<Node> = new Set();
|
|
94
|
+
|
|
95
|
+
const disposeOfStyleSheetsEffect = effect(() => {
|
|
96
|
+
const newRootNodes = rootNodes.value;
|
|
97
|
+
const addedRootNodes = [...newRootNodes].filter(rootNode => !previousRootNodes.has(rootNode));
|
|
98
|
+
const removedRootNodes = [...previousRootNodes].filter(rootNode => !newRootNodes.has(rootNode));
|
|
99
|
+
for (const rootNode of addedRootNodes) {
|
|
100
|
+
if (isDocument(rootNode) || (isDocumentFragment(rootNode) && isShadowRoot(rootNode))) {
|
|
101
|
+
rootNode.adoptedStyleSheets.push(stylesheet);
|
|
102
|
+
}
|
|
93
103
|
}
|
|
94
|
-
|
|
104
|
+
for (const rootNode of removedRootNodes) {
|
|
105
|
+
if (isDocument(rootNode) || (isDocumentFragment(rootNode) && isShadowRoot(rootNode))) {
|
|
106
|
+
rootNode.adoptedStyleSheets.splice(rootNode.adoptedStyleSheets.indexOf(stylesheet), 1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
previousRootNodes = newRootNodes;
|
|
110
|
+
});
|
|
95
111
|
|
|
96
112
|
const disposeOfElementsEffect = effect(() => {
|
|
97
113
|
const added = extendedElementsWithIssues.value.filter(elementWithIssues => {
|
|
98
|
-
return !previousExtendedElementsWithIssues.some(previousElementWithIssues => previousElementWithIssues
|
|
114
|
+
return !previousExtendedElementsWithIssues.some(previousElementWithIssues => areElementsWithIssuesEqual(previousElementWithIssues, elementWithIssues));
|
|
99
115
|
});
|
|
100
116
|
const removed = previousExtendedElementsWithIssues.filter(previousElementWithIssues => {
|
|
101
|
-
return !extendedElementsWithIssues.value.some(elementWithIssues => elementWithIssues
|
|
117
|
+
return !extendedElementsWithIssues.value.some(elementWithIssues => areElementsWithIssuesEqual(elementWithIssues, previousElementWithIssues));
|
|
102
118
|
});
|
|
103
119
|
removeIssues(removed);
|
|
104
120
|
setIssues(added);
|
|
@@ -106,7 +122,7 @@ export default function createDomUpdater(name: string, intersectionObserver?: In
|
|
|
106
122
|
});
|
|
107
123
|
|
|
108
124
|
return () => {
|
|
109
|
-
|
|
125
|
+
disposeOfStyleSheetsEffect();
|
|
110
126
|
disposeOfElementsEffect();
|
|
111
127
|
};
|
|
112
128
|
}
|
|
@@ -56,20 +56,45 @@ export default () => {
|
|
|
56
56
|
:host {
|
|
57
57
|
all: initial !important;
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
--
|
|
61
|
-
--
|
|
59
|
+
/* OKLCH stuff: https://oklch.com/ */
|
|
60
|
+
--light-color: oklch(0.98 0 0);
|
|
61
|
+
--dark-color: oklch(0.22 0 0);
|
|
62
|
+
|
|
63
|
+
--background-color: light-dark(var(--light-color), var(--dark-color));
|
|
64
|
+
--text-color: light-dark(var(--dark-color), var(--light-color));
|
|
65
|
+
|
|
66
|
+
--impact-lightness: 0.80;
|
|
67
|
+
--focus-lightness: 0.45;
|
|
68
|
+
@media (prefers-color-scheme: dark) {
|
|
69
|
+
--impact-lightness: 0.45;
|
|
70
|
+
--focus-lightness: 0.80;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
--blue-hue: 230;
|
|
74
|
+
--gold-hue: 90;
|
|
75
|
+
--red-hue: 0;
|
|
76
|
+
|
|
77
|
+
/* Contrasts with background. */
|
|
78
|
+
--focus-color: oklch(var(--focus-lightness) 0.25 var(--blue-hue));
|
|
79
|
+
|
|
80
|
+
--impact-chroma: 0.16;
|
|
62
81
|
|
|
63
|
-
--impact-
|
|
64
|
-
--impact-
|
|
65
|
-
--impact-
|
|
66
|
-
|
|
82
|
+
--impact-moderate-hue: var(--blue-hue);
|
|
83
|
+
--impact-serious-hue: var(--gold-hue);
|
|
84
|
+
--impact-critical-hue: var(--red-hue);
|
|
85
|
+
|
|
86
|
+
--impact-minor-color: oklch(var(--impact-lightness) 0 0);
|
|
87
|
+
--impact-moderate-color: oklch(var(--impact-lightness) var(--impact-chroma) var(--impact-moderate-hue));
|
|
88
|
+
--impact-serious-color: oklch(var(--impact-lightness) var(--impact-chroma) var(--impact-serious-hue));
|
|
89
|
+
--impact-critical-color: oklch(var(--impact-lightness) var(--impact-chroma) var(--impact-critical-hue));
|
|
90
|
+
|
|
91
|
+
--base-size: max(1rem, 16px);
|
|
67
92
|
|
|
68
93
|
/* Spacing and typography custom props, inspired by https://utopia.fyi (simplified). */
|
|
69
94
|
|
|
70
95
|
/* @link https://utopia.fyi/type/calculator?c=320,16,1.2,1240,16,1.2,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */
|
|
71
96
|
--ratio: 1.2;
|
|
72
|
-
--step-0:
|
|
97
|
+
--step-0: var(--base-size);
|
|
73
98
|
--step-1: calc(var(--step-0) * var(--ratio));
|
|
74
99
|
--step-2: calc(var(--step-1) * var(--ratio));
|
|
75
100
|
--step-3: calc(var(--step-2) * var(--ratio));
|
|
@@ -77,15 +102,15 @@ export default () => {
|
|
|
77
102
|
--step--1: calc(var(--step-0) / var(--ratio));
|
|
78
103
|
|
|
79
104
|
/* @link https://utopia.fyi/space/calculator?c=320,16,1.2,1240,16,1.2,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */
|
|
80
|
-
--space-3xs: 0.
|
|
81
|
-
--space-2xs: 0.
|
|
82
|
-
--space-xs: 0.
|
|
83
|
-
--space-s:
|
|
84
|
-
--space-m: 1.
|
|
85
|
-
--space-l:
|
|
86
|
-
--space-xl:
|
|
87
|
-
--space-2xl:
|
|
88
|
-
--space-3xl:
|
|
105
|
+
--space-3xs: calc(0.25 * var(--base-size));
|
|
106
|
+
--space-2xs: calc(0.5 * var(--base-size));
|
|
107
|
+
--space-xs: calc(0.75 * var(--base-size));
|
|
108
|
+
--space-s: var(--base-size);
|
|
109
|
+
--space-m: calc(1.5 * var(--base-size));
|
|
110
|
+
--space-l: calc(2 * var(--base-size));
|
|
111
|
+
--space-xl: calc(3 * var(--base-size));
|
|
112
|
+
--space-2xl: calc(4 * var(--base-size));
|
|
113
|
+
--space-3xl: calc(6 * var(--base-size));
|
|
89
114
|
}
|
|
90
115
|
|
|
91
116
|
a[href], button {
|
|
@@ -116,12 +141,15 @@ export default () => {
|
|
|
116
141
|
overflow-wrap: break-word;
|
|
117
142
|
font-family: system-ui;
|
|
118
143
|
line-height: 1.5;
|
|
119
|
-
|
|
120
|
-
color: var(--
|
|
144
|
+
text-wrap: pretty;
|
|
145
|
+
background-color: var(--background-color);
|
|
146
|
+
color: var(--text-color);
|
|
121
147
|
border: 2px solid currentColor;
|
|
122
148
|
padding: var(--space-l);
|
|
123
149
|
inline-size: min(90ch, calc(100% - var(--space-s)* 2));
|
|
124
150
|
max-block-size: calc(100% - var(--space-s) * 2);
|
|
151
|
+
|
|
152
|
+
color-scheme: light dark;
|
|
125
153
|
}
|
|
126
154
|
|
|
127
155
|
#button-container {
|
|
@@ -129,8 +157,8 @@ export default () => {
|
|
|
129
157
|
}
|
|
130
158
|
|
|
131
159
|
#close {
|
|
132
|
-
background-color: var(--
|
|
133
|
-
color: var(--
|
|
160
|
+
background-color: var(--background-color);
|
|
161
|
+
color: var(--text-color);
|
|
134
162
|
border: 2px solid currentColor;
|
|
135
163
|
padding-inline: var(--space-2xs);
|
|
136
164
|
aspect-ratio: 1 / 1;
|
|
@@ -167,7 +195,7 @@ export default () => {
|
|
|
167
195
|
}
|
|
168
196
|
|
|
169
197
|
a {
|
|
170
|
-
font-weight:
|
|
198
|
+
font-weight: 500;
|
|
171
199
|
}
|
|
172
200
|
}
|
|
173
201
|
|
|
@@ -260,6 +288,16 @@ export default () => {
|
|
|
260
288
|
}
|
|
261
289
|
}, { signal: this.#abortController.signal });
|
|
262
290
|
|
|
291
|
+
dialog?.addEventListener('keydown', (event) => {
|
|
292
|
+
try {
|
|
293
|
+
if (event.key === 'Escape') {
|
|
294
|
+
event.stopPropagation();
|
|
295
|
+
}
|
|
296
|
+
} catch (error) {
|
|
297
|
+
logAndRethrow(error);
|
|
298
|
+
}
|
|
299
|
+
}, { signal: this.#abortController.signal });
|
|
300
|
+
|
|
263
301
|
this.#disposeOfEffect = effect(() => {
|
|
264
302
|
if (this.issues) {
|
|
265
303
|
const issues = this.issues.value;
|
|
@@ -12,8 +12,6 @@ export interface AccentedTrigger extends HTMLElement {
|
|
|
12
12
|
visible: Signal<boolean> | undefined;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const triggerSize = 'max(32px, 2rem)';
|
|
16
|
-
|
|
17
15
|
// We want Accented to not throw an error in Node, and use static imports,
|
|
18
16
|
// so we can't export `class extends HTMLElement` because HTMLElement is not available in Node.
|
|
19
17
|
export default (name: string) => {
|
|
@@ -27,21 +25,37 @@ export default (name: string) => {
|
|
|
27
25
|
template.innerHTML = `
|
|
28
26
|
<style>
|
|
29
27
|
:host {
|
|
28
|
+
--ratio: 1.2;
|
|
29
|
+
--base-size: max(1rem, 16px);
|
|
30
30
|
position: fixed !important;
|
|
31
|
+
inset-inline-start: anchor(self-start) !important;
|
|
31
32
|
inset-inline-end: anchor(self-end) !important;
|
|
32
33
|
inset-block-start: anchor(self-start) !important;
|
|
34
|
+
inset-block-end: anchor(self-end) !important;
|
|
33
35
|
|
|
34
36
|
position-visibility: anchors-visible !important;
|
|
35
37
|
|
|
36
38
|
/* Revert potential effects of white-space: pre; set on a trigger's ancestor. */
|
|
37
39
|
white-space: normal !important;
|
|
40
|
+
|
|
41
|
+
pointer-events: none !important;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
#trigger {
|
|
45
|
+
pointer-events: auto;
|
|
46
|
+
|
|
47
|
+
position: absolute;
|
|
48
|
+
inset-block-start: 4px;
|
|
49
|
+
inset-inline-end: 4px;
|
|
50
|
+
|
|
41
51
|
box-sizing: border-box;
|
|
42
|
-
font-size:
|
|
43
|
-
inline-size:
|
|
44
|
-
block-size:
|
|
52
|
+
font-size: calc(var(--ratio) * var(--ratio) * var(--base-size));
|
|
53
|
+
inline-size: calc(2 * var(--base-size));
|
|
54
|
+
block-size: calc(2 * var(--base-size));
|
|
55
|
+
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
justify-content: center;
|
|
45
59
|
|
|
46
60
|
/* Make it look better in forced-colors mode. */
|
|
47
61
|
border: 2px solid transparent;
|
|
@@ -49,6 +63,10 @@ export default (name: string) => {
|
|
|
49
63
|
background-color: var(--${name}-primary-color);
|
|
50
64
|
color: var(--${name}-secondary-color);
|
|
51
65
|
|
|
66
|
+
padding: 0;
|
|
67
|
+
|
|
68
|
+
border-radius: calc(0.25 * var(--base-size));
|
|
69
|
+
|
|
52
70
|
outline-offset: -4px;
|
|
53
71
|
outline-color: currentColor;
|
|
54
72
|
outline-width: 2px;
|
|
@@ -63,7 +81,7 @@ export default (name: string) => {
|
|
|
63
81
|
}
|
|
64
82
|
}
|
|
65
83
|
</style>
|
|
66
|
-
<button id="trigger" lang="en"
|
|
84
|
+
<button id="trigger" lang="en">!</button>
|
|
67
85
|
`;
|
|
68
86
|
|
|
69
87
|
return class extends HTMLElement implements AccentedTrigger {
|
|
@@ -75,6 +93,8 @@ export default (name: string) => {
|
|
|
75
93
|
|
|
76
94
|
#disposeOfVisibilityEffect: (() => void) | undefined;
|
|
77
95
|
|
|
96
|
+
#elementMutationObserver: MutationObserver | undefined;
|
|
97
|
+
|
|
78
98
|
element: Element | undefined;
|
|
79
99
|
|
|
80
100
|
dialog: AccentedDialog | undefined;
|
|
@@ -104,11 +124,34 @@ export default (name: string) => {
|
|
|
104
124
|
if (trigger && this.element) {
|
|
105
125
|
trigger.ariaLabel = `Accessibility issues in ${this.element.nodeName.toLowerCase()}`;
|
|
106
126
|
}
|
|
127
|
+
|
|
128
|
+
this.#setTransform();
|
|
129
|
+
|
|
130
|
+
this.#elementMutationObserver = new MutationObserver(() => {
|
|
131
|
+
try {
|
|
132
|
+
this.#setTransform();
|
|
133
|
+
} catch (error) {
|
|
134
|
+
logAndRethrow(error);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (this.element) {
|
|
139
|
+
this.#elementMutationObserver.observe(this.element, {
|
|
140
|
+
attributes: true
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
107
144
|
this.#abortController = new AbortController();
|
|
108
145
|
trigger?.addEventListener('click', (event) => {
|
|
109
146
|
try {
|
|
147
|
+
// event.preventDefault() ensures that if the issue is within a link,
|
|
148
|
+
// the link's default behavior (following the URL) is prevented.
|
|
110
149
|
event.preventDefault();
|
|
111
150
|
|
|
151
|
+
// event.stopPropagation() ensures that if there's a click handler on the trigger's ancestor
|
|
152
|
+
// (a link, or a button, or anything else), it doesn't get triggered.
|
|
153
|
+
event.stopPropagation();
|
|
154
|
+
|
|
112
155
|
// We append the dialog when the button is clicked,
|
|
113
156
|
// and remove it from the DOM when the dialog is closed.
|
|
114
157
|
// This gives us a performance improvement since Axe
|
|
@@ -135,12 +178,10 @@ export default (name: string) => {
|
|
|
135
178
|
this.#disposeOfPositionEffect = effect(() => {
|
|
136
179
|
if (this.position && trigger) {
|
|
137
180
|
const position = this.position.value;
|
|
138
|
-
this.style.setProperty('top', `${position.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
this.style.setProperty('left', `${position.inlineEndLeft}px`, 'important');
|
|
143
|
-
}
|
|
181
|
+
this.style.setProperty('top', `${position.top}px`, 'important');
|
|
182
|
+
this.style.setProperty('left', `${position.left}px`, 'important');
|
|
183
|
+
this.style.setProperty('width', `${position.width}px`, 'important');
|
|
184
|
+
this.style.setProperty('height', `${position.height}px`, 'important');
|
|
144
185
|
}
|
|
145
186
|
});
|
|
146
187
|
|
|
@@ -171,9 +212,26 @@ export default (name: string) => {
|
|
|
171
212
|
this.#disposeOfVisibilityEffect();
|
|
172
213
|
this.#disposeOfVisibilityEffect = undefined;
|
|
173
214
|
}
|
|
215
|
+
if (this.#elementMutationObserver) {
|
|
216
|
+
this.#elementMutationObserver.disconnect();
|
|
217
|
+
}
|
|
174
218
|
} catch (error) {
|
|
175
219
|
logAndRethrow(error);
|
|
176
220
|
}
|
|
177
221
|
}
|
|
222
|
+
|
|
223
|
+
#setTransform() {
|
|
224
|
+
// We read and write values in separate animation frames to avoid layout thrashing.
|
|
225
|
+
window.requestAnimationFrame(() => {
|
|
226
|
+
if (this.element) {
|
|
227
|
+
const transform = window.getComputedStyle(this.element).getPropertyValue('transform');
|
|
228
|
+
if (transform !== 'none') {
|
|
229
|
+
window.requestAnimationFrame(() => {
|
|
230
|
+
this.style.setProperty('transform', transform, 'important');
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
178
236
|
};
|
|
179
237
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import logAndRethrow from './log-and-rethrow.js';
|
|
2
|
+
import recalculatePositions from './utils/recalculate-positions.js';
|
|
3
|
+
|
|
4
|
+
export default function setupResizeListener() {
|
|
5
|
+
const abortController = new AbortController();
|
|
6
|
+
window.addEventListener('fullscreenchange', () => {
|
|
7
|
+
try {
|
|
8
|
+
recalculatePositions();
|
|
9
|
+
} catch (error) {
|
|
10
|
+
logAndRethrow(error);
|
|
11
|
+
}
|
|
12
|
+
}, { signal: abortController.signal });
|
|
13
|
+
|
|
14
|
+
return () => {
|
|
15
|
+
abortController.abort();
|
|
16
|
+
};
|
|
17
|
+
};
|
package/src/scanner.ts
CHANGED
|
@@ -6,8 +6,9 @@ import updateElementsWithIssues from './utils/update-elements-with-issues.js';
|
|
|
6
6
|
import recalculatePositions from './utils/recalculate-positions.js';
|
|
7
7
|
import recalculateScrollableAncestors from './utils/recalculate-scrollable-ancestors.js';
|
|
8
8
|
import supportsAnchorPositioning from './utils/supports-anchor-positioning.js';
|
|
9
|
-
import { issuesUrl } from './constants.js';
|
|
9
|
+
import { getAccentedElementNames, issuesUrl } from './constants.js';
|
|
10
10
|
import logAndRethrow from './log-and-rethrow.js';
|
|
11
|
+
import createShadowDOMAwareMutationObserver from './utils/shadow-dom-aware-mutation-observer.js';
|
|
11
12
|
|
|
12
13
|
export default function createScanner(name: string, axeContext: AxeContext, axeOptions: AxeOptions, throttle: Required<Throttle>, callback: Callback) {
|
|
13
14
|
const axeRunningWindowProp = `__${name}_axe_running__`;
|
|
@@ -22,7 +23,7 @@ export default function createScanner(name: string, axeContext: AxeContext, axeO
|
|
|
22
23
|
|
|
23
24
|
try {
|
|
24
25
|
|
|
25
|
-
performance.mark('
|
|
26
|
+
performance.mark('scan-start');
|
|
26
27
|
|
|
27
28
|
win[axeRunningWindowProp] = true;
|
|
28
29
|
|
|
@@ -54,17 +55,27 @@ export default function createScanner(name: string, axeContext: AxeContext, axeO
|
|
|
54
55
|
}
|
|
55
56
|
win[axeRunningWindowProp] = false;
|
|
56
57
|
|
|
57
|
-
const
|
|
58
|
+
const scanMeasure = performance.measure('scan', 'scan-start');
|
|
59
|
+
const scanDuration = Math.round(scanMeasure.duration);
|
|
58
60
|
|
|
59
61
|
if (!enabled.value) {
|
|
60
62
|
return;
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
performance.mark('dom-update-start');
|
|
66
|
+
|
|
63
67
|
updateElementsWithIssues(extendedElementsWithIssues, result.violations, window, name);
|
|
64
68
|
|
|
69
|
+
const domUpdateMeasure = performance.measure('dom-update', 'dom-update-start');
|
|
70
|
+
const domUpdateDuration = Math.round(domUpdateMeasure.duration);
|
|
71
|
+
|
|
65
72
|
callback({
|
|
66
73
|
elementsWithIssues: elementsWithIssues.value,
|
|
67
|
-
|
|
74
|
+
performance: {
|
|
75
|
+
totalBlockingTime: scanDuration + domUpdateDuration,
|
|
76
|
+
scan: scanDuration,
|
|
77
|
+
domUpdate: domUpdateDuration
|
|
78
|
+
}
|
|
68
79
|
});
|
|
69
80
|
} catch (error) {
|
|
70
81
|
win[axeRunningWindowProp] = false;
|
|
@@ -77,8 +88,8 @@ export default function createScanner(name: string, axeContext: AxeContext, axeO
|
|
|
77
88
|
// if that's an element or array of elements (not a selector).
|
|
78
89
|
taskQueue.add(document);
|
|
79
90
|
|
|
80
|
-
const accentedElementNames =
|
|
81
|
-
const mutationObserver =
|
|
91
|
+
const accentedElementNames = getAccentedElementNames(name);
|
|
92
|
+
const mutationObserver = createShadowDOMAwareMutationObserver(name, mutationList => {
|
|
82
93
|
try {
|
|
83
94
|
// We're not interested in mutations that are caused exclusively by the custom elements
|
|
84
95
|
// introduced by Accented.
|