accented 0.0.1-dev.3 → 0.0.2
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 +214 -0
- package/dist/accented.d.ts +28 -7
- package/dist/accented.d.ts.map +1 -1
- package/dist/accented.js +100 -42
- package/dist/accented.js.map +1 -1
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +3 -0
- package/dist/constants.js.map +1 -0
- package/dist/dom-updater.d.ts +1 -6
- package/dist/dom-updater.d.ts.map +1 -1
- package/dist/dom-updater.js +94 -20
- package/dist/dom-updater.js.map +1 -1
- package/dist/elements/accented-dialog.d.ts +356 -0
- package/dist/elements/accented-dialog.d.ts.map +1 -0
- package/dist/elements/accented-dialog.js +361 -0
- package/dist/elements/accented-dialog.js.map +1 -0
- package/dist/elements/accented-trigger.d.ts +359 -0
- package/dist/elements/accented-trigger.d.ts.map +1 -0
- package/dist/elements/accented-trigger.js +159 -0
- package/dist/elements/accented-trigger.js.map +1 -0
- package/dist/intersection-observer.d.ts +5 -0
- package/dist/intersection-observer.d.ts.map +1 -0
- package/dist/intersection-observer.js +28 -0
- package/dist/intersection-observer.js.map +1 -0
- package/dist/log-and-rethrow.d.ts +2 -0
- package/dist/log-and-rethrow.d.ts.map +1 -0
- package/dist/log-and-rethrow.js +7 -0
- package/dist/log-and-rethrow.js.map +1 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +25 -0
- package/dist/logger.js.map +1 -0
- package/dist/register-elements.d.ts +2 -0
- package/dist/register-elements.d.ts.map +1 -0
- package/dist/register-elements.js +21 -0
- package/dist/register-elements.js.map +1 -0
- package/dist/resize-listener.d.ts +2 -0
- package/dist/resize-listener.d.ts.map +1 -0
- package/dist/resize-listener.js +18 -0
- package/dist/resize-listener.js.map +1 -0
- package/dist/scanner.d.ts +3 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +120 -0
- package/dist/scanner.js.map +1 -0
- package/dist/scroll-listeners.d.ts +2 -0
- package/dist/scroll-listeners.d.ts.map +1 -0
- package/dist/scroll-listeners.js +38 -0
- package/dist/scroll-listeners.js.map +1 -0
- package/dist/state.d.ts +6 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +14 -0
- package/dist/state.js.map +1 -0
- package/dist/task-queue.d.ts +3 -4
- package/dist/task-queue.d.ts.map +1 -1
- package/dist/task-queue.js +27 -23
- package/dist/task-queue.js.map +1 -1
- package/dist/types.d.ts +136 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/are-issue-sets-equal.d.ts +3 -0
- package/dist/utils/are-issue-sets-equal.d.ts.map +1 -0
- package/dist/utils/are-issue-sets-equal.js +6 -0
- package/dist/utils/are-issue-sets-equal.js.map +1 -0
- package/dist/utils/deep-merge.d.ts +4 -0
- package/dist/utils/deep-merge.d.ts.map +1 -0
- package/dist/utils/deep-merge.js +18 -0
- package/dist/utils/deep-merge.js.map +1 -0
- package/dist/utils/get-element-html.d.ts +2 -0
- package/dist/utils/get-element-html.d.ts.map +1 -0
- package/dist/utils/get-element-html.js +14 -0
- package/dist/utils/get-element-html.js.map +1 -0
- package/dist/utils/get-element-position.d.ts +3 -0
- package/dist/utils/get-element-position.d.ts.map +1 -0
- package/dist/utils/get-element-position.js +22 -0
- package/dist/utils/get-element-position.js.map +1 -0
- package/dist/utils/get-scrollable-ancestors.d.ts +2 -0
- package/dist/utils/get-scrollable-ancestors.d.ts.map +1 -0
- package/dist/utils/get-scrollable-ancestors.js +15 -0
- package/dist/utils/get-scrollable-ancestors.js.map +1 -0
- package/dist/utils/recalculate-positions.d.ts +2 -0
- package/dist/utils/recalculate-positions.d.ts.map +1 -0
- package/dist/utils/recalculate-positions.js +27 -0
- package/dist/utils/recalculate-positions.js.map +1 -0
- package/dist/utils/recalculate-scrollable-ancestors.d.ts +2 -0
- package/dist/utils/recalculate-scrollable-ancestors.d.ts.map +1 -0
- package/dist/utils/recalculate-scrollable-ancestors.js +13 -0
- package/dist/utils/recalculate-scrollable-ancestors.js.map +1 -0
- package/dist/utils/supports-anchor-positioning.d.ts +6 -0
- package/dist/utils/supports-anchor-positioning.d.ts.map +1 -0
- package/dist/utils/supports-anchor-positioning.js +4 -0
- package/dist/utils/supports-anchor-positioning.js.map +1 -0
- package/dist/utils/transform-violations.d.ts +4 -0
- package/dist/utils/transform-violations.d.ts.map +1 -0
- package/dist/utils/transform-violations.js +48 -0
- package/dist/utils/transform-violations.js.map +1 -0
- package/dist/utils/update-elements-with-issues.d.ts +7 -0
- package/dist/utils/update-elements-with-issues.d.ts.map +1 -0
- package/dist/utils/update-elements-with-issues.js +64 -0
- package/dist/utils/update-elements-with-issues.js.map +1 -0
- package/dist/validate-options.d.ts +3 -0
- package/dist/validate-options.d.ts.map +1 -0
- package/dist/validate-options.js +42 -0
- package/dist/validate-options.js.map +1 -0
- package/package.json +8 -3
- package/src/accented.test.ts +24 -0
- package/src/accented.ts +119 -0
- package/src/constants.ts +2 -0
- package/src/dom-updater.ts +112 -0
- package/src/elements/accented-dialog.ts +384 -0
- package/src/elements/accented-trigger.ts +179 -0
- package/src/intersection-observer.ts +28 -0
- package/src/log-and-rethrow.ts +9 -0
- package/src/logger.ts +26 -0
- package/src/register-elements.ts +21 -0
- package/src/resize-listener.ts +17 -0
- package/src/scanner.ts +139 -0
- package/src/scroll-listeners.ts +37 -0
- package/src/state.ts +24 -0
- package/src/task-queue.test.ts +135 -0
- package/src/task-queue.ts +59 -0
- package/src/types.ts +155 -0
- package/src/utils/are-issue-sets-equal.test.ts +49 -0
- package/src/utils/are-issue-sets-equal.ts +10 -0
- package/src/utils/deep-merge.test.ts +34 -0
- package/src/utils/deep-merge.ts +18 -0
- package/src/utils/get-element-html.ts +13 -0
- package/src/utils/get-element-position.ts +21 -0
- package/src/utils/get-scrollable-ancestors.ts +14 -0
- package/src/utils/recalculate-positions.ts +27 -0
- package/src/utils/recalculate-scrollable-ancestors.ts +13 -0
- package/src/utils/supports-anchor-positioning.ts +7 -0
- package/src/utils/transform-violations.test.ts +124 -0
- package/src/utils/transform-violations.ts +56 -0
- package/src/utils/update-elements-with-issues.test.ts +283 -0
- package/src/utils/update-elements-with-issues.ts +75 -0
- package/src/validate-options.ts +44 -0
- package/dist/utils/issuesToElements.d.ts +0 -3
- package/dist/utils/issuesToElements.d.ts.map +0 -1
- package/dist/utils/issuesToElements.js +0 -16
- package/dist/utils/issuesToElements.js.map +0 -1
- package/dist/whatever.d.ts +0 -2
- package/dist/whatever.d.ts.map +0 -1
- package/dist/whatever.js +0 -2
- package/dist/whatever.js.map +0 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export default function getElementPosition(element, win) {
|
|
2
|
+
const rect = element.getBoundingClientRect();
|
|
3
|
+
const direction = win.getComputedStyle(element).direction;
|
|
4
|
+
if (direction === 'ltr') {
|
|
5
|
+
return {
|
|
6
|
+
inlineEndLeft: rect.right,
|
|
7
|
+
blockStartTop: rect.top,
|
|
8
|
+
direction
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
else if (direction === 'rtl') {
|
|
12
|
+
return {
|
|
13
|
+
inlineEndLeft: rect.left,
|
|
14
|
+
blockStartTop: rect.top,
|
|
15
|
+
direction
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
throw new Error(`The element ${element} has a direction "${direction}", which is not supported.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=get-element-position.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-element-position.js","sourceRoot":"","sources":["../../src/utils/get-element-position.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,OAAgB,EAAE,GAAW;IACtE,MAAM,IAAI,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAC7C,MAAM,SAAS,GAAG,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC;IAC1D,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;QACxB,OAAO;YACL,aAAa,EAAE,IAAI,CAAC,KAAK;YACzB,aAAa,EAAE,IAAI,CAAC,GAAG;YACvB,SAAS;SACV,CAAC;IACJ,CAAC;SAAM,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;QAC/B,OAAO;YACL,aAAa,EAAE,IAAI,CAAC,IAAI;YACxB,aAAa,EAAE,IAAI,CAAC,GAAG;YACvB,SAAS;SACV,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,eAAe,OAAO,qBAAqB,SAAS,4BAA4B,CAAC,CAAC;IACpG,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-scrollable-ancestors.d.ts","sourceRoot":"","sources":["../../src/utils/get-scrollable-ancestors.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,oBAWhF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const scrollableOverflowValues = new Set(['auto', 'scroll', 'hidden']);
|
|
2
|
+
export default function getScrollableAncestors(element, win) {
|
|
3
|
+
let currentElement = element;
|
|
4
|
+
let scrollableAncestors = new Set();
|
|
5
|
+
while (currentElement.parentElement) {
|
|
6
|
+
currentElement = currentElement.parentElement;
|
|
7
|
+
const computedStyle = win.getComputedStyle(currentElement);
|
|
8
|
+
if (scrollableOverflowValues.has(computedStyle.overflowX) || scrollableOverflowValues.has(computedStyle.overflowY)) {
|
|
9
|
+
scrollableAncestors.add(currentElement);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return scrollableAncestors;
|
|
13
|
+
}
|
|
14
|
+
;
|
|
15
|
+
//# sourceMappingURL=get-scrollable-ancestors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-scrollable-ancestors.js","sourceRoot":"","sources":["../../src/utils/get-scrollable-ancestors.ts"],"names":[],"mappings":"AAAA,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEvE,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAE,OAAoB,EAAE,GAAW;IAC/E,IAAI,cAAc,GAAG,OAAO,CAAC;IAC7B,IAAI,mBAAmB,GAAG,IAAI,GAAG,EAAe,CAAC;IACjD,OAAO,cAAc,CAAC,aAAa,EAAE,CAAC;QACpC,cAAc,GAAG,cAAc,CAAC,aAAa,CAAC;QAC9C,MAAM,aAAa,GAAG,GAAG,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;QAC3D,IAAI,wBAAwB,CAAC,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,wBAAwB,CAAC,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;YACnH,mBAAmB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,mBAAmB,CAAC;AAC7B,CAAC;AAAA,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recalculate-positions.d.ts","sourceRoot":"","sources":["../../src/utils/recalculate-positions.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,OAAO,UAAU,oBAAoB,SAmB3C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { batch } from '@preact/signals-core';
|
|
2
|
+
import { extendedElementsWithIssues } from '../state.js';
|
|
3
|
+
import getElementPosition from './get-element-position.js';
|
|
4
|
+
import logAndRethrow from '../log-and-rethrow.js';
|
|
5
|
+
let frameRequested = false;
|
|
6
|
+
export default function recalculatePositions() {
|
|
7
|
+
if (frameRequested) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
frameRequested = true;
|
|
11
|
+
window.requestAnimationFrame(() => {
|
|
12
|
+
try {
|
|
13
|
+
frameRequested = false;
|
|
14
|
+
batch(() => {
|
|
15
|
+
extendedElementsWithIssues.value.forEach(({ element, position, visible }) => {
|
|
16
|
+
if (visible.value && element.isConnected) {
|
|
17
|
+
position.value = getElementPosition(element, window);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
logAndRethrow(error);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=recalculate-positions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recalculate-positions.js","sourceRoot":"","sources":["../../src/utils/recalculate-positions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,kBAAkB,MAAM,2BAA2B,CAAC;AAC3D,OAAO,aAAa,MAAM,uBAAuB,CAAC;AAElD,IAAI,cAAc,GAAG,KAAK,CAAC;AAE3B,MAAM,CAAC,OAAO,UAAU,oBAAoB;IAC1C,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO;IACT,CAAC;IACD,cAAc,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE;QAChC,IAAI,CAAC;YACH,cAAc,GAAG,KAAK,CAAC;YACvB,KAAK,CAAC,GAAG,EAAE;gBACT,0BAA0B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE;oBAC1E,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;wBACzC,QAAQ,CAAC,KAAK,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;oBACvD,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recalculate-scrollable-ancestors.d.ts","sourceRoot":"","sources":["../../src/utils/recalculate-scrollable-ancestors.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,8BAA8B,SAQrD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { batch } from '@preact/signals-core';
|
|
2
|
+
import { extendedElementsWithIssues } from '../state.js';
|
|
3
|
+
import getScrollableAncestors from './get-scrollable-ancestors.js';
|
|
4
|
+
export default function recalculateScrollableAncestors() {
|
|
5
|
+
batch(() => {
|
|
6
|
+
extendedElementsWithIssues.value.forEach(({ element, scrollableAncestors }) => {
|
|
7
|
+
if (element.isConnected) {
|
|
8
|
+
scrollableAncestors.value = getScrollableAncestors(element, window);
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=recalculate-scrollable-ancestors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recalculate-scrollable-ancestors.js","sourceRoot":"","sources":["../../src/utils/recalculate-scrollable-ancestors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AAEnE,MAAM,CAAC,OAAO,UAAU,8BAA8B;IACpD,KAAK,CAAC,GAAG,EAAE;QACT,0BAA0B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,EAAE;YAC5E,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBACxB,mBAAmB,CAAC,KAAK,GAAG,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACtE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supports-anchor-positioning.d.ts","sourceRoot":"","sources":["../../src/utils/supports-anchor-positioning.ts"],"names":[],"mappings":"AAAA,KAAK,aAAa,GAAG,MAAM,GAAG;IAC5B,GAAG,EAAE,OAAO,GAAG,CAAA;CAChB,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,GAAG,EAAE,aAAa,WAEnE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supports-anchor-positioning.js","sourceRoot":"","sources":["../../src/utils/supports-anchor-positioning.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,GAAkB;IAClE,OAAO,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform-violations.d.ts","sourceRoot":"","sources":["../../src/utils/transform-violations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,UAAU,CAAC;AACxD,OAAO,KAAK,EAAS,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAOzD,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,UAAU,EAAE,OAAO,UAAU,CAAC,UAAU,uBA+CnF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
function impactCompare(a, b) {
|
|
2
|
+
const impactOrder = [null, 'minor', 'moderate', 'serious', 'critical'];
|
|
3
|
+
return impactOrder.indexOf(a) - impactOrder.indexOf(b);
|
|
4
|
+
}
|
|
5
|
+
export default function transformViolations(violations) {
|
|
6
|
+
const elementsWithIssues = [];
|
|
7
|
+
for (const violation of violations) {
|
|
8
|
+
for (const node of violation.nodes) {
|
|
9
|
+
const { element, target } = node;
|
|
10
|
+
// Although axe-core can perform iframe scanning, I haven't succeeded in it,
|
|
11
|
+
// and the docs suggest that the axe-core script should be explicitly included
|
|
12
|
+
// in each of the iframed documents anyway.
|
|
13
|
+
// It seems preferable to disallow iframe scanning and not report issues in elements within iframes
|
|
14
|
+
// in the case that such issues are for some reason reported by axe-core.
|
|
15
|
+
// A consumer of Accented can instead scan the iframed document by calling Accented initialization from that document.
|
|
16
|
+
const isInIframe = target.length > 1;
|
|
17
|
+
// Highlighting elements in shadow DOM is not yet supported, see https://github.com/pomerantsev/accented/issues/25
|
|
18
|
+
// Until then, we don’t want such elements to be added to the set.
|
|
19
|
+
const isInShadowDOM = Array.isArray(target[0]);
|
|
20
|
+
if (element && !isInIframe && !isInShadowDOM) {
|
|
21
|
+
const issue = {
|
|
22
|
+
id: violation.id,
|
|
23
|
+
title: violation.help,
|
|
24
|
+
description: node.failureSummary ?? violation.description,
|
|
25
|
+
url: violation.helpUrl,
|
|
26
|
+
impact: violation.impact ?? null
|
|
27
|
+
};
|
|
28
|
+
const existingElementIndex = elementsWithIssues.findIndex(elementWithIssues => elementWithIssues.element === element);
|
|
29
|
+
if (existingElementIndex === -1) {
|
|
30
|
+
elementsWithIssues.push({
|
|
31
|
+
element,
|
|
32
|
+
issues: [issue]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
elementsWithIssues[existingElementIndex].issues.push(issue);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const elementWithIssues of elementsWithIssues) {
|
|
42
|
+
elementWithIssues.issues.sort((a, b) => {
|
|
43
|
+
return -impactCompare(a.impact, b.impact) || a.id.localeCompare(b.id);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return elementsWithIssues;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=transform-violations.js.map
|
|
@@ -0,0 +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;IAClF,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,kHAAkH;YAClH,kEAAkE;YAClE,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAE/C,IAAI,OAAO,IAAI,CAAC,UAAU,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC7C,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,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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AxeResults } from 'axe-core';
|
|
2
|
+
import type { Signal } from '@preact/signals-core';
|
|
3
|
+
import type { ExtendedElementWithIssues } from '../types';
|
|
4
|
+
export default function updateElementsWithIssues(extendedElementsWithIssues: Signal<Array<ExtendedElementWithIssues>>, violations: typeof AxeResults.violations, win: Window & {
|
|
5
|
+
CSS: typeof CSS;
|
|
6
|
+
}, name: string): void;
|
|
7
|
+
//# sourceMappingURL=update-elements-with-issues.d.ts.map
|
|
@@ -0,0 +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;AAW1D,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,QA4D/M"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { batch, signal } from '@preact/signals-core';
|
|
2
|
+
import transformViolations from './transform-violations.js';
|
|
3
|
+
import areIssueSetsEqual from './are-issue-sets-equal.js';
|
|
4
|
+
import getElementPosition from './get-element-position.js';
|
|
5
|
+
import getScrollableAncestors from './get-scrollable-ancestors.js';
|
|
6
|
+
import supportsAnchorPositioning from './supports-anchor-positioning.js';
|
|
7
|
+
let count = 0;
|
|
8
|
+
export default function updateElementsWithIssues(extendedElementsWithIssues, violations, win, name) {
|
|
9
|
+
const updatedElementsWithIssues = transformViolations(violations);
|
|
10
|
+
batch(() => {
|
|
11
|
+
for (const updatedElementWithIssues of updatedElementsWithIssues) {
|
|
12
|
+
const existingElementIndex = extendedElementsWithIssues.value.findIndex(extendedElementWithIssues => extendedElementWithIssues.element === updatedElementWithIssues.element);
|
|
13
|
+
if (existingElementIndex > -1 && extendedElementsWithIssues.value[existingElementIndex] && !areIssueSetsEqual(extendedElementsWithIssues.value[existingElementIndex].issues.value, updatedElementWithIssues.issues)) {
|
|
14
|
+
extendedElementsWithIssues.value[existingElementIndex].issues.value = updatedElementWithIssues.issues;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const addedElementsWithIssues = updatedElementsWithIssues.filter(updatedElementWithIssues => {
|
|
18
|
+
return !extendedElementsWithIssues.value.some(extendedElementWithIssues => extendedElementWithIssues.element === updatedElementWithIssues.element);
|
|
19
|
+
});
|
|
20
|
+
const removedElementsWithIssues = extendedElementsWithIssues.value.filter(extendedElementWithIssues => {
|
|
21
|
+
return !updatedElementsWithIssues.some(updatedElementWithIssues => updatedElementWithIssues.element === extendedElementWithIssues.element);
|
|
22
|
+
});
|
|
23
|
+
if (addedElementsWithIssues.length > 0 || removedElementsWithIssues.length > 0) {
|
|
24
|
+
extendedElementsWithIssues.value = [...extendedElementsWithIssues.value]
|
|
25
|
+
.filter(extendedElementWithIssues => {
|
|
26
|
+
return !removedElementsWithIssues.some(removedElementWithIssues => removedElementWithIssues.element === extendedElementWithIssues.element);
|
|
27
|
+
})
|
|
28
|
+
.concat(addedElementsWithIssues
|
|
29
|
+
.filter(addedElementWithIssues => addedElementWithIssues.element.isConnected)
|
|
30
|
+
.map(addedElementWithIssues => {
|
|
31
|
+
const id = count++;
|
|
32
|
+
const trigger = win.document.createElement(`${name}-trigger`);
|
|
33
|
+
const elementZIndex = parseInt(win.getComputedStyle(addedElementWithIssues.element).zIndex, 10);
|
|
34
|
+
if (!isNaN(elementZIndex)) {
|
|
35
|
+
trigger.style.setProperty('z-index', (elementZIndex + 1).toString(), 'important');
|
|
36
|
+
}
|
|
37
|
+
trigger.style.setProperty('position-anchor', `--${name}-anchor-${id}`, 'important');
|
|
38
|
+
trigger.dataset.id = id.toString();
|
|
39
|
+
const accentedDialog = win.document.createElement(`${name}-dialog`);
|
|
40
|
+
trigger.dialog = accentedDialog;
|
|
41
|
+
const position = getElementPosition(addedElementWithIssues.element, win);
|
|
42
|
+
trigger.position = signal(position);
|
|
43
|
+
trigger.visible = signal(true);
|
|
44
|
+
trigger.element = addedElementWithIssues.element;
|
|
45
|
+
const scrollableAncestors = supportsAnchorPositioning(win) ?
|
|
46
|
+
new Set() :
|
|
47
|
+
getScrollableAncestors(addedElementWithIssues.element, win);
|
|
48
|
+
const issues = signal(addedElementWithIssues.issues);
|
|
49
|
+
accentedDialog.issues = issues;
|
|
50
|
+
accentedDialog.element = addedElementWithIssues.element;
|
|
51
|
+
return {
|
|
52
|
+
id,
|
|
53
|
+
element: addedElementWithIssues.element,
|
|
54
|
+
visible: trigger.visible,
|
|
55
|
+
position: trigger.position,
|
|
56
|
+
scrollableAncestors: signal(scrollableAncestors),
|
|
57
|
+
trigger,
|
|
58
|
+
issues
|
|
59
|
+
};
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=update-elements-with-issues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-elements-with-issues.js","sourceRoot":"","sources":["../../src/utils/update-elements-with-issues.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-options.d.ts","sourceRoot":"","sources":["../src/validate-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAQ/C,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,OAAO,EAAE,eAAe,QAmC/D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { allowedAxeOptions } from './types.js';
|
|
2
|
+
// The space of valid CSS and HTML names is wider than this,
|
|
3
|
+
// but with Unicode it gets complicated quickly, so I'm sticking to only allowing
|
|
4
|
+
// lowercase alphanumeric names that possibly contain dashes that start with a letter.
|
|
5
|
+
const nameRegex = /^[a-z]([a-z0-9]|-)+$/;
|
|
6
|
+
export default function validateOptions(options) {
|
|
7
|
+
if (typeof options !== 'object' || options === null) {
|
|
8
|
+
throw new TypeError(`Accented: invalid argument. The options parameter must be an object if provided. It’s currently set to ${options}.`);
|
|
9
|
+
}
|
|
10
|
+
if (options.throttle !== undefined) {
|
|
11
|
+
if (typeof options.throttle !== 'object' || options.throttle === null) {
|
|
12
|
+
throw new TypeError(`Accented: invalid argument. \`throttle\` option must be an object if provided. It’s currently set to ${options.throttle}.`);
|
|
13
|
+
}
|
|
14
|
+
if (options.throttle.wait !== undefined && (typeof options.throttle.wait !== 'number' || options.throttle.wait < 0)) {
|
|
15
|
+
throw new TypeError(`Accented: invalid argument. \`throttle.wait\` option must be a non-negative number if provided. It’s currently set to ${options.throttle.wait}.`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (options.output !== undefined) {
|
|
19
|
+
if (typeof options.output !== 'object' || options.output === null) {
|
|
20
|
+
throw new TypeError(`Accented: invalid argument. \`output\` option must be an object if provided. It’s currently set to ${options.output}.`);
|
|
21
|
+
}
|
|
22
|
+
if (options.output.console !== undefined && typeof options.output.console !== 'boolean') {
|
|
23
|
+
console.warn(`Accented: invalid argument. \`output.console\` option is expected to be a boolean. It’s currently set to ${options.output.console}.`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (options.callback !== undefined && typeof options.callback !== 'function') {
|
|
27
|
+
throw new TypeError(`Accented: invalid argument. \`callback\` option must be a function if provided. It’s currently set to ${options.callback}.`);
|
|
28
|
+
}
|
|
29
|
+
if (options.name !== undefined && (typeof options.name !== 'string' || !options.name.match(nameRegex))) {
|
|
30
|
+
throw new TypeError(`Accented: invalid argument. \`name\` option must be a string that starts with a lowercase letter and only contains lowercase alphanumeric characters and dashes. It’s currently set to ${options.name}.`);
|
|
31
|
+
}
|
|
32
|
+
if (options.axeOptions !== undefined) {
|
|
33
|
+
if (typeof options.axeOptions !== 'object' || options.axeOptions === null) {
|
|
34
|
+
throw new TypeError(`Accented: invalid argument. \`axeOptions\` option must be an object if provided. It’s currently set to ${options.axeOptions}.`);
|
|
35
|
+
}
|
|
36
|
+
const unsupportedKeys = Object.keys(options.axeOptions).filter(key => !allowedAxeOptions.includes(key));
|
|
37
|
+
if (unsupportedKeys.length > 0) {
|
|
38
|
+
throw new TypeError(`Accented: invalid argument. \`axeOptions\` contains the following unsupported keys: ${unsupportedKeys.join(', ')}. Valid options are: ${allowedAxeOptions.join(', ')}.`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=validate-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-options.js","sourceRoot":"","sources":["../src/validate-options.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "accented",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
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
|
-
"dist"
|
|
8
|
+
"dist",
|
|
9
|
+
"src"
|
|
9
10
|
],
|
|
10
11
|
"repository": {
|
|
11
12
|
"type": "git",
|
|
@@ -24,11 +25,15 @@
|
|
|
24
25
|
},
|
|
25
26
|
"homepage": "https://github.com/pomerantsev/accented#readme",
|
|
26
27
|
"dependencies": {
|
|
28
|
+
"@preact/signals-core": "^1.8.0",
|
|
27
29
|
"axe-core": "^4.10.2"
|
|
28
30
|
},
|
|
29
31
|
"scripts": {
|
|
30
32
|
"build": "tsc",
|
|
33
|
+
"checkBuiltFiles": "node --import tsx ./scripts/check-built-files.ts",
|
|
34
|
+
"checkImportsInBuiltFiles": "node ./dist/accented.js",
|
|
35
|
+
"typecheckTests": "tsc -p ./tsconfig.test.json",
|
|
31
36
|
"watch": "tsc --watch",
|
|
32
|
-
"test": "node --test --import tsx ./**/*.test.ts"
|
|
37
|
+
"test": "node --test --import tsx \"./**/*.test.ts\""
|
|
33
38
|
}
|
|
34
39
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import {suite, test} from 'node:test';
|
|
3
|
+
import type { Mock } from 'node:test';
|
|
4
|
+
|
|
5
|
+
import accented from './accented.js';
|
|
6
|
+
|
|
7
|
+
suite('Accented', () => {
|
|
8
|
+
test('runs without errors in NodeJS and issues a warning and a trace (it’s meant to be a no-op on the server side)', (t) => {
|
|
9
|
+
t.mock.method(console, 'warn', () => {});
|
|
10
|
+
t.mock.method(console, 'trace', () => {});
|
|
11
|
+
accented();
|
|
12
|
+
assert.equal((console.warn as Mock<() => void>).mock.callCount(), 1);
|
|
13
|
+
assert.equal((console.trace as Mock<() => void>).mock.callCount(), 1);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
suite('argument validation', () => {
|
|
17
|
+
// @ts-expect-error
|
|
18
|
+
assert.throws(() => accented({ throttle: null }));
|
|
19
|
+
// @ts-expect-error
|
|
20
|
+
assert.throws(() => accented({ throttle: 1000 }));
|
|
21
|
+
|
|
22
|
+
assert.throws(() => accented({ throttle: { wait: -1 } }));
|
|
23
|
+
});
|
|
24
|
+
});
|
package/src/accented.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
|
|
2
|
+
import registerElements from './register-elements.js';
|
|
3
|
+
import createDomUpdater from './dom-updater.js';
|
|
4
|
+
import createLogger from './logger.js';
|
|
5
|
+
import createScanner from './scanner.js';
|
|
6
|
+
import setupScrollListeners from './scroll-listeners.js';
|
|
7
|
+
import setupResizeListener from './resize-listener.js';
|
|
8
|
+
import setupIntersectionObserver from './intersection-observer.js';
|
|
9
|
+
import { enabled, extendedElementsWithIssues } from './state.js';
|
|
10
|
+
import deepMerge from './utils/deep-merge.js';
|
|
11
|
+
import type { AccentedOptions, DisableAccented } from './types';
|
|
12
|
+
import validateOptions from './validate-options.js';
|
|
13
|
+
import supportsAnchorPositioning from './utils/supports-anchor-positioning.js';
|
|
14
|
+
import logAndRethrow from './log-and-rethrow.js';
|
|
15
|
+
|
|
16
|
+
export type { AccentedOptions, DisableAccented };
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Enables highlighting of elements with accessibility issues.
|
|
20
|
+
*
|
|
21
|
+
* @param {AccentedOptions} options - The options object.
|
|
22
|
+
*
|
|
23
|
+
* @returns A `disable` function that can be called to stop the scanning and highlighting.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* accented();
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const disableAccented = accented({
|
|
30
|
+
* output: {
|
|
31
|
+
* console: false
|
|
32
|
+
* },
|
|
33
|
+
* throttle: {
|
|
34
|
+
* wait: 500,
|
|
35
|
+
* leading: false
|
|
36
|
+
* },
|
|
37
|
+
* callback: ({ elementsWithIssues, scanDuration }) => {
|
|
38
|
+
* console.log('Elements with issues:', elementsWithIssues);
|
|
39
|
+
* console.log('Scan duration:', scanDuration);
|
|
40
|
+
* }
|
|
41
|
+
* });
|
|
42
|
+
*/
|
|
43
|
+
export default function accented(options: AccentedOptions = {}): DisableAccented {
|
|
44
|
+
|
|
45
|
+
validateOptions(options);
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
49
|
+
console.warn('Accented: this script can only run in the browser, and it’s likely running on the server now. Exiting.');
|
|
50
|
+
console.trace();
|
|
51
|
+
return () => {};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const defaultOutput: Required<AccentedOptions['output']> = {
|
|
55
|
+
console: true
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const defaultThrottle: Required<AccentedOptions['throttle']> = {
|
|
59
|
+
wait: 1000,
|
|
60
|
+
leading: true
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// IMPORTANT: when changing any of the properties or values, also do the following:
|
|
64
|
+
// * update the default value in the type documentation accordingly;
|
|
65
|
+
// * update validations and validation tests if necessary;
|
|
66
|
+
// * update examples in the accented() function JSDoc;
|
|
67
|
+
// * update examples in the Readme.
|
|
68
|
+
const defaultOptions: Required<AccentedOptions> = {
|
|
69
|
+
axeContext: document,
|
|
70
|
+
axeOptions: {},
|
|
71
|
+
name: 'accented',
|
|
72
|
+
output: defaultOutput,
|
|
73
|
+
throttle: defaultThrottle,
|
|
74
|
+
callback: () => {}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const {axeContext, axeOptions, name, output, throttle, callback} = deepMerge(defaultOptions, options);
|
|
78
|
+
|
|
79
|
+
if (enabled.value) {
|
|
80
|
+
// Add link to the recipes section of the docs (#56).
|
|
81
|
+
console.warn(
|
|
82
|
+
'You are trying to run the Accented library more than once. ' +
|
|
83
|
+
'This will likely lead to errors.'
|
|
84
|
+
);
|
|
85
|
+
console.trace();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
enabled.value = true;
|
|
89
|
+
|
|
90
|
+
registerElements(name);
|
|
91
|
+
|
|
92
|
+
const {disconnect: cleanupIntersectionObserver, intersectionObserver } = supportsAnchorPositioning(window) ? {} : setupIntersectionObserver();
|
|
93
|
+
const cleanupScanner = createScanner(name, axeContext, axeOptions, throttle, callback);
|
|
94
|
+
const cleanupDomUpdater = createDomUpdater(name, intersectionObserver);
|
|
95
|
+
const cleanupLogger = output.console ? createLogger() : () => {};
|
|
96
|
+
const cleanupScrollListeners = supportsAnchorPositioning(window) ? () => {} : setupScrollListeners();
|
|
97
|
+
const cleanupResizeListener = supportsAnchorPositioning(window) ? () => {} : setupResizeListener();
|
|
98
|
+
|
|
99
|
+
return () => {
|
|
100
|
+
try {
|
|
101
|
+
enabled.value = false;
|
|
102
|
+
extendedElementsWithIssues.value = [];
|
|
103
|
+
cleanupScanner();
|
|
104
|
+
cleanupDomUpdater();
|
|
105
|
+
cleanupLogger();
|
|
106
|
+
cleanupScrollListeners();
|
|
107
|
+
cleanupResizeListener();
|
|
108
|
+
if (cleanupIntersectionObserver) {
|
|
109
|
+
cleanupIntersectionObserver();
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
logAndRethrow(error);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
} catch (error) {
|
|
116
|
+
logAndRethrow(error);
|
|
117
|
+
return () => {};
|
|
118
|
+
}
|
|
119
|
+
}
|
package/src/constants.ts
ADDED