accented 0.0.0-20250404114312 → 0.0.0-20250424114613
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/README.md +3 -1
- package/dist/accented.d.ts.map +1 -1
- package/dist/accented.js +5 -3
- package/dist/accented.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/dom-updater.d.ts.map +1 -1
- package/dist/dom-updater.js +29 -3
- package/dist/dom-updater.js.map +1 -1
- package/dist/elements/accented-dialog.d.ts +11 -7
- package/dist/elements/accented-dialog.d.ts.map +1 -1
- package/dist/elements/accented-dialog.js +35 -64
- package/dist/elements/accented-dialog.js.map +1 -1
- package/dist/elements/accented-trigger.d.ts +9 -5
- package/dist/elements/accented-trigger.d.ts.map +1 -1
- package/dist/elements/accented-trigger.js +6 -5
- package/dist/elements/accented-trigger.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +4 -1
- package/dist/logger.js.map +1 -1
- package/dist/scanner.d.ts +2 -2
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +19 -14
- package/dist/scanner.js.map +1 -1
- package/dist/task-queue.d.ts +2 -2
- package/dist/task-queue.d.ts.map +1 -1
- package/dist/task-queue.js +2 -1
- package/dist/task-queue.js.map +1 -1
- package/dist/types.d.ts +25 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/containing-blocks.d.ts +3 -0
- package/dist/utils/containing-blocks.d.ts.map +1 -0
- package/dist/utils/containing-blocks.js +46 -0
- package/dist/utils/containing-blocks.js.map +1 -0
- package/dist/utils/contains.d.ts +2 -0
- package/dist/utils/contains.d.ts.map +1 -0
- package/dist/utils/contains.js +19 -0
- package/dist/utils/contains.js.map +1 -0
- package/dist/utils/deduplicate-nodes.d.ts +2 -0
- package/dist/utils/deduplicate-nodes.d.ts.map +1 -0
- package/dist/utils/deduplicate-nodes.js +5 -0
- package/dist/utils/deduplicate-nodes.js.map +1 -0
- package/dist/utils/dom-helpers.d.ts +3 -0
- package/dist/utils/dom-helpers.d.ts.map +1 -1
- package/dist/utils/dom-helpers.js +13 -0
- package/dist/utils/dom-helpers.js.map +1 -1
- package/dist/utils/ensure-non-empty.d.ts +2 -0
- package/dist/utils/ensure-non-empty.d.ts.map +1 -0
- package/dist/utils/ensure-non-empty.js +7 -0
- package/dist/utils/ensure-non-empty.js.map +1 -0
- package/dist/utils/get-element-position.d.ts +8 -0
- package/dist/utils/get-element-position.d.ts.map +1 -1
- package/dist/utils/get-element-position.js +22 -7
- package/dist/utils/get-element-position.js.map +1 -1
- package/dist/utils/get-scan-context.d.ts +3 -0
- package/dist/utils/get-scan-context.d.ts.map +1 -0
- package/dist/utils/get-scan-context.js +28 -0
- package/dist/utils/get-scan-context.js.map +1 -0
- package/dist/utils/is-node-in-scan-context.d.ts +3 -0
- package/dist/utils/is-node-in-scan-context.d.ts.map +1 -0
- package/dist/utils/is-node-in-scan-context.js +26 -0
- package/dist/utils/is-node-in-scan-context.js.map +1 -0
- package/dist/utils/normalize-context.d.ts +3 -0
- package/dist/utils/normalize-context.d.ts.map +1 -0
- package/dist/utils/normalize-context.js +57 -0
- package/dist/utils/normalize-context.js.map +1 -0
- package/dist/utils/shadow-dom-aware-mutation-observer.d.ts.map +1 -1
- package/dist/utils/update-elements-with-issues.d.ts +10 -4
- package/dist/utils/update-elements-with-issues.d.ts.map +1 -1
- package/dist/utils/update-elements-with-issues.js +25 -2
- package/dist/utils/update-elements-with-issues.js.map +1 -1
- package/dist/validate-options.d.ts.map +1 -1
- package/dist/validate-options.js +86 -0
- package/dist/validate-options.js.map +1 -1
- package/package.json +7 -3
- package/src/accented.ts +5 -3
- package/src/dom-updater.ts +33 -3
- package/src/elements/accented-dialog.ts +38 -68
- package/src/elements/accented-trigger.ts +6 -5
- package/src/logger.ts +9 -1
- package/src/scanner.ts +21 -15
- package/src/task-queue.ts +6 -4
- package/src/types.ts +38 -5
- package/src/utils/containing-blocks.ts +57 -0
- package/src/utils/contains.test.ts +55 -0
- package/src/utils/contains.ts +19 -0
- package/src/utils/deduplicate-nodes.ts +3 -0
- package/src/utils/dom-helpers.ts +16 -0
- package/src/utils/ensure-non-empty.ts +6 -0
- package/src/utils/get-element-position.ts +23 -7
- package/src/utils/get-scan-context.test.ts +79 -0
- package/src/utils/get-scan-context.ts +39 -0
- package/src/utils/is-node-in-scan-context.test.ts +70 -0
- package/src/utils/is-node-in-scan-context.ts +29 -0
- package/src/utils/normalize-context.test.ts +105 -0
- package/src/utils/normalize-context.ts +58 -0
- package/src/utils/update-elements-with-issues.test.ts +61 -8
- package/src/utils/update-elements-with-issues.ts +42 -3
- package/src/validate-options.ts +88 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isNode, isNodeList } from './dom-helpers.js';
|
|
2
|
+
import { deduplicateNodes } from './deduplicate-nodes.js';
|
|
3
|
+
function recursiveSelectAll(selectors, root) {
|
|
4
|
+
const nodesOnCurrentLevel = root.querySelectorAll(selectors[0]);
|
|
5
|
+
if (selectors.length === 1) {
|
|
6
|
+
return Array.from(nodesOnCurrentLevel);
|
|
7
|
+
}
|
|
8
|
+
const restSelectors = selectors.slice(1);
|
|
9
|
+
const selected = [];
|
|
10
|
+
for (const node of nodesOnCurrentLevel) {
|
|
11
|
+
if (node.shadowRoot) {
|
|
12
|
+
selected.push(...recursiveSelectAll(restSelectors, node.shadowRoot));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return selected;
|
|
16
|
+
}
|
|
17
|
+
function selectorToNodes(selector) {
|
|
18
|
+
if (typeof selector === 'string') {
|
|
19
|
+
return recursiveSelectAll([selector], document);
|
|
20
|
+
}
|
|
21
|
+
else if (isNode(selector)) {
|
|
22
|
+
return [selector];
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return recursiveSelectAll(selector.fromShadowDom, document);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function contextPropToNodes(contextProp) {
|
|
29
|
+
let nodes = [];
|
|
30
|
+
if (typeof contextProp === 'object' && (Array.isArray(contextProp) || isNodeList(contextProp))) {
|
|
31
|
+
nodes = Array.from(contextProp).map(item => selectorToNodes(item)).flat();
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
nodes = selectorToNodes(contextProp);
|
|
35
|
+
}
|
|
36
|
+
return deduplicateNodes(nodes);
|
|
37
|
+
}
|
|
38
|
+
export default function normalizeContext(context) {
|
|
39
|
+
let contextInclude = [];
|
|
40
|
+
let contextExclude = [];
|
|
41
|
+
if (typeof context === 'object' && ('include' in context || 'exclude' in context)) {
|
|
42
|
+
if (context.include !== undefined) {
|
|
43
|
+
contextInclude = contextPropToNodes(context.include);
|
|
44
|
+
}
|
|
45
|
+
if (context.exclude !== undefined) {
|
|
46
|
+
contextExclude = contextPropToNodes(context.exclude);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
contextInclude = contextPropToNodes(context);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
include: contextInclude,
|
|
54
|
+
exclude: contextExclude
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=normalize-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize-context.js","sourceRoot":"","sources":["../../src/utils/normalize-context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,SAAS,kBAAkB,CAAC,SAAwB,EAAE,IAA2B;IAC/E,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAC;IACjE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,aAAa,GAAkB,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,EAAE,CAAC;IACpB,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,QAAQ,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,aAAa,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,eAAe,CAAC,QAAkB;IACzC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,kBAAkB,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClD,CAAC;SAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpB,CAAC;SAAM,CAAC;QACN,OAAO,kBAAkB,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,WAAwB;IAClD,IAAI,KAAK,GAAgB,EAAE,CAAC;IAC5B,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;QAC/F,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5E,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,OAAgB;IACvD,IAAI,cAAc,GAAgB,EAAE,CAAC;IACrC,IAAI,cAAc,GAAgB,EAAE,CAAC;IACrC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,SAAS,IAAI,OAAO,IAAI,SAAS,IAAI,OAAO,CAAC,EAAE,CAAC;QAClF,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAClC,cAAc,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAClC,cAAc,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;SAAM,CAAC;QACN,cAAc,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO;QACL,OAAO,EAAE,cAAc;QACvB,OAAO,EAAE,cAAc;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadow-dom-aware-mutation-observer.d.ts","sourceRoot":"","sources":["../../src/utils/shadow-dom-aware-mutation-observer.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,oCAAoC,CAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB;;qBAIxF,oBAAoB,GAAG,SAAS;oBA8BjB,IAAI,YAAY,oBAAoB,GAAG,IAAI;kBAQ7C,IAAI;
|
|
1
|
+
{"version":3,"file":"shadow-dom-aware-mutation-observer.d.ts","sourceRoot":"","sources":["../../src/utils/shadow-dom-aware-mutation-observer.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,oCAAoC,CAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB;;qBAIxF,oBAAoB,GAAG,SAAS;oBA8BjB,IAAI,YAAY,oBAAoB,GAAG,IAAI;kBAQ7C,IAAI;iCAKJ,UAAU,KAAK,CAAC,OAAO,GAAG,QAAQ,GAAG,gBAAgB,CAAC;gCAavD,UAAU,KAAK,CAAC,OAAO,GAAG,QAAQ,GAAG,gBAAgB,CAAC;;EAc/E"}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { AxeResults } from 'axe-core';
|
|
2
2
|
import type { Signal } from '@preact/signals-core';
|
|
3
|
-
import type { ExtendedElementWithIssues } from '../types';
|
|
4
|
-
export default function updateElementsWithIssues(extendedElementsWithIssues
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import type { ExtendedElementWithIssues, ScanContext } from '../types';
|
|
4
|
+
export default function updateElementsWithIssues({ extendedElementsWithIssues, scanContext, violations, win, name }: {
|
|
5
|
+
extendedElementsWithIssues: Signal<Array<ExtendedElementWithIssues>>;
|
|
6
|
+
scanContext: ScanContext;
|
|
7
|
+
violations: typeof AxeResults.violations;
|
|
8
|
+
win: Window & {
|
|
9
|
+
CSS: typeof CSS;
|
|
10
|
+
};
|
|
11
|
+
name: string;
|
|
12
|
+
}): void;
|
|
7
13
|
//# sourceMappingURL=update-elements-with-issues.d.ts.map
|
|
@@ -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,WAAW,EAAE,MAAM,UAAU,CAAC;AAgCvE,MAAM,CAAC,OAAO,UAAU,wBAAwB,CAAC,EAC/C,0BAA0B,EAC1B,WAAW,EACX,UAAU,EACV,GAAG,EACH,IAAI,EACL,EAAE;IACD,0BAA0B,EAAE,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACrE,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,OAAO,UAAU,CAAC,UAAU,CAAC;IACzC,GAAG,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,OAAO,GAAG,CAAA;KAAE,CAAC;IAClC,IAAI,EAAE,MAAM,CAAA;CACb,QAuEA"}
|
|
@@ -2,11 +2,27 @@ import { batch, signal } from '@preact/signals-core';
|
|
|
2
2
|
import transformViolations from './transform-violations.js';
|
|
3
3
|
import areElementsWithIssuesEqual from './are-elements-with-issues-equal.js';
|
|
4
4
|
import areIssueSetsEqual from './are-issue-sets-equal.js';
|
|
5
|
+
import isNodeInScanContext from './is-node-in-scan-context.js';
|
|
5
6
|
import getElementPosition from './get-element-position.js';
|
|
6
7
|
import getScrollableAncestors from './get-scrollable-ancestors.js';
|
|
7
8
|
import supportsAnchorPositioning from './supports-anchor-positioning.js';
|
|
9
|
+
import { isSvgElement } from './dom-helpers.js';
|
|
10
|
+
import getParent from './get-parent.js';
|
|
11
|
+
function shouldSkipRender(element) {
|
|
12
|
+
// Skip rendering if the element is inside an SVG:
|
|
13
|
+
// https://github.com/pomerantsev/accented/issues/62
|
|
14
|
+
const parent = getParent(element);
|
|
15
|
+
const isInsideSvg = Boolean(parent && isSvgElement(parent));
|
|
16
|
+
// Some issues, such as meta-viewport, are on <head> descendants,
|
|
17
|
+
// but since <head> is never rendered, we don't want to output anything
|
|
18
|
+
// for those in the DOM.
|
|
19
|
+
// We're not anticipating the use of shadow DOM in <head>,
|
|
20
|
+
// so the use of .closest() should be fine.
|
|
21
|
+
const isInsideHead = element.closest('head') !== null;
|
|
22
|
+
return isInsideSvg || isInsideHead;
|
|
23
|
+
}
|
|
8
24
|
let count = 0;
|
|
9
|
-
export default function updateElementsWithIssues(extendedElementsWithIssues, violations, win, name) {
|
|
25
|
+
export default function updateElementsWithIssues({ extendedElementsWithIssues, scanContext, violations, win, name }) {
|
|
10
26
|
const updatedElementsWithIssues = transformViolations(violations, name);
|
|
11
27
|
batch(() => {
|
|
12
28
|
for (const updatedElementWithIssues of updatedElementsWithIssues) {
|
|
@@ -18,8 +34,14 @@ export default function updateElementsWithIssues(extendedElementsWithIssues, vio
|
|
|
18
34
|
const addedElementsWithIssues = updatedElementsWithIssues.filter(updatedElementWithIssues => {
|
|
19
35
|
return !extendedElementsWithIssues.value.some(extendedElementWithIssues => areElementsWithIssuesEqual(extendedElementWithIssues, updatedElementWithIssues));
|
|
20
36
|
});
|
|
37
|
+
// Only consider an element to be removed in two cases:
|
|
38
|
+
// 1. It has been removed from the DOM.
|
|
39
|
+
// 2. It is within the scan context, but not among updatedElementsWithIssues.
|
|
21
40
|
const removedElementsWithIssues = extendedElementsWithIssues.value.filter(extendedElementWithIssues => {
|
|
22
|
-
|
|
41
|
+
const isConnected = extendedElementWithIssues.element.isConnected;
|
|
42
|
+
const hasNoMoreIssues = isNodeInScanContext(extendedElementWithIssues.element, scanContext)
|
|
43
|
+
&& !updatedElementsWithIssues.some(updatedElementWithIssues => areElementsWithIssuesEqual(updatedElementWithIssues, extendedElementWithIssues));
|
|
44
|
+
return !isConnected || hasNoMoreIssues;
|
|
23
45
|
});
|
|
24
46
|
if (addedElementsWithIssues.length > 0 || removedElementsWithIssues.length > 0) {
|
|
25
47
|
extendedElementsWithIssues.value = [...extendedElementsWithIssues.value]
|
|
@@ -52,6 +74,7 @@ export default function updateElementsWithIssues(extendedElementsWithIssues, vio
|
|
|
52
74
|
return {
|
|
53
75
|
id,
|
|
54
76
|
element: addedElementWithIssues.element,
|
|
77
|
+
skipRender: shouldSkipRender(addedElementWithIssues.element),
|
|
55
78
|
rootNode: addedElementWithIssues.rootNode,
|
|
56
79
|
visible: trigger.visible,
|
|
57
80
|
position: trigger.position,
|
|
@@ -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,0BAA0B,MAAM,qCAAqC,CAAC;AAC7E,OAAO,iBAAiB,MAAM,2BAA2B,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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-options.d.ts","sourceRoot":"","sources":["../src/validate-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"validate-options.d.ts","sourceRoot":"","sources":["../src/validate-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsD,eAAe,EAAW,MAAM,SAAS,CAAC;AA4F5G,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,OAAO,EAAE,eAAe,QAsC/D"}
|
package/dist/validate-options.js
CHANGED
|
@@ -1,4 +1,87 @@
|
|
|
1
1
|
import { allowedAxeOptions } from './types.js';
|
|
2
|
+
import { isNode, isNodeList } from './utils/dom-helpers.js';
|
|
3
|
+
function isSelector(contextFragment) {
|
|
4
|
+
return typeof contextFragment === 'string'
|
|
5
|
+
|| isNode(contextFragment)
|
|
6
|
+
|| 'fromShadowDom' in contextFragment;
|
|
7
|
+
}
|
|
8
|
+
function validateSelector(selector) {
|
|
9
|
+
if (typeof selector === 'string') {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
else if (isNode(selector)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
else if ('fromShadowDom' in selector) {
|
|
16
|
+
if (!Array.isArray(selector.fromShadowDom)
|
|
17
|
+
|| selector.fromShadowDom.length < 2 ||
|
|
18
|
+
!selector.fromShadowDom.every(item => typeof item === 'string')) {
|
|
19
|
+
throw new TypeError(`Accented: invalid argument. \`fromShadowDom\` must be an array of strings with at least 2 elements. It’s currently set to ${selector.fromShadowDom}.`);
|
|
20
|
+
}
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
const neverSelector = selector;
|
|
25
|
+
throw new TypeError(`Accented: invalid argument. The selector must be one of: string, Node, or an object with a \`fromShadowDom\` property. It’s currently set to ${neverSelector}.`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isSelectorList(contextFragment) {
|
|
29
|
+
return (typeof contextFragment === 'object' && isNodeList(contextFragment))
|
|
30
|
+
|| (Array.isArray(contextFragment) && contextFragment.every(item => isSelector(item)));
|
|
31
|
+
}
|
|
32
|
+
function validateSelectorList(selectorList) {
|
|
33
|
+
if (isNodeList(selectorList)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
else if (Array.isArray(selectorList)) {
|
|
37
|
+
for (const selector of selectorList) {
|
|
38
|
+
validateSelector(selector);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const neverSelectorList = selectorList;
|
|
43
|
+
throw new TypeError(`Accented: invalid argument. The selector list must either be a NodeList or an array. It’s currently set to ${neverSelectorList}.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function isContextProp(contextFragment) {
|
|
47
|
+
return isSelector(contextFragment) || isSelectorList(contextFragment);
|
|
48
|
+
}
|
|
49
|
+
function validateContextProp(context) {
|
|
50
|
+
if (isSelector(context)) {
|
|
51
|
+
validateSelector(context);
|
|
52
|
+
}
|
|
53
|
+
else if (isSelectorList(context)) {
|
|
54
|
+
validateSelectorList(context);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const neverContext = context;
|
|
58
|
+
throw new TypeError(`Accented: invalid argument. The context property must either be a selector or a selector list. It’s currently set to ${neverContext}.`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function isContextObject(contextFragment) {
|
|
62
|
+
return typeof contextFragment === 'object' && contextFragment !== null
|
|
63
|
+
&& ('include' in contextFragment || 'exclude' in contextFragment);
|
|
64
|
+
}
|
|
65
|
+
function validateContextObject(contextObject) {
|
|
66
|
+
if ('include' in contextObject) {
|
|
67
|
+
validateContextProp(contextObject.include);
|
|
68
|
+
}
|
|
69
|
+
if ('exclude' in contextObject) {
|
|
70
|
+
validateContextProp(contextObject.exclude);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function validateContext(context) {
|
|
74
|
+
if (isContextProp(context)) {
|
|
75
|
+
validateContextProp(context);
|
|
76
|
+
}
|
|
77
|
+
else if (isContextObject(context)) {
|
|
78
|
+
validateContextObject(context);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const neverContext = context;
|
|
82
|
+
throw new TypeError(`Accented: invalid context argument. It’s currently set to ${neverContext}.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
2
85
|
// The space of valid CSS and HTML names is wider than this,
|
|
3
86
|
// but with Unicode it gets complicated quickly, so I'm sticking to only allowing
|
|
4
87
|
// lowercase alphanumeric names that possibly contain dashes that start with a letter.
|
|
@@ -38,5 +121,8 @@ export default function validateOptions(options) {
|
|
|
38
121
|
throw new TypeError(`Accented: invalid argument. \`axeOptions\` contains the following unsupported keys: ${unsupportedKeys.join(', ')}. Valid options are: ${allowedAxeOptions.join(', ')}.`);
|
|
39
122
|
}
|
|
40
123
|
}
|
|
124
|
+
if (options.context !== undefined) {
|
|
125
|
+
validateContext(options.context);
|
|
126
|
+
}
|
|
41
127
|
}
|
|
42
128
|
//# sourceMappingURL=validate-options.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-options.js","sourceRoot":"","sources":["../src/validate-options.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"validate-options.js","sourceRoot":"","sources":["../src/validate-options.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "accented",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-20250424114613",
|
|
4
4
|
"description": "Continuous accessibility testing and issue highlighting for web development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/accented.js",
|
|
@@ -20,14 +20,18 @@
|
|
|
20
20
|
"axe-core"
|
|
21
21
|
],
|
|
22
22
|
"author": "Pavel Pomerantsev",
|
|
23
|
-
"license": "MIT
|
|
23
|
+
"license": "MIT",
|
|
24
24
|
"bugs": {
|
|
25
25
|
"url": "https://github.com/pomerantsev/accented/issues"
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://github.com/pomerantsev/accented#readme",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@preact/signals-core": "^1.8.0",
|
|
30
|
-
"axe-core": "^4.10.
|
|
30
|
+
"axe-core": "^4.10.3"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/jsdom": "^21.1.7",
|
|
34
|
+
"jsdom": "^26.0.0"
|
|
31
35
|
},
|
|
32
36
|
"scripts": {
|
|
33
37
|
"build": "tsc",
|
package/src/accented.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { AccentedOptions, DisableAccented } from './types';
|
|
|
13
13
|
import validateOptions from './validate-options.js';
|
|
14
14
|
import supportsAnchorPositioning from './utils/supports-anchor-positioning.js';
|
|
15
15
|
import logAndRethrow from './log-and-rethrow.js';
|
|
16
|
+
import { initializeContainingBlockSupportSet } from './utils/containing-blocks.js';
|
|
16
17
|
|
|
17
18
|
export type { AccentedOptions, DisableAccented };
|
|
18
19
|
|
|
@@ -67,7 +68,7 @@ export default function accented(options: AccentedOptions = {}): DisableAccented
|
|
|
67
68
|
// * update examples in the accented() function JSDoc;
|
|
68
69
|
// * update examples in the Readme.
|
|
69
70
|
const defaultOptions: Required<AccentedOptions> = {
|
|
70
|
-
|
|
71
|
+
context: document,
|
|
71
72
|
axeOptions: {},
|
|
72
73
|
name: 'accented',
|
|
73
74
|
output: defaultOutput,
|
|
@@ -75,7 +76,7 @@ export default function accented(options: AccentedOptions = {}): DisableAccented
|
|
|
75
76
|
callback: () => {}
|
|
76
77
|
};
|
|
77
78
|
|
|
78
|
-
const {
|
|
79
|
+
const {context, axeOptions, name, output, throttle, callback} = deepMerge(defaultOptions, options);
|
|
79
80
|
|
|
80
81
|
if (enabled.value) {
|
|
81
82
|
// Add link to the recipes section of the docs (#56).
|
|
@@ -88,10 +89,11 @@ export default function accented(options: AccentedOptions = {}): DisableAccented
|
|
|
88
89
|
|
|
89
90
|
enabled.value = true;
|
|
90
91
|
|
|
92
|
+
initializeContainingBlockSupportSet();
|
|
91
93
|
registerElements(name);
|
|
92
94
|
|
|
93
95
|
const {disconnect: cleanupIntersectionObserver, intersectionObserver } = supportsAnchorPositioning(window) ? {} : setupIntersectionObserver();
|
|
94
|
-
const cleanupScanner = createScanner(name,
|
|
96
|
+
const cleanupScanner = createScanner(name, context, axeOptions, throttle, callback);
|
|
95
97
|
const cleanupDomUpdater = createDomUpdater(name, intersectionObserver);
|
|
96
98
|
const cleanupLogger = output.console ? createLogger() : () => {};
|
|
97
99
|
const cleanupScrollListeners = supportsAnchorPositioning(window) ? () => {} : setupScrollListeners();
|
package/src/dom-updater.ts
CHANGED
|
@@ -6,6 +6,30 @@ import supportsAnchorPositioning from './utils/supports-anchor-positioning.js';
|
|
|
6
6
|
import { isDocument, isDocumentFragment, isShadowRoot } from './utils/dom-helpers.js';
|
|
7
7
|
import getParent from './utils/get-parent.js';
|
|
8
8
|
|
|
9
|
+
const shouldInsertTriggerInsideElement = (element: Element): boolean => {
|
|
10
|
+
/**
|
|
11
|
+
* No parent means that the element is a root node,
|
|
12
|
+
* which cannot have siblings.
|
|
13
|
+
*/
|
|
14
|
+
const noParent = !getParent(element);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Table cells get a special treatment because if a sibling to a TH or TD is inserted,
|
|
18
|
+
* it alters the table layout, no matter how that sibling is positioned.
|
|
19
|
+
* We don't want tables to look broken, so we're inserting the trigger inside the table cell.
|
|
20
|
+
*/
|
|
21
|
+
const isTableCell = element.nodeName === 'TH' || element.nodeName === 'TD';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* We want to put the trigger inside the <summary> element,
|
|
25
|
+
* because otherwise it will be hidden by the browser when the <details> element is collapsed
|
|
26
|
+
* (since none of the siblings of <summary> are visible then).
|
|
27
|
+
*/
|
|
28
|
+
const isSummary = element.nodeName === 'SUMMARY';
|
|
29
|
+
|
|
30
|
+
return noParent || isTableCell || isSummary;
|
|
31
|
+
};
|
|
32
|
+
|
|
9
33
|
export default function createDomUpdater(name: string, intersectionObserver?: IntersectionObserver) {
|
|
10
34
|
const attrName = `data-${name}`;
|
|
11
35
|
|
|
@@ -38,15 +62,18 @@ export default function createDomUpdater(name: string, intersectionObserver?: In
|
|
|
38
62
|
|
|
39
63
|
function setIssues (extendedElementsWithIssues: Array<ExtendedElementWithIssues>) {
|
|
40
64
|
for (const elementWithIssues of extendedElementsWithIssues) {
|
|
65
|
+
if (elementWithIssues.skipRender) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
41
68
|
elementWithIssues.element.setAttribute(attrName, elementWithIssues.id.toString());
|
|
42
69
|
if (supportsAnchorPositioning(window)) {
|
|
43
70
|
setAnchorName(elementWithIssues);
|
|
44
71
|
}
|
|
45
72
|
|
|
46
|
-
if (
|
|
47
|
-
elementWithIssues.element.insertAdjacentElement('afterend', elementWithIssues.trigger);
|
|
48
|
-
} else {
|
|
73
|
+
if (shouldInsertTriggerInsideElement(elementWithIssues.element)) {
|
|
49
74
|
elementWithIssues.element.insertAdjacentElement('beforeend', elementWithIssues.trigger);
|
|
75
|
+
} else {
|
|
76
|
+
elementWithIssues.element.insertAdjacentElement('afterend', elementWithIssues.trigger);
|
|
50
77
|
}
|
|
51
78
|
if (intersectionObserver) {
|
|
52
79
|
intersectionObserver.observe(elementWithIssues.element);
|
|
@@ -56,6 +83,9 @@ export default function createDomUpdater(name: string, intersectionObserver?: In
|
|
|
56
83
|
|
|
57
84
|
function removeIssues (extendedElementsWithIssues: Array<ExtendedElementWithIssues>) {
|
|
58
85
|
for (const elementWithIssues of extendedElementsWithIssues) {
|
|
86
|
+
if (elementWithIssues.skipRender) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
59
89
|
elementWithIssues.element.removeAttribute(attrName);
|
|
60
90
|
if (supportsAnchorPositioning(window)) {
|
|
61
91
|
removeAnchorName(elementWithIssues);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Issue } from '../types';
|
|
2
2
|
import type { Signal } from '@preact/signals-core';
|
|
3
|
-
import { effect } from '@preact/signals-core';
|
|
4
3
|
import getElementHtml from '../utils/get-element-html.js';
|
|
5
4
|
import { accentedUrl } from '../constants.js';
|
|
6
5
|
import logAndRethrow from '../log-and-rethrow.js';
|
|
@@ -9,6 +8,7 @@ export interface AccentedDialog extends HTMLElement {
|
|
|
9
8
|
issues: Signal<Array<Issue>> | undefined;
|
|
10
9
|
element: Element | undefined;
|
|
11
10
|
showModal: () => void;
|
|
11
|
+
open: boolean;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// We want Accented to not throw an error in Node, and use static imports,
|
|
@@ -241,15 +241,13 @@ export default () => {
|
|
|
241
241
|
`);
|
|
242
242
|
|
|
243
243
|
return class extends HTMLElement implements AccentedDialog {
|
|
244
|
-
#disposeOfEffect: (() => void) | undefined;
|
|
245
|
-
|
|
246
244
|
#abortController: AbortController | undefined;
|
|
247
245
|
|
|
248
246
|
issues: Signal<Array<Issue>> | undefined;
|
|
249
247
|
|
|
250
248
|
element: Element | undefined;
|
|
251
249
|
|
|
252
|
-
|
|
250
|
+
open: boolean = false;
|
|
253
251
|
|
|
254
252
|
constructor() {
|
|
255
253
|
try {
|
|
@@ -298,75 +296,52 @@ export default () => {
|
|
|
298
296
|
}
|
|
299
297
|
}, { signal: this.#abortController.signal });
|
|
300
298
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
descriptionList.appendChild(li);
|
|
329
|
-
}
|
|
330
|
-
description.appendChild(descriptionContent);
|
|
299
|
+
if (this.issues) {
|
|
300
|
+
const issues = this.issues.value;
|
|
301
|
+
const issuesList = shadowRoot.getElementById('issues');
|
|
302
|
+
if (issuesList) {
|
|
303
|
+
issuesList.innerHTML = '';
|
|
304
|
+
for (const issue of issues) {
|
|
305
|
+
const issueContent = issueTemplate.content.cloneNode(true) as Element;
|
|
306
|
+
const title = issueContent.querySelector('a');
|
|
307
|
+
const impact = issueContent.querySelector('.impact');
|
|
308
|
+
const description = issueContent.querySelector('.description');
|
|
309
|
+
if (title && impact && description) {
|
|
310
|
+
title.textContent = issue.title + ' (' + issue.id + ')';
|
|
311
|
+
title.href = issue.url;
|
|
312
|
+
|
|
313
|
+
impact.textContent = 'User impact: ' + issue.impact;
|
|
314
|
+
impact.setAttribute('data-impact', String(issue.impact));
|
|
315
|
+
|
|
316
|
+
const descriptionItems = issue.description.split(/\n\s*/);
|
|
317
|
+
const descriptionContent = descriptionTemplate.content.cloneNode(true) as Element;
|
|
318
|
+
const descriptionTitle = descriptionContent.querySelector('span');
|
|
319
|
+
const descriptionList = descriptionContent.querySelector('ul');
|
|
320
|
+
if (descriptionTitle && descriptionList && descriptionItems.length > 1) {
|
|
321
|
+
descriptionTitle.textContent = descriptionItems[0]!;
|
|
322
|
+
for (const descriptionItem of descriptionItems.slice(1)) {
|
|
323
|
+
const li = document.createElement('li');
|
|
324
|
+
li.textContent = descriptionItem;
|
|
325
|
+
descriptionList.appendChild(li);
|
|
331
326
|
}
|
|
327
|
+
description.appendChild(descriptionContent);
|
|
332
328
|
}
|
|
333
|
-
issuesList.appendChild(issueContent);
|
|
334
329
|
}
|
|
330
|
+
issuesList.appendChild(issueContent);
|
|
335
331
|
}
|
|
336
332
|
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const updateElementHtml = () => {
|
|
340
|
-
if (this.element) {
|
|
341
|
-
const elementHtmlContainer = shadowRoot.getElementById('element-html');
|
|
342
|
-
if (elementHtmlContainer) {
|
|
343
|
-
elementHtmlContainer.textContent = getElementHtml(this.element);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
updateElementHtml();
|
|
333
|
+
}
|
|
349
334
|
|
|
350
|
-
this.#elementMutationObserver = new MutationObserver(() => {
|
|
351
|
-
try {
|
|
352
|
-
updateElementHtml();
|
|
353
|
-
} catch (error) {
|
|
354
|
-
logAndRethrow(error);
|
|
355
|
-
}
|
|
356
|
-
});
|
|
357
335
|
if (this.element) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
this.#elementMutationObserver.observe(this.element, {
|
|
363
|
-
attributes: true,
|
|
364
|
-
childList: true
|
|
365
|
-
});
|
|
336
|
+
const elementHtmlContainer = shadowRoot.getElementById('element-html');
|
|
337
|
+
if (elementHtmlContainer) {
|
|
338
|
+
elementHtmlContainer.textContent = getElementHtml(this.element);
|
|
339
|
+
}
|
|
366
340
|
}
|
|
367
341
|
|
|
368
342
|
dialog?.addEventListener('close', () => {
|
|
369
343
|
try {
|
|
344
|
+
this.open = false;
|
|
370
345
|
this.dispatchEvent(new Event('close'));
|
|
371
346
|
} catch (error) {
|
|
372
347
|
logAndRethrow(error);
|
|
@@ -380,15 +355,9 @@ export default () => {
|
|
|
380
355
|
|
|
381
356
|
disconnectedCallback() {
|
|
382
357
|
try {
|
|
383
|
-
if (this.#disposeOfEffect) {
|
|
384
|
-
this.#disposeOfEffect();
|
|
385
|
-
}
|
|
386
358
|
if (this.#abortController) {
|
|
387
359
|
this.#abortController.abort();
|
|
388
360
|
}
|
|
389
|
-
if (this.#elementMutationObserver) {
|
|
390
|
-
this.#elementMutationObserver.disconnect();
|
|
391
|
-
}
|
|
392
361
|
} catch (error) {
|
|
393
362
|
logAndRethrow(error);
|
|
394
363
|
}
|
|
@@ -399,6 +368,7 @@ export default () => {
|
|
|
399
368
|
const dialog = this.shadowRoot.querySelector('dialog');
|
|
400
369
|
if (dialog) {
|
|
401
370
|
dialog.showModal();
|
|
371
|
+
this.open = true;
|
|
402
372
|
}
|
|
403
373
|
}
|
|
404
374
|
}
|
|
@@ -44,11 +44,12 @@ export default (name: string) => {
|
|
|
44
44
|
#trigger {
|
|
45
45
|
pointer-events: auto;
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
margin-inline-start: auto;
|
|
48
|
+
margin-inline-end: 4px;
|
|
49
|
+
margin-block-start: 4px;
|
|
50
50
|
|
|
51
51
|
box-sizing: border-box;
|
|
52
|
+
font-family: system-ui;
|
|
52
53
|
font-size: calc(var(--ratio) * var(--ratio) * var(--base-size));
|
|
53
54
|
inline-size: calc(2 * var(--base-size));
|
|
54
55
|
block-size: calc(2 * var(--base-size));
|
|
@@ -81,7 +82,7 @@ export default (name: string) => {
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
</style>
|
|
84
|
-
<button id="trigger" lang="en"
|
|
85
|
+
<button id="trigger" lang="en">á</button>
|
|
85
86
|
`;
|
|
86
87
|
|
|
87
88
|
return class extends HTMLElement implements AccentedTrigger {
|
|
@@ -200,7 +201,7 @@ export default (name: string) => {
|
|
|
200
201
|
if (this.#abortController) {
|
|
201
202
|
this.#abortController.abort();
|
|
202
203
|
}
|
|
203
|
-
if (this.#dialogCloseAbortController) {
|
|
204
|
+
if (this.#dialogCloseAbortController && !this.dialog?.open) {
|
|
204
205
|
this.#dialogCloseAbortController.abort();
|
|
205
206
|
this.dialog?.remove();
|
|
206
207
|
}
|
package/src/logger.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { effect } from '@preact/signals-core';
|
|
2
2
|
import { elementsWithIssues, enabled } from './state.js';
|
|
3
3
|
import { accentedUrl } from './constants.js';
|
|
4
|
+
import type { ElementWithIssues } from './types';
|
|
5
|
+
|
|
6
|
+
function filterPropsForOutput(elements: Array<ElementWithIssues>) {
|
|
7
|
+
return elements.map(({ element, issues }) => ({ element, issues }));
|
|
8
|
+
}
|
|
4
9
|
|
|
5
10
|
export default function createLogger() {
|
|
6
11
|
|
|
@@ -14,7 +19,10 @@ export default function createLogger() {
|
|
|
14
19
|
const elementCount = elementsWithIssues.value.length;
|
|
15
20
|
if (elementCount > 0) {
|
|
16
21
|
const issueCount = elementsWithIssues.value.reduce((acc, { issues }) => acc + issues.length, 0);
|
|
17
|
-
console.log(
|
|
22
|
+
console.log(
|
|
23
|
+
`${issueCount} accessibility issue${issueCount === 1 ? '' : 's'} found in ${elementCount} element${issueCount === 1 ? '' : 's'} (Accented, ${accentedUrl}):\n`,
|
|
24
|
+
filterPropsForOutput(elementsWithIssues.value)
|
|
25
|
+
);
|
|
18
26
|
} else {
|
|
19
27
|
if (firstRun) {
|
|
20
28
|
firstRun = false;
|