accented 0.0.2 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +14 -0
- package/README.md +44 -187
- package/dist/accented.d.ts +8 -8
- package/dist/accented.d.ts.map +1 -1
- package/dist/accented.js +37 -30
- package/dist/accented.js.map +1 -1
- package/dist/common/strings.d.ts +2 -0
- package/dist/common/strings.d.ts.map +1 -0
- package/dist/common/strings.js +2 -0
- package/dist/common/strings.js.map +1 -0
- package/dist/common/tokens.d.ts +7 -0
- package/dist/common/tokens.d.ts.map +1 -0
- package/dist/common/tokens.js +8 -0
- package/dist/common/tokens.js.map +1 -0
- package/dist/constants.d.ts +2 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/dom-updater.d.ts +1 -1
- package/dist/dom-updater.d.ts.map +1 -1
- package/dist/dom-updater.js +73 -31
- package/dist/dom-updater.js.map +1 -1
- package/dist/elements/accented-dialog.d.ts +18 -10
- package/dist/elements/accented-dialog.d.ts.map +1 -1
- package/dist/elements/accented-dialog.js +116 -95
- package/dist/elements/accented-dialog.js.map +1 -1
- package/dist/elements/accented-trigger.d.ts +14 -9
- package/dist/elements/accented-trigger.d.ts.map +1 -1
- package/dist/elements/accented-trigger.js +83 -24
- 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 +17 -0
- package/dist/fullscreen-listener.js.map +1 -0
- package/dist/intersection-observer.d.ts +1 -1
- package/dist/intersection-observer.d.ts.map +1 -1
- package/dist/intersection-observer.js +12 -6
- package/dist/intersection-observer.js.map +1 -1
- package/dist/log-and-rethrow.d.ts +1 -1
- package/dist/log-and-rethrow.d.ts.map +1 -1
- package/dist/log-and-rethrow.js +2 -3
- package/dist/log-and-rethrow.js.map +1 -1
- package/dist/logger.d.ts +4 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +6 -3
- package/dist/logger.js.map +1 -1
- package/dist/register-elements.d.ts +1 -1
- package/dist/register-elements.d.ts.map +1 -1
- package/dist/register-elements.js +6 -7
- package/dist/register-elements.js.map +1 -1
- package/dist/resize-listener.d.ts +1 -1
- package/dist/resize-listener.d.ts.map +1 -1
- package/dist/resize-listener.js +3 -4
- package/dist/resize-listener.js.map +1 -1
- package/dist/scanner.d.ts +2 -2
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +76 -43
- package/dist/scanner.js.map +1 -1
- package/dist/scroll-listeners.d.ts +1 -1
- package/dist/scroll-listeners.d.ts.map +1 -1
- package/dist/scroll-listeners.js +3 -4
- package/dist/scroll-listeners.js.map +1 -1
- package/dist/state.d.ts +3 -2
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +5 -3
- package/dist/state.js.map +1 -1
- package/dist/task-queue.d.ts +4 -4
- package/dist/task-queue.d.ts.map +1 -1
- package/dist/task-queue.js +3 -2
- package/dist/task-queue.js.map +1 -1
- package/dist/types.d.ts +140 -49
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.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/are-issue-sets-equal.d.ts +2 -2
- package/dist/utils/are-issue-sets-equal.d.ts.map +1 -1
- package/dist/utils/are-issue-sets-equal.js +3 -3
- package/dist/utils/are-issue-sets-equal.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 +4 -0
- package/dist/utils/deduplicate-nodes.js.map +1 -0
- package/dist/utils/deep-merge.d.ts +1 -1
- package/dist/utils/deep-merge.d.ts.map +1 -1
- package/dist/utils/deep-merge.js +8 -5
- package/dist/utils/deep-merge.js.map +1 -1
- package/dist/utils/dom-helpers.d.ts +9 -0
- package/dist/utils/dom-helpers.d.ts.map +1 -0
- package/dist/utils/dom-helpers.js +34 -0
- package/dist/utils/dom-helpers.js.map +1 -0
- 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-html.d.ts +1 -1
- package/dist/utils/get-element-html.d.ts.map +1 -1
- package/dist/utils/get-element-html.js +4 -2
- package/dist/utils/get-element-html.js.map +1 -1
- package/dist/utils/get-element-position.d.ts +10 -2
- package/dist/utils/get-element-position.d.ts.map +1 -1
- package/dist/utils/get-element-position.js +64 -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-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/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 +10 -6
- package/dist/utils/get-scrollable-ancestors.js.map +1 -1
- 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/is-non-empty.d.ts +2 -0
- package/dist/utils/is-non-empty.d.ts.map +1 -0
- package/dist/utils/is-non-empty.js +4 -0
- package/dist/utils/is-non-empty.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 +59 -0
- package/dist/utils/normalize-context.js.map +1 -0
- package/dist/utils/recalculate-positions.d.ts +1 -1
- package/dist/utils/recalculate-positions.d.ts.map +1 -1
- package/dist/utils/recalculate-positions.js +5 -5
- package/dist/utils/recalculate-positions.js.map +1 -1
- package/dist/utils/recalculate-scrollable-ancestors.d.ts +1 -1
- package/dist/utils/recalculate-scrollable-ancestors.d.ts.map +1 -1
- package/dist/utils/recalculate-scrollable-ancestors.js +4 -4
- package/dist/utils/recalculate-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 +61 -0
- package/dist/utils/shadow-dom-aware-mutation-observer.js.map +1 -0
- package/dist/utils/supports-anchor-positioning.d.ts +1 -1
- package/dist/utils/supports-anchor-positioning.d.ts.map +1 -1
- package/dist/utils/supports-anchor-positioning.js +15 -2
- package/dist/utils/supports-anchor-positioning.js.map +1 -1
- package/dist/utils/transform-violations.d.ts +2 -2
- package/dist/utils/transform-violations.d.ts.map +1 -1
- package/dist/utils/transform-violations.js +25 -10
- package/dist/utils/transform-violations.js.map +1 -1
- package/dist/utils/update-elements-with-issues.d.ts +11 -5
- package/dist/utils/update-elements-with-issues.d.ts.map +1 -1
- package/dist/utils/update-elements-with-issues.js +56 -24
- package/dist/utils/update-elements-with-issues.js.map +1 -1
- package/dist/validate-options.d.ts +2 -2
- package/dist/validate-options.d.ts.map +1 -1
- package/dist/validate-options.js +91 -4
- package/dist/validate-options.js.map +1 -1
- package/package.json +16 -8
- package/src/accented.test.ts +2 -2
- package/src/accented.ts +45 -34
- package/src/common/strings.ts +2 -0
- package/src/common/tokens.ts +10 -0
- package/src/constants.ts +2 -1
- package/src/dom-updater.ts +87 -34
- package/src/elements/accented-dialog.ts +163 -123
- package/src/elements/accented-trigger.ts +128 -50
- package/src/fullscreen-listener.ts +21 -0
- package/src/intersection-observer.ts +27 -16
- package/src/log-and-rethrow.ts +2 -3
- package/src/logger.ts +14 -4
- package/src/register-elements.ts +7 -7
- package/src/resize-listener.ts +15 -11
- package/src/scanner.ts +113 -57
- package/src/scroll-listeners.ts +27 -19
- package/src/state.ts +27 -16
- package/src/task-queue.test.ts +5 -4
- package/src/task-queue.ts +8 -6
- package/src/types.ts +179 -76
- package/src/utils/are-elements-with-issues-equal.ts +11 -0
- package/src/utils/are-issue-sets-equal.test.ts +6 -7
- package/src/utils/are-issue-sets-equal.ts +8 -6
- package/src/utils/containing-blocks.ts +60 -0
- package/src/utils/contains.test.ts +54 -0
- package/src/utils/contains.ts +19 -0
- package/src/utils/deduplicate-nodes.ts +3 -0
- package/src/utils/deep-merge.test.ts +8 -1
- package/src/utils/deep-merge.ts +14 -8
- package/src/utils/dom-helpers.ts +42 -0
- package/src/utils/ensure-non-empty.ts +6 -0
- package/src/utils/get-element-html.ts +4 -2
- package/src/utils/get-element-position.ts +84 -16
- package/src/utils/get-parent.ts +14 -0
- package/src/utils/get-scan-context.test.ts +85 -0
- package/src/utils/get-scan-context.ts +36 -0
- package/src/utils/get-scrollable-ancestors.ts +15 -7
- 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/is-non-empty.ts +3 -0
- package/src/utils/normalize-context.test.ts +105 -0
- package/src/utils/normalize-context.ts +65 -0
- package/src/utils/recalculate-positions.ts +5 -5
- package/src/utils/recalculate-scrollable-ancestors.ts +4 -4
- package/src/utils/shadow-dom-aware-mutation-observer.ts +75 -0
- package/src/utils/supports-anchor-positioning.ts +19 -3
- package/src/utils/transform-violations.test.ts +29 -25
- package/src/utils/transform-violations.ts +32 -12
- package/src/utils/update-elements-with-issues.test.ts +145 -53
- package/src/utils/update-elements-with-issues.ts +123 -54
- package/src/validate-options.ts +154 -14
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { AccentedDialog } from './accented-dialog';
|
|
2
|
-
import type { Position } from '../types';
|
|
3
|
-
import { effect } from '@preact/signals-core';
|
|
4
1
|
import type { Signal } from '@preact/signals-core';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
2
|
+
import { effect } from '@preact/signals-core';
|
|
3
|
+
import { fontSystemSans } from '../common/tokens.js';
|
|
4
|
+
import { logAndRethrow } from '../log-and-rethrow.js';
|
|
5
|
+
import type { Position } from '../types.ts';
|
|
6
|
+
import { supportsAnchorPositioning } from '../utils/supports-anchor-positioning.js';
|
|
7
|
+
import type { AccentedDialog } from './accented-dialog.ts';
|
|
7
8
|
|
|
8
9
|
export interface AccentedTrigger extends HTMLElement {
|
|
9
10
|
element: Element | undefined;
|
|
@@ -12,11 +13,9 @@ export interface AccentedTrigger extends HTMLElement {
|
|
|
12
13
|
visible: Signal<boolean> | undefined;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
const triggerSize = 'max(32px, 2rem)';
|
|
16
|
-
|
|
17
16
|
// We want Accented to not throw an error in Node, and use static imports,
|
|
18
17
|
// so we can't export `class extends HTMLElement` because HTMLElement is not available in Node.
|
|
19
|
-
export
|
|
18
|
+
export const getAccentedTrigger = (name: string) => {
|
|
20
19
|
const template = document.createElement('template');
|
|
21
20
|
|
|
22
21
|
// I initially tried creating a CSSStyelSheet object with styles instead of having a <style> element in the template,
|
|
@@ -27,21 +26,44 @@ export default (name: string) => {
|
|
|
27
26
|
template.innerHTML = `
|
|
28
27
|
<style>
|
|
29
28
|
:host {
|
|
29
|
+
--ratio: 1.2;
|
|
30
|
+
--base-size: max(1rem, 16px);
|
|
30
31
|
position: fixed !important;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
${
|
|
33
|
+
supportsAnchorPositioning(window)
|
|
34
|
+
? `
|
|
35
|
+
inset-inline-start: anchor(self-start) !important;
|
|
36
|
+
inset-inline-end: anchor(self-end) !important;
|
|
37
|
+
inset-block-start: anchor(self-start) !important;
|
|
38
|
+
inset-block-end: anchor(self-end) !important;
|
|
39
|
+
`
|
|
40
|
+
: ''
|
|
41
|
+
}
|
|
35
42
|
|
|
36
43
|
/* Revert potential effects of white-space: pre; set on a trigger's ancestor. */
|
|
37
44
|
white-space: normal !important;
|
|
45
|
+
|
|
46
|
+
pointer-events: none !important;
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
#trigger {
|
|
50
|
+
pointer-events: auto;
|
|
51
|
+
|
|
52
|
+
user-select: none;
|
|
53
|
+
|
|
54
|
+
margin-inline-start: auto;
|
|
55
|
+
margin-inline-end: 4px;
|
|
56
|
+
margin-block-start: 4px;
|
|
57
|
+
|
|
41
58
|
box-sizing: border-box;
|
|
42
|
-
font-
|
|
43
|
-
|
|
44
|
-
|
|
59
|
+
font-family: ${fontSystemSans};
|
|
60
|
+
font-size: calc(var(--ratio) * var(--ratio) * var(--base-size));
|
|
61
|
+
inline-size: calc(2 * var(--base-size));
|
|
62
|
+
block-size: calc(2 * var(--base-size));
|
|
63
|
+
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: center;
|
|
45
67
|
|
|
46
68
|
/* Make it look better in forced-colors mode. */
|
|
47
69
|
border: 2px solid transparent;
|
|
@@ -49,6 +71,10 @@ export default (name: string) => {
|
|
|
49
71
|
background-color: var(--${name}-primary-color);
|
|
50
72
|
color: var(--${name}-secondary-color);
|
|
51
73
|
|
|
74
|
+
padding: 0;
|
|
75
|
+
|
|
76
|
+
border-radius: calc(0.25 * var(--base-size));
|
|
77
|
+
|
|
52
78
|
outline-offset: -4px;
|
|
53
79
|
outline-color: currentColor;
|
|
54
80
|
outline-width: 2px;
|
|
@@ -58,12 +84,13 @@ export default (name: string) => {
|
|
|
58
84
|
outline-style: solid;
|
|
59
85
|
}
|
|
60
86
|
|
|
87
|
+
/* We should probably be comfortable with showing these styles on non-hover devices. */
|
|
61
88
|
&:hover:not(:focus-visible) {
|
|
62
89
|
outline-style: dashed;
|
|
63
90
|
}
|
|
64
91
|
}
|
|
65
92
|
</style>
|
|
66
|
-
<button id="trigger" lang="en"
|
|
93
|
+
<button id="trigger" lang="en">á</button>
|
|
67
94
|
`;
|
|
68
95
|
|
|
69
96
|
return class extends HTMLElement implements AccentedTrigger {
|
|
@@ -75,6 +102,8 @@ export default (name: string) => {
|
|
|
75
102
|
|
|
76
103
|
#disposeOfVisibilityEffect: (() => void) | undefined;
|
|
77
104
|
|
|
105
|
+
#elementMutationObserver: MutationObserver | undefined;
|
|
106
|
+
|
|
78
107
|
element: Element | undefined;
|
|
79
108
|
|
|
80
109
|
dialog: AccentedDialog | undefined;
|
|
@@ -84,8 +113,8 @@ export default (name: string) => {
|
|
|
84
113
|
visible: Signal<boolean> | undefined;
|
|
85
114
|
|
|
86
115
|
constructor() {
|
|
116
|
+
super();
|
|
87
117
|
try {
|
|
88
|
-
super();
|
|
89
118
|
this.attachShadow({ mode: 'open' });
|
|
90
119
|
const content = template.content.cloneNode(true);
|
|
91
120
|
if (this.shadowRoot) {
|
|
@@ -104,50 +133,82 @@ export default (name: string) => {
|
|
|
104
133
|
if (trigger && this.element) {
|
|
105
134
|
trigger.ariaLabel = `Accessibility issues in ${this.element.nodeName.toLowerCase()}`;
|
|
106
135
|
}
|
|
107
|
-
|
|
108
|
-
|
|
136
|
+
|
|
137
|
+
this.#setTransform();
|
|
138
|
+
|
|
139
|
+
this.#elementMutationObserver = new MutationObserver(() => {
|
|
109
140
|
try {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// We append the dialog when the button is clicked,
|
|
113
|
-
// and remove it from the DOM when the dialog is closed.
|
|
114
|
-
// This gives us a performance improvement since Axe
|
|
115
|
-
// scan time seems to depend on the number of elements in the DOM.
|
|
116
|
-
if (this.dialog) {
|
|
117
|
-
this.#dialogCloseAbortController = new AbortController();
|
|
118
|
-
document.body.append(this.dialog);
|
|
119
|
-
this.dialog.showModal();
|
|
120
|
-
this.dialog.addEventListener('close', () => {
|
|
121
|
-
try {
|
|
122
|
-
this.dialog?.remove();
|
|
123
|
-
this.#dialogCloseAbortController?.abort();
|
|
124
|
-
} catch (error) {
|
|
125
|
-
logAndRethrow(error);
|
|
126
|
-
}
|
|
127
|
-
}, { signal: this.#dialogCloseAbortController.signal });
|
|
128
|
-
}
|
|
141
|
+
this.#setTransform();
|
|
129
142
|
} catch (error) {
|
|
130
143
|
logAndRethrow(error);
|
|
131
144
|
}
|
|
132
|
-
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
if (this.element) {
|
|
148
|
+
this.#elementMutationObserver.observe(this.element, {
|
|
149
|
+
attributes: true,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.#abortController = new AbortController();
|
|
154
|
+
trigger?.addEventListener(
|
|
155
|
+
'click',
|
|
156
|
+
(event) => {
|
|
157
|
+
try {
|
|
158
|
+
// event.preventDefault() ensures that if the issue is within a link,
|
|
159
|
+
// the link's default behavior (following the URL) is prevented.
|
|
160
|
+
event.preventDefault();
|
|
161
|
+
|
|
162
|
+
// event.stopPropagation() ensures that if there's a click handler on the trigger's ancestor
|
|
163
|
+
// (a link, or a button, or anything else), it doesn't get triggered.
|
|
164
|
+
event.stopPropagation();
|
|
165
|
+
|
|
166
|
+
// We append the dialog when the button is clicked,
|
|
167
|
+
// and remove it from the DOM when the dialog is closed.
|
|
168
|
+
// This gives us a performance improvement since Axe
|
|
169
|
+
// scan time seems to depend on the number of elements in the DOM.
|
|
170
|
+
if (this.dialog) {
|
|
171
|
+
this.#dialogCloseAbortController = new AbortController();
|
|
172
|
+
document.body.append(this.dialog);
|
|
173
|
+
this.dialog.showModal();
|
|
174
|
+
this.dialog.addEventListener(
|
|
175
|
+
'close',
|
|
176
|
+
() => {
|
|
177
|
+
try {
|
|
178
|
+
this.dialog?.remove();
|
|
179
|
+
this.#dialogCloseAbortController?.abort();
|
|
180
|
+
} catch (error) {
|
|
181
|
+
logAndRethrow(error);
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
{ signal: this.#dialogCloseAbortController.signal },
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
logAndRethrow(error);
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
{ signal: this.#abortController.signal },
|
|
192
|
+
);
|
|
133
193
|
|
|
134
194
|
if (!supportsAnchorPositioning(window)) {
|
|
135
195
|
this.#disposeOfPositionEffect = effect(() => {
|
|
136
196
|
if (this.position && trigger) {
|
|
137
197
|
const position = this.position.value;
|
|
138
|
-
this.style.setProperty('top', `${position.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
this.style.setProperty('left', `${position.inlineEndLeft}px`, 'important');
|
|
143
|
-
}
|
|
198
|
+
this.style.setProperty('top', `${position.top}px`, 'important');
|
|
199
|
+
this.style.setProperty('left', `${position.left}px`, 'important');
|
|
200
|
+
this.style.setProperty('width', `${position.width}px`, 'important');
|
|
201
|
+
this.style.setProperty('height', `${position.height}px`, 'important');
|
|
144
202
|
}
|
|
145
203
|
});
|
|
146
|
-
|
|
147
|
-
this.#disposeOfVisibilityEffect = effect(() => {
|
|
148
|
-
this.style.setProperty('visibility', this.visible?.value ? 'visible' : 'hidden', 'important');
|
|
149
|
-
});
|
|
150
204
|
}
|
|
205
|
+
this.#disposeOfVisibilityEffect = effect(() => {
|
|
206
|
+
this.style.setProperty(
|
|
207
|
+
'visibility',
|
|
208
|
+
this.visible?.value ? 'visible' : 'hidden',
|
|
209
|
+
'important',
|
|
210
|
+
);
|
|
211
|
+
});
|
|
151
212
|
}
|
|
152
213
|
} catch (error) {
|
|
153
214
|
logAndRethrow(error);
|
|
@@ -159,7 +220,7 @@ export default (name: string) => {
|
|
|
159
220
|
if (this.#abortController) {
|
|
160
221
|
this.#abortController.abort();
|
|
161
222
|
}
|
|
162
|
-
if (this.#dialogCloseAbortController) {
|
|
223
|
+
if (this.#dialogCloseAbortController && !this.dialog?.open) {
|
|
163
224
|
this.#dialogCloseAbortController.abort();
|
|
164
225
|
this.dialog?.remove();
|
|
165
226
|
}
|
|
@@ -171,9 +232,26 @@ export default (name: string) => {
|
|
|
171
232
|
this.#disposeOfVisibilityEffect();
|
|
172
233
|
this.#disposeOfVisibilityEffect = undefined;
|
|
173
234
|
}
|
|
235
|
+
if (this.#elementMutationObserver) {
|
|
236
|
+
this.#elementMutationObserver.disconnect();
|
|
237
|
+
}
|
|
174
238
|
} catch (error) {
|
|
175
239
|
logAndRethrow(error);
|
|
176
240
|
}
|
|
177
241
|
}
|
|
242
|
+
|
|
243
|
+
#setTransform() {
|
|
244
|
+
// We read and write values in separate animation frames to avoid layout thrashing.
|
|
245
|
+
window.requestAnimationFrame(() => {
|
|
246
|
+
if (this.element) {
|
|
247
|
+
const transform = window.getComputedStyle(this.element).getPropertyValue('transform');
|
|
248
|
+
if (transform !== 'none') {
|
|
249
|
+
window.requestAnimationFrame(() => {
|
|
250
|
+
this.style.setProperty('transform', transform, 'important');
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
178
256
|
};
|
|
179
257
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { logAndRethrow } from './log-and-rethrow.js';
|
|
2
|
+
import { recalculatePositions } from './utils/recalculate-positions.js';
|
|
3
|
+
|
|
4
|
+
export function setupResizeListener() {
|
|
5
|
+
const abortController = new AbortController();
|
|
6
|
+
window.addEventListener(
|
|
7
|
+
'fullscreenchange',
|
|
8
|
+
() => {
|
|
9
|
+
try {
|
|
10
|
+
recalculatePositions();
|
|
11
|
+
} catch (error) {
|
|
12
|
+
logAndRethrow(error);
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
{ signal: abortController.signal },
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
return () => {
|
|
19
|
+
abortController.abort();
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -1,28 +1,39 @@
|
|
|
1
|
-
import logAndRethrow from './log-and-rethrow.js';
|
|
1
|
+
import { logAndRethrow } from './log-and-rethrow.js';
|
|
2
2
|
import { extendedElementsWithIssues } from './state.js';
|
|
3
|
-
import getElementPosition from './utils/get-element-position.js';
|
|
3
|
+
import { getElementPosition } from './utils/get-element-position.js';
|
|
4
|
+
import { supportsAnchorPositioning } from './utils/supports-anchor-positioning.js';
|
|
4
5
|
|
|
5
|
-
export
|
|
6
|
-
const intersectionObserver = new IntersectionObserver(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
export function setupIntersectionObserver() {
|
|
7
|
+
const intersectionObserver = new IntersectionObserver(
|
|
8
|
+
(entries) => {
|
|
9
|
+
try {
|
|
10
|
+
for (const entry of entries) {
|
|
11
|
+
const extendedElementWithIssues = extendedElementsWithIssues.value.find(
|
|
12
|
+
(el) => el.element === entry.target,
|
|
13
|
+
);
|
|
14
|
+
if (extendedElementWithIssues) {
|
|
15
|
+
// We initially treated setting visibility in the intersection observer
|
|
16
|
+
// as a fallback option for browsers that don't support `position-visibility`,
|
|
17
|
+
// but then we realized that this `position-visibility` actually works
|
|
18
|
+
// in an unexpected way when the container has `overflow: visible`.
|
|
19
|
+
// So now we always set visibility in the intersection observer.
|
|
20
|
+
extendedElementWithIssues.visible.value = entry.isIntersecting;
|
|
21
|
+
if (entry.isIntersecting && !supportsAnchorPositioning(window)) {
|
|
22
|
+
extendedElementWithIssues.position.value = getElementPosition(entry.target, window);
|
|
23
|
+
}
|
|
14
24
|
}
|
|
15
25
|
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
logAndRethrow(error);
|
|
16
28
|
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}, { threshold: 0 });
|
|
29
|
+
},
|
|
30
|
+
{ threshold: 0 },
|
|
31
|
+
);
|
|
21
32
|
|
|
22
33
|
return {
|
|
23
34
|
intersectionObserver,
|
|
24
35
|
disconnect: () => {
|
|
25
36
|
intersectionObserver.disconnect();
|
|
26
|
-
}
|
|
37
|
+
},
|
|
27
38
|
};
|
|
28
39
|
}
|
package/src/log-and-rethrow.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { issuesUrl } from './constants.js';
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export function logAndRethrow(error: unknown) {
|
|
4
4
|
console.error(
|
|
5
|
-
`Accented threw an error (see below). Try updating your browser to the latest version.
|
|
6
|
-
`If you’re still seeing the error, file an issue at ${issuesUrl}.`
|
|
5
|
+
`Accented threw an error (see below). Try updating your browser to the latest version. If you’re still seeing the error, file an issue at ${issuesUrl}.`,
|
|
7
6
|
);
|
|
8
7
|
throw error;
|
|
9
8
|
}
|
package/src/logger.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { effect } from '@preact/signals-core';
|
|
2
|
-
import { elementsWithIssues, enabled } from './state.js';
|
|
3
2
|
import { accentedUrl } from './constants.js';
|
|
3
|
+
import { elementsWithIssues, enabled } from './state.js';
|
|
4
|
+
import type { ElementWithIssues } from './types.ts';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
function filterPropsForOutput(elements: Array<ElementWithIssues>) {
|
|
7
|
+
return elements.map(({ element, issues }) => ({ element, issues }));
|
|
8
|
+
}
|
|
6
9
|
|
|
10
|
+
export function createLogger() {
|
|
7
11
|
let firstRun = true;
|
|
8
12
|
|
|
9
13
|
return effect(() => {
|
|
@@ -13,8 +17,14 @@ export default function createLogger() {
|
|
|
13
17
|
|
|
14
18
|
const elementCount = elementsWithIssues.value.length;
|
|
15
19
|
if (elementCount > 0) {
|
|
16
|
-
const issueCount = elementsWithIssues.value.reduce(
|
|
17
|
-
|
|
20
|
+
const issueCount = elementsWithIssues.value.reduce(
|
|
21
|
+
(acc, { issues }) => acc + issues.length,
|
|
22
|
+
0,
|
|
23
|
+
);
|
|
24
|
+
console.log(
|
|
25
|
+
`${issueCount} accessibility issue${issueCount === 1 ? '' : 's'} found in ${elementCount} element${issueCount === 1 ? '' : 's'} (Accented, ${accentedUrl}):\n`,
|
|
26
|
+
filterPropsForOutput(elementsWithIssues.value),
|
|
27
|
+
);
|
|
18
28
|
} else {
|
|
19
29
|
if (firstRun) {
|
|
20
30
|
firstRun = false;
|
package/src/register-elements.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { getAccentedDialog } from './elements/accented-dialog.js';
|
|
2
|
+
import { getAccentedTrigger } from './elements/accented-trigger.js';
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export function registerElements(name: string): void {
|
|
5
5
|
const elements = [
|
|
6
6
|
{
|
|
7
7
|
elementName: `${name}-trigger`,
|
|
8
|
-
Component: getAccentedTrigger(name)
|
|
8
|
+
Component: getAccentedTrigger(name),
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
elementName: `${name}-dialog`,
|
|
12
|
-
Component: getAccentedDialog()
|
|
13
|
-
}
|
|
12
|
+
Component: getAccentedDialog(),
|
|
13
|
+
},
|
|
14
14
|
];
|
|
15
15
|
|
|
16
16
|
for (const { elementName, Component } of elements) {
|
|
@@ -18,4 +18,4 @@ export default function registerElements(name: string): void {
|
|
|
18
18
|
customElements.define(elementName, Component);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
}
|
|
21
|
+
}
|
package/src/resize-listener.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import logAndRethrow from './log-and-rethrow.js';
|
|
2
|
-
import recalculatePositions from './utils/recalculate-positions.js';
|
|
1
|
+
import { logAndRethrow } from './log-and-rethrow.js';
|
|
2
|
+
import { recalculatePositions } from './utils/recalculate-positions.js';
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export function setupResizeListener() {
|
|
5
5
|
const abortController = new AbortController();
|
|
6
|
-
window.addEventListener(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
window.addEventListener(
|
|
7
|
+
'resize',
|
|
8
|
+
() => {
|
|
9
|
+
try {
|
|
10
|
+
recalculatePositions();
|
|
11
|
+
} catch (error) {
|
|
12
|
+
logAndRethrow(error);
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
{ signal: abortController.signal },
|
|
16
|
+
);
|
|
13
17
|
|
|
14
18
|
return () => {
|
|
15
19
|
abortController.abort();
|
|
16
20
|
};
|
|
17
|
-
}
|
|
21
|
+
}
|