@issuegraph/editor 0.4.0 → 0.10.0
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 +31 -6
- package/dist/a11y/baseline.d.ts +182 -0
- package/dist/a11y/baseline.d.ts.map +1 -0
- package/dist/a11y/baseline.js +430 -0
- package/dist/a11y/baseline.js.map +1 -0
- package/dist/audit/styles.d.ts +1 -1
- package/dist/audit/styles.d.ts.map +1 -1
- package/dist/audit/styles.js +1 -1
- package/dist/create/draft.d.ts +17 -0
- package/dist/create/draft.d.ts.map +1 -1
- package/dist/create/draft.js +19 -0
- package/dist/create/draft.js.map +1 -1
- package/dist/create/keys.d.ts +70 -5
- package/dist/create/keys.d.ts.map +1 -1
- package/dist/create/keys.js +78 -17
- package/dist/create/keys.js.map +1 -1
- package/dist/firstpass/candidates.d.ts +17 -1
- package/dist/firstpass/candidates.d.ts.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/overlay/render.d.ts.map +1 -1
- package/dist/overlay/render.js +54 -14
- package/dist/overlay/render.js.map +1 -1
- package/dist/overlay/styles.d.ts +1 -1
- package/dist/overlay/styles.d.ts.map +1 -1
- package/dist/overlay/styles.js +40 -0
- package/dist/overlay/styles.js.map +1 -1
- package/dist/picker/render.d.ts +26 -16
- package/dist/picker/render.d.ts.map +1 -1
- package/dist/picker/render.js +25 -36
- package/dist/picker/render.js.map +1 -1
- package/dist/picker/styles.d.ts +7 -7
- package/dist/picker/styles.d.ts.map +1 -1
- package/dist/picker/styles.js +7 -36
- package/dist/picker/styles.js.map +1 -1
- package/dist/picker/view.d.ts +8 -4
- package/dist/picker/view.d.ts.map +1 -1
- package/dist/picker/view.js +4 -3
- package/dist/picker/view.js.map +1 -1
- package/dist/picker/words.d.ts +12 -10
- package/dist/picker/words.d.ts.map +1 -1
- package/dist/picker/words.js +12 -8
- package/dist/picker/words.js.map +1 -1
- package/dist/scale/ladder.d.ts.map +1 -1
- package/dist/scale/ladder.js +10 -3
- package/dist/scale/ladder.js.map +1 -1
- package/dist/scale/render.d.ts.map +1 -1
- package/dist/scale/render.js +9 -1
- package/dist/scale/render.js.map +1 -1
- package/dist/workspace/chrome.d.ts +1 -1
- package/dist/workspace/chrome.d.ts.map +1 -1
- package/dist/workspace/chrome.js +48 -0
- package/dist/workspace/chrome.js.map +1 -1
- package/dist/workspace/firstpass.d.ts +166 -0
- package/dist/workspace/firstpass.d.ts.map +1 -0
- package/dist/workspace/firstpass.js +151 -0
- package/dist/workspace/firstpass.js.map +1 -0
- package/dist/workspace/host.d.ts +200 -10
- package/dist/workspace/host.d.ts.map +1 -1
- package/dist/workspace/host.js +420 -42
- package/dist/workspace/host.js.map +1 -1
- package/dist/workspace/inspector.d.ts +45 -1
- package/dist/workspace/inspector.d.ts.map +1 -1
- package/dist/workspace/inspector.js +11 -0
- package/dist/workspace/inspector.js.map +1 -1
- package/dist/workspace/mount.d.ts +52 -5
- package/dist/workspace/mount.d.ts.map +1 -1
- package/dist/workspace/mount.js +1366 -58
- package/dist/workspace/mount.js.map +1 -1
- package/dist/workspace/recovery.d.ts +155 -0
- package/dist/workspace/recovery.d.ts.map +1 -0
- package/dist/workspace/recovery.js +156 -0
- package/dist/workspace/recovery.js.map +1 -0
- package/dist/workspace/render.d.ts +402 -1
- package/dist/workspace/render.d.ts.map +1 -1
- package/dist/workspace/render.js +941 -35
- package/dist/workspace/render.js.map +1 -1
- package/dist/workspace/styles.d.ts +1 -1
- package/dist/workspace/styles.d.ts.map +1 -1
- package/dist/workspace/styles.js +554 -41
- package/dist/workspace/styles.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The accessible contract of every command control, read off a rendered
|
|
3
|
+
* surface — so it is committed as an artifact rather than asserted in prose.
|
|
4
|
+
*
|
|
5
|
+
* ## Why a DOM node and not an `ElementSpec`
|
|
6
|
+
*
|
|
7
|
+
* There is no spec tree for the workspace to walk. `renderWorkspace` returns
|
|
8
|
+
* `markup: string`; it composes its four zones by joining independently
|
|
9
|
+
* rendered strings, the `data-zone` wrapper is the one tag written by hand in
|
|
10
|
+
* that file, and every `…Spec` builder is module-private. Worse for a spec
|
|
11
|
+
* walk, a substantial part of the interactive surface never passes a renderer
|
|
12
|
+
* at all — `mountWorkspace` builds the kind chooser, the target search and its
|
|
13
|
+
* match list with `createElement`, and says so ("WHAT IS LEFT HERE IS WHAT
|
|
14
|
+
* NEEDS A DOM"). A baseline taken over specs would silently omit exactly the
|
|
15
|
+
* keyboard-relevant controls.
|
|
16
|
+
*
|
|
17
|
+
* The rendered DOM has all of it, and it is also what a screen reader actually
|
|
18
|
+
* meets.
|
|
19
|
+
*
|
|
20
|
+
* ## NOT EXPORTED, and that is the correction of a real mistake
|
|
21
|
+
*
|
|
22
|
+
* An earlier revision published `controlSurface` on the package surface,
|
|
23
|
+
* reasoning that a host composing these zones into its own chrome would want
|
|
24
|
+
* the same record. Nothing asked for it, and `index.ts` states the rule it
|
|
25
|
+
* broke: "a published package can add an export later and can never take one
|
|
26
|
+
* back, so nothing is exported before something is owed."
|
|
27
|
+
*
|
|
28
|
+
* The cost was not theoretical. Exporting it turned this file into a
|
|
29
|
+
* general-purpose accessible-name and focusability reader, and accessible-name
|
|
30
|
+
* computation has a long tail — `title`, `placeholder`, an input's own `value`,
|
|
31
|
+
* whitespace-only labels, hidden inputs, `contenteditable`. Three consecutive
|
|
32
|
+
* review rounds produced findings of exactly that shape: each real, each cheap,
|
|
33
|
+
* and none about markup this package draws. That tail has no end, and this
|
|
34
|
+
* change cannot discharge it.
|
|
35
|
+
*
|
|
36
|
+
* Internal, the obligation is bounded and discharged: the reader only ever
|
|
37
|
+
* meets what this package renders, which is a closed set recorded in six
|
|
38
|
+
* states. If a host ever owes this, export it then — with its tail addressed,
|
|
39
|
+
* and against a consumer that actually needs it.
|
|
40
|
+
*
|
|
41
|
+
* ## Structurally typed, so this module still touches no global
|
|
42
|
+
*
|
|
43
|
+
* {@link SurfaceElement} is declared by what it must answer rather than as
|
|
44
|
+
* `Element`, which is `element.ts`'s own `SpecDocument` idiom — "declared
|
|
45
|
+
* structurally rather than as `Document` so a host can pass any implementation
|
|
46
|
+
* that answers these five calls, and so this module stays honest about how
|
|
47
|
+
* little of the DOM it actually needs". `purity.test.ts` imports every shipped
|
|
48
|
+
* module with the browser globals removed; nothing here reaches for one.
|
|
49
|
+
*
|
|
50
|
+
* ## What is recorded, and what is deliberately not
|
|
51
|
+
*
|
|
52
|
+
* VALUES ARE KEPT FOR MACHINE STATES AND DROPPED FOR HUMAN-READABLE NAMES.
|
|
53
|
+
* That split is by provenance, not one blanket rule, because the two fail
|
|
54
|
+
* differently. `aria-pressed` is rendered as `cond ? 'true' : 'false'`, so a
|
|
55
|
+
* baseline holding only the attribute NAME is byte-identical when a toggle
|
|
56
|
+
* inverts — the regression it exists to catch. A label, meanwhile, is often
|
|
57
|
+
* the host's word (`picker/words.ts`, `reevaluate/words.ts` and
|
|
58
|
+
* `firstpass/words.ts` all require a `Record<K, string>` from the host and
|
|
59
|
+
* default none), so pinning the string would fail any host that translated it.
|
|
60
|
+
*
|
|
61
|
+
* An earlier draft justified dropping every value with "the package ships no
|
|
62
|
+
* English", which is false: `scale/render.ts` writes `'connected components'`,
|
|
63
|
+
* `'what to do next'`, `'search matches'` and `'isolated issues'` itself, and
|
|
64
|
+
* the viewer ships more landmark names. The true, narrower claim is the one
|
|
65
|
+
* above.
|
|
66
|
+
*
|
|
67
|
+
* AN IDREF IS RECORDED BY WHETHER IT RESOLVES, never by its value. The
|
|
68
|
+
* disclosure's `aria-controls` names `diffRegionId(recovery.mutationId)`, and a
|
|
69
|
+
* mutation id is generated per run — pinning it would make the artifact churn
|
|
70
|
+
* on every render for no signal. What is worth pinning is the fact a reader
|
|
71
|
+
* depends on: that the id names a region that is actually there. A dangling
|
|
72
|
+
* `aria-controls` is a real defect and a stable one to record.
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* Every attribute a control publishes itself on.
|
|
76
|
+
*
|
|
77
|
+
* THREE CHANNELS, NOT ONE, and reading only the first is how a record comes to
|
|
78
|
+
* claim a surface it never saw. `data-ig-command` is the general one, but the
|
|
79
|
+
* first pass's y/n/s answers carry `data-ig-answer` and the audit header's
|
|
80
|
+
* toggle carries `data-ig-audit-filter` — `firstpass/render.ts` and
|
|
81
|
+
* `audit/surface.ts` each say so where they declare theirs. Keyed on the
|
|
82
|
+
* command alone, this would have recorded `null` for the audit toggle and for
|
|
83
|
+
* every answer, and the rules below would have skipped exactly the controls a
|
|
84
|
+
* keyboard reader depends on most.
|
|
85
|
+
*/
|
|
86
|
+
export const CONTROL_ATTRIBUTES = Object.freeze([
|
|
87
|
+
'data-ig-command',
|
|
88
|
+
'data-ig-answer',
|
|
89
|
+
'data-ig-audit-filter',
|
|
90
|
+
]);
|
|
91
|
+
/**
|
|
92
|
+
* Implicit roles, for the tags this package actually renders.
|
|
93
|
+
*
|
|
94
|
+
* Closed and small on purpose. A general HTML-AAM table would be a second
|
|
95
|
+
* implementation of a specification this package does not own, and every entry
|
|
96
|
+
* beyond what is rendered here would be untested. An unmapped tag records
|
|
97
|
+
* `null` rather than a guess — including everything in the SVG namespace,
|
|
98
|
+
* where the HTML implicit roles do not apply and `path` has none at all.
|
|
99
|
+
*/
|
|
100
|
+
const IMPLICIT_ROLES = Object.freeze({
|
|
101
|
+
button: 'button',
|
|
102
|
+
h1: 'heading',
|
|
103
|
+
h2: 'heading',
|
|
104
|
+
h3: 'heading',
|
|
105
|
+
h4: 'heading',
|
|
106
|
+
li: 'listitem',
|
|
107
|
+
ol: 'list',
|
|
108
|
+
ul: 'list',
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* The two tags whose implicit role depends on more than the tag.
|
|
112
|
+
*
|
|
113
|
+
* `a` is a `link` only with an `href` — without one it is not a link and not
|
|
114
|
+
* focusable. `section` is a `region` only when it has an accessible name;
|
|
115
|
+
* unnamed it exposes no role at all. Both were mapped unconditionally in an
|
|
116
|
+
* earlier revision, which recorded a role the accessibility tree does not have.
|
|
117
|
+
*/
|
|
118
|
+
/**
|
|
119
|
+
* `input`'s implicit role, which is its `type`'s rather than its tag's.
|
|
120
|
+
*
|
|
121
|
+
* The mounted target search is `<input type="search">` — `searchbox`, not
|
|
122
|
+
* nothing — and recording `null` for a control this package itself renders
|
|
123
|
+
* means the role column could not notice it being changed into a semantically
|
|
124
|
+
* different control. Only the types rendered here are mapped; the rest stay
|
|
125
|
+
* `null`, on the same rule as every other unmapped tag.
|
|
126
|
+
*/
|
|
127
|
+
const INPUT_ROLES = Object.freeze({
|
|
128
|
+
button: 'button',
|
|
129
|
+
checkbox: 'checkbox',
|
|
130
|
+
radio: 'radio',
|
|
131
|
+
reset: 'button',
|
|
132
|
+
search: 'searchbox',
|
|
133
|
+
submit: 'button',
|
|
134
|
+
text: 'textbox',
|
|
135
|
+
});
|
|
136
|
+
function conditionalRole(root, element, tag) {
|
|
137
|
+
if (tag === 'a')
|
|
138
|
+
return element.getAttribute('href') === null ? null : 'link';
|
|
139
|
+
if (tag === 'section')
|
|
140
|
+
return nameSource(root, element) === 'none' ? null : 'region';
|
|
141
|
+
// NO `type` IS `type="text"`, which is HTML's own default rather than an
|
|
142
|
+
// assumption: an `<input>` with no type is a text field.
|
|
143
|
+
if (tag === 'input')
|
|
144
|
+
return INPUT_ROLES[element.getAttribute('type') ?? 'text'] ?? null;
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
/** ARIA attributes whose value is drawn from a fixed set, so the value is data. */
|
|
148
|
+
const ENUMERATED_ARIA = Object.freeze([
|
|
149
|
+
'aria-busy',
|
|
150
|
+
'aria-checked',
|
|
151
|
+
'aria-current',
|
|
152
|
+
'aria-expanded',
|
|
153
|
+
'aria-hidden',
|
|
154
|
+
'aria-live',
|
|
155
|
+
'aria-modal',
|
|
156
|
+
'aria-pressed',
|
|
157
|
+
'aria-selected',
|
|
158
|
+
]);
|
|
159
|
+
/** ARIA attributes whose value is an id, recorded by whether it resolves. */
|
|
160
|
+
const IDREF_ARIA = Object.freeze([
|
|
161
|
+
'aria-controls',
|
|
162
|
+
'aria-describedby',
|
|
163
|
+
'aria-labelledby',
|
|
164
|
+
]);
|
|
165
|
+
const TEXT_NODE = 3;
|
|
166
|
+
function isElement(node) {
|
|
167
|
+
return 'tagName' in node;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The text a screen reader would announce for this element.
|
|
171
|
+
*
|
|
172
|
+
* SUBTREES MARKED `aria-hidden` CONTRIBUTE NOTHING, which is the case a naive
|
|
173
|
+
* "does it have a text child" test gets wrong. `parts.ts` renders a command
|
|
174
|
+
* button as a hidden glyph beside its label; delete the label and the button
|
|
175
|
+
* still has a text descendant while its accessible name is empty. That is a
|
|
176
|
+
* name loss no presence check would report.
|
|
177
|
+
*/
|
|
178
|
+
function visibleText(element) {
|
|
179
|
+
let out = '';
|
|
180
|
+
const walk = (node) => {
|
|
181
|
+
if (!isElement(node)) {
|
|
182
|
+
if (node.nodeType === TEXT_NODE)
|
|
183
|
+
out += node.nodeValue ?? '';
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
// `hidden` AS WELL AS `aria-hidden`, and for the same reason one step
|
|
187
|
+
// further along: a natively hidden subtree is not rendered at all, so its
|
|
188
|
+
// text reaches no reader. `<button><span hidden>Save</span></button>` is
|
|
189
|
+
// exposed with NO accessible name, and counting that text reported one —
|
|
190
|
+
// letting the naming rule pass on a control that announces nothing.
|
|
191
|
+
if (node.getAttribute('aria-hidden') === 'true')
|
|
192
|
+
return;
|
|
193
|
+
if (node.getAttribute('hidden') !== null)
|
|
194
|
+
return;
|
|
195
|
+
for (let index = 0; index < node.childNodes.length; index += 1) {
|
|
196
|
+
const child = node.childNodes[index];
|
|
197
|
+
if (child !== undefined)
|
|
198
|
+
walk(child);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
walk(element);
|
|
202
|
+
return out.trim();
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Whether a `<label>` names this control, by either association HTML defines.
|
|
206
|
+
*
|
|
207
|
+
* WRAPPING FIRST, then `for`. `scale/render.ts` uses the wrapping form and says
|
|
208
|
+
* why in as many words — two search boxes side by side with one `id` would make
|
|
209
|
+
* `for` resolve to whichever came first, so one would silently lose its label.
|
|
210
|
+
*
|
|
211
|
+
* THE `for` LOOKUP WALKS AND COMPARES rather than building `label[for="..."]`:
|
|
212
|
+
* an id is host data, and interpolating one into a selector is the injection
|
|
213
|
+
* this module already had to remove once.
|
|
214
|
+
*/
|
|
215
|
+
function labelNames(root, element) {
|
|
216
|
+
const wrapping = element.closest('label');
|
|
217
|
+
if (wrapping !== null && visibleText(wrapping) !== '')
|
|
218
|
+
return true;
|
|
219
|
+
const id = element.getAttribute('id');
|
|
220
|
+
if (id === null || id === '')
|
|
221
|
+
return false;
|
|
222
|
+
for (const label of root.querySelectorAll('label')) {
|
|
223
|
+
if (label.getAttribute('for') === id && visibleText(label) !== '')
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
function nameSource(root, element) {
|
|
229
|
+
// AN EMPTY VALUE IS NOT A NAME, and it is not the same as no attribute.
|
|
230
|
+
// `renderMarkup` omits only `undefined`, `null` and `false`, so
|
|
231
|
+
// `aria-label=""` does reach the markup — the case the "omitted, never empty"
|
|
232
|
+
// rule `holdLine` states for `data-code` exists to prevent.
|
|
233
|
+
// `aria-labelledby` FIRST, because accessible-name computation resolves it
|
|
234
|
+
// BEFORE `aria-label` — so a host supplying both, with the reference pointing
|
|
235
|
+
// at an empty element, is exposed with no name while a reader that took the
|
|
236
|
+
// label would have reported one. Order is the whole of the fix; each branch
|
|
237
|
+
// was already right on its own.
|
|
238
|
+
//
|
|
239
|
+
// AN IDREF THAT RESOLVES IS NOT YET A NAME. `aria-labelledby` naming an
|
|
240
|
+
// element that exists but carries no text computes to an empty accessible
|
|
241
|
+
// name, and reading the attribute alone reported a supplied name for a
|
|
242
|
+
// control that announces nothing. This is the same defect as `aria-label=""`,
|
|
243
|
+
// which is already answered `empty` — fixing one half and not the other
|
|
244
|
+
// would have left the rule inconsistent about the same mistake.
|
|
245
|
+
//
|
|
246
|
+
// `ariaOf` keeps answering `resolves` for the same attribute, and the two are
|
|
247
|
+
// not in conflict: it reports whether the reference POINTS at something,
|
|
248
|
+
// which is its own defect when it does not. Whether the thing it points at
|
|
249
|
+
// says anything is this function's question.
|
|
250
|
+
const labelledBy = element.getAttribute('aria-labelledby');
|
|
251
|
+
if (labelledBy !== null) {
|
|
252
|
+
const named = labelledBy.split(/\s+/).filter((token) => token !== '');
|
|
253
|
+
let text = '';
|
|
254
|
+
for (const target of root.querySelectorAll('[id]')) {
|
|
255
|
+
if (named.includes(target.getAttribute('id') ?? ''))
|
|
256
|
+
text += visibleText(target);
|
|
257
|
+
}
|
|
258
|
+
return text.trim() === '' ? 'empty' : 'aria-labelledby';
|
|
259
|
+
}
|
|
260
|
+
const label = element.getAttribute('aria-label');
|
|
261
|
+
// TRIMMED, because a name made of spaces is not a name: the browser exposes
|
|
262
|
+
// an empty accessible name for `aria-label=" "`, which a template padding an
|
|
263
|
+
// empty translation produces easily.
|
|
264
|
+
if (label !== null)
|
|
265
|
+
return label.trim() === '' ? 'empty' : 'aria-label';
|
|
266
|
+
if (visibleText(element) !== '')
|
|
267
|
+
return 'text';
|
|
268
|
+
return labelNames(root, element) ? 'label' : 'none';
|
|
269
|
+
}
|
|
270
|
+
function tabStopOf(element) {
|
|
271
|
+
// DISABLED AND INERT ARE NOT TAB STOPS, whatever the tag says. The mount sets
|
|
272
|
+
// `inert` on every zone while the first-pass overlay is up — "the zones go
|
|
273
|
+
// inert under it" — so without this every covered control recorded `tab` and
|
|
274
|
+
// passed a rule asserting the keyboard can reach it, while the browser was
|
|
275
|
+
// refusing focus to all of them.
|
|
276
|
+
if (element.getAttribute('disabled') !== null)
|
|
277
|
+
return 'none';
|
|
278
|
+
if (element.closest('[inert]') !== null)
|
|
279
|
+
return 'none';
|
|
280
|
+
// `hidden` TOO, and for the same reason: the browser takes a hidden subtree
|
|
281
|
+
// out of the tab order, so a native button inside one is not reachable
|
|
282
|
+
// however focusable its tag is. Nothing in this package renders it today —
|
|
283
|
+
// which is exactly why it is worth handling here rather than later, since
|
|
284
|
+
// `controlSurface` is exported for hosts to run over their own chrome.
|
|
285
|
+
if (element.closest('[hidden]') !== null)
|
|
286
|
+
return 'none';
|
|
287
|
+
const raw = element.getAttribute('tabindex');
|
|
288
|
+
if (raw === null) {
|
|
289
|
+
// NATIVELY IN THE TAB ORDER. `a` only with an `href`: without one it is not
|
|
290
|
+
// focusable, and recording it as a tab stop would claim a reachability the
|
|
291
|
+
// markup does not have.
|
|
292
|
+
const tag = element.tagName.toLowerCase();
|
|
293
|
+
if (tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea')
|
|
294
|
+
return 'tab';
|
|
295
|
+
return tag === 'a' && element.getAttribute('href') !== null ? 'tab' : 'none';
|
|
296
|
+
}
|
|
297
|
+
const index = Number(raw);
|
|
298
|
+
if (!Number.isInteger(index))
|
|
299
|
+
return 'none';
|
|
300
|
+
return index < 0 ? 'programmatic' : 'tab';
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Every id under `root`, gathered once.
|
|
304
|
+
*
|
|
305
|
+
* A SET RATHER THAN A QUERY PER TOKEN, and that is a correctness fix, not a
|
|
306
|
+
* speed one. An earlier revision resolved each IDREF with
|
|
307
|
+
* `` querySelectorAll(`[id="${id}"]`) `` — interpolating a value read off the
|
|
308
|
+
* DOM straight into a selector, which is verbatim the class the mount's focus
|
|
309
|
+
* token was written to avoid. Measured: `aria-describedby='a"]'` made this
|
|
310
|
+
* function THROW, and a token containing `],[id` resolved against the wrong
|
|
311
|
+
* elements. `controlSurface` is exported for hosts to run over their own
|
|
312
|
+
* chrome, where ids are tracker-derived, so the injection was reachable.
|
|
313
|
+
*
|
|
314
|
+
* SCOPED TO `root`, which is a real bound and is stated rather than hidden: an
|
|
315
|
+
* IDREF pointing into the host's own chrome outside the mounted surface reads
|
|
316
|
+
* as `dangling` here. That is the right default for a record ABOUT this
|
|
317
|
+
* surface, and a host taking it over its whole page gets the wider answer.
|
|
318
|
+
*/
|
|
319
|
+
function idsUnder(root) {
|
|
320
|
+
const ids = new Set();
|
|
321
|
+
// `root` ITSELF IS NOT IN ITS OWN `querySelectorAll`, so it is added by hand:
|
|
322
|
+
// a host may well hang the surface off an element that carries an id.
|
|
323
|
+
const own = root.getAttribute('id');
|
|
324
|
+
if (own !== null)
|
|
325
|
+
ids.add(own);
|
|
326
|
+
for (const element of root.querySelectorAll('[id]')) {
|
|
327
|
+
const id = element.getAttribute('id');
|
|
328
|
+
if (id !== null)
|
|
329
|
+
ids.add(id);
|
|
330
|
+
}
|
|
331
|
+
return ids;
|
|
332
|
+
}
|
|
333
|
+
function ariaOf(ids, element) {
|
|
334
|
+
const out = {};
|
|
335
|
+
for (const attribute of ENUMERATED_ARIA) {
|
|
336
|
+
const value = element.getAttribute(attribute);
|
|
337
|
+
if (value !== null)
|
|
338
|
+
out[attribute] = value;
|
|
339
|
+
}
|
|
340
|
+
// `aria-hidden` IS INHERITED, and the rule that reads it is about exactly
|
|
341
|
+
// that. A wrapper carrying it takes its descendants out of the accessibility
|
|
342
|
+
// tree WITHOUT taking them out of the tab order — which is the "focusable and
|
|
343
|
+
// announces nothing" case the rule exists to reject. Read off the element
|
|
344
|
+
// alone, the rule could not see the shape it was written for: the entry
|
|
345
|
+
// carried no `aria-hidden` at all and passed.
|
|
346
|
+
//
|
|
347
|
+
// The other enumerated states are properties of the element that carries
|
|
348
|
+
// them, so only this one is resolved through ancestry.
|
|
349
|
+
if (element.closest('[aria-hidden="true"]') !== null)
|
|
350
|
+
out['aria-hidden'] = 'true';
|
|
351
|
+
for (const attribute of IDREF_ARIA) {
|
|
352
|
+
const value = element.getAttribute(attribute);
|
|
353
|
+
if (value === null)
|
|
354
|
+
continue;
|
|
355
|
+
// EVERY id IT NAMES, because the attribute takes a list and a half-resolved
|
|
356
|
+
// reference is still broken for the token that dangles.
|
|
357
|
+
const named = value.split(/\s+/).filter((token) => token !== '');
|
|
358
|
+
out[attribute] =
|
|
359
|
+
named.length > 0 && named.every((id) => ids.has(id)) ? 'resolves' : 'dangling';
|
|
360
|
+
}
|
|
361
|
+
return out;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Every control under `root`, in document order, sorted so the record is stable.
|
|
365
|
+
*
|
|
366
|
+
* Pure and total. SORTED RATHER THAN LEFT IN DOCUMENT ORDER: a baseline is
|
|
367
|
+
* diffed by people, and a control moving between zones should read as one
|
|
368
|
+
* changed line rather than as a reordering of the whole file. Document order is
|
|
369
|
+
* a fact about layout, which the zone already carries.
|
|
370
|
+
*
|
|
371
|
+
* The bound it does NOT cover is stated where it can be checked: a control
|
|
372
|
+
* publishing itself on some fourth attribute is invisible here, and
|
|
373
|
+
* {@link CONTROL_ATTRIBUTES} is the list to extend.
|
|
374
|
+
*/
|
|
375
|
+
export function controlSurface(root) {
|
|
376
|
+
const entries = [];
|
|
377
|
+
const seen = new Set();
|
|
378
|
+
const ids = idsUnder(root);
|
|
379
|
+
for (const channel of CONTROL_ATTRIBUTES) {
|
|
380
|
+
for (const element of root.querySelectorAll(`[${channel}]`)) {
|
|
381
|
+
const control = element.getAttribute(channel);
|
|
382
|
+
// ONE ENTRY PER ELEMENT, even where a control carries two channels: the
|
|
383
|
+
// record is about the control, and a second row for one button would
|
|
384
|
+
// make every rule below count it twice.
|
|
385
|
+
if (control === null || seen.has(element))
|
|
386
|
+
continue;
|
|
387
|
+
seen.add(element);
|
|
388
|
+
const tag = element.tagName.toLowerCase();
|
|
389
|
+
entries.push({
|
|
390
|
+
zone: element.closest('.ig-zone')?.getAttribute('data-zone') ?? null,
|
|
391
|
+
channel,
|
|
392
|
+
control,
|
|
393
|
+
target: element.getAttribute('data-ig-target'),
|
|
394
|
+
value: element.getAttribute('data-ig-value') ?? element.getAttribute('data-ig-kind'),
|
|
395
|
+
tag,
|
|
396
|
+
role: element.getAttribute('role') ??
|
|
397
|
+
IMPLICIT_ROLES[tag] ??
|
|
398
|
+
conditionalRole(root, element, tag),
|
|
399
|
+
tabStop: tabStopOf(element),
|
|
400
|
+
inert: element.closest('[inert]') !== null,
|
|
401
|
+
name: nameSource(root, element),
|
|
402
|
+
aria: ariaOf(ids, element),
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
// FIELD BY FIELD, BY CODE POINT. `localeCompare` was both non-total and
|
|
407
|
+
// machine-dependent here: it treats `\u0000` as ignorable, so the separator
|
|
408
|
+
// bought nothing and distinct keys compared EQUAL, and with no locale it
|
|
409
|
+
// follows the runner's own ICU build — which would reorder a committed
|
|
410
|
+
// artifact that is compared with an order-sensitive `deepEqual`.
|
|
411
|
+
const key = (entry) => [
|
|
412
|
+
entry.zone ?? '',
|
|
413
|
+
entry.channel,
|
|
414
|
+
entry.control,
|
|
415
|
+
entry.target ?? '',
|
|
416
|
+
entry.value ?? '',
|
|
417
|
+
];
|
|
418
|
+
return [...entries].sort((a, b) => {
|
|
419
|
+
const left = key(a);
|
|
420
|
+
const right = key(b);
|
|
421
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
422
|
+
const one = left[index] ?? '';
|
|
423
|
+
const other = right[index] ?? '';
|
|
424
|
+
if (one !== other)
|
|
425
|
+
return one < other ? -1 : 1;
|
|
426
|
+
}
|
|
427
|
+
return 0;
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
//# sourceMappingURL=baseline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.js","sourceRoot":"","sources":["../../src/a11y/baseline.ts"],"names":[],"mappings":"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"}
|
package/dist/audit/styles.d.ts
CHANGED
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
* There is no transition, no animation and no `@keyframes` here, and there is a
|
|
34
34
|
* test that says so.
|
|
35
35
|
*/
|
|
36
|
-
export declare const auditStylesheet = "\n.ig-audit {\n align-items: center;\n display: inline-flex;\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n gap: var(--ig-space-tight);\n}\n\n.ig-audit-toggle {\n align-items: center;\n background: none;\n border: 0;\n color: var(--ig-text-muted);\n cursor: pointer;\n display: inline-flex;\n font: inherit;\n gap: var(--ig-space-tight);\n padding: 0;\n}\n\n.ig-audit-toggle[aria-pressed='true'] {\n color: var(--ig-text);\n}\n\n.ig-audit-count {\n color: var(--ig-text);\n font-family: var(--ig-font-mono);\n font-variant-numeric: tabular-nums;\n}\n\n[data-ig-audit] {\n box-shadow: inset var(--ig-stroke) 0 0 0 var(--ig-edge-serialize-with);\n}\n";
|
|
36
|
+
export declare const auditStylesheet = "\n.ig-audit {\n align-items: center;\n display: inline-flex;\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n gap: var(--ig-space-tight);\n}\n\n.ig-audit-toggle {\n align-items: center;\n background: none;\n border: 0;\n color: var(--ig-text-muted);\n cursor: pointer;\n display: inline-flex;\n font: inherit;\n gap: var(--ig-space-tight);\n padding: 0;\n}\n\n.ig-audit-toggle[aria-pressed='true'] {\n color: var(--ig-text);\n}\n\n.ig-audit-count {\n color: var(--ig-text);\n font-family: var(--ig-font-mono);\n font-variant-numeric: tabular-nums;\n}\n\n[data-ig-audit] {\n box-shadow: inset var(--ig-stroke-audit) 0 0 0 var(--ig-edge-serialize-with);\n}\n";
|
|
37
37
|
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/audit/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/audit/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,eAAO,MAAM,eAAe,msBAkC3B,CAAC"}
|
package/dist/audit/styles.js
CHANGED
|
@@ -66,7 +66,7 @@ export const auditStylesheet = `
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
[${AUDIT_SEVERITY_ATTRIBUTE}] {
|
|
69
|
-
box-shadow: inset var(--ig-stroke) 0 0 0 var(--ig-edge-serialize-with);
|
|
69
|
+
box-shadow: inset var(--ig-stroke-audit) 0 0 0 var(--ig-edge-serialize-with);
|
|
70
70
|
}
|
|
71
71
|
`;
|
|
72
72
|
//# sourceMappingURL=styles.js.map
|
package/dist/create/draft.d.ts
CHANGED
|
@@ -65,6 +65,23 @@ export interface CreateDraft {
|
|
|
65
65
|
}
|
|
66
66
|
/** Nothing gathered. The state before a create starts and after one emits. */
|
|
67
67
|
export declare const IDLE_CREATE_DRAFT: CreateDraft;
|
|
68
|
+
/**
|
|
69
|
+
* Whether the draft is at the KIND step: a source gathered, no kind yet.
|
|
70
|
+
*
|
|
71
|
+
* A PREDICATE RATHER THAN A SHELL'S TWO NULL CHECKS, because two of them
|
|
72
|
+
* disagreed. `render.ts`'s panel asks this question to draw the kind list and
|
|
73
|
+
* `mount.ts` now asks it to classify the keyboard, and a step whose definition
|
|
74
|
+
* is written out at each site is one a later edit can move at one of them —
|
|
75
|
+
* which is how the chooser came to be drawn at a moment the key map did not
|
|
76
|
+
* recognise (`#152`).
|
|
77
|
+
*
|
|
78
|
+
* IT ASKS ABOUT THE DRAFT ALONE, and deliberately says nothing about focus or
|
|
79
|
+
* about which of the two choosers is on screen. Whether a drop is live decides
|
|
80
|
+
* WHICH renderer draws the step, never WHETHER the reader is at it; folding that
|
|
81
|
+
* in would give this predicate a second subject and make it false for the
|
|
82
|
+
* floating chooser, which is the one opened by a pointer.
|
|
83
|
+
*/
|
|
84
|
+
export declare function isChoosingKind(draft: CreateDraft): boolean;
|
|
68
85
|
/**
|
|
69
86
|
* One fact arriving, from whichever path gathered it.
|
|
70
87
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/create/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACjC,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACjC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CAChC;AAED,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,EAAE,WAI9B,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEhC;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;CACpC;AAqBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,YAAY,CAmCtF"}
|
|
1
|
+
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/create/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACjC,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACjC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CAChC;AAED,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,EAAE,WAI9B,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE1D;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEhC;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;CACpC;AAqBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,YAAY,CAmCtF"}
|
package/dist/create/draft.js
CHANGED
|
@@ -53,6 +53,25 @@ export const IDLE_CREATE_DRAFT = Object.freeze({
|
|
|
53
53
|
target: null,
|
|
54
54
|
kind: null,
|
|
55
55
|
});
|
|
56
|
+
/**
|
|
57
|
+
* Whether the draft is at the KIND step: a source gathered, no kind yet.
|
|
58
|
+
*
|
|
59
|
+
* A PREDICATE RATHER THAN A SHELL'S TWO NULL CHECKS, because two of them
|
|
60
|
+
* disagreed. `render.ts`'s panel asks this question to draw the kind list and
|
|
61
|
+
* `mount.ts` now asks it to classify the keyboard, and a step whose definition
|
|
62
|
+
* is written out at each site is one a later edit can move at one of them —
|
|
63
|
+
* which is how the chooser came to be drawn at a moment the key map did not
|
|
64
|
+
* recognise (`#152`).
|
|
65
|
+
*
|
|
66
|
+
* IT ASKS ABOUT THE DRAFT ALONE, and deliberately says nothing about focus or
|
|
67
|
+
* about which of the two choosers is on screen. Whether a drop is live decides
|
|
68
|
+
* WHICH renderer draws the step, never WHETHER the reader is at it; folding that
|
|
69
|
+
* in would give this predicate a second subject and make it false for the
|
|
70
|
+
* floating chooser, which is the one opened by a pointer.
|
|
71
|
+
*/
|
|
72
|
+
export function isChoosingKind(draft) {
|
|
73
|
+
return draft.source !== null && draft.kind === null;
|
|
74
|
+
}
|
|
56
75
|
function complete(draft) {
|
|
57
76
|
const { source, target, kind } = draft;
|
|
58
77
|
if (source === null || target === null || kind === null)
|
package/dist/create/draft.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/create/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAoBH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,iBAAiB,GAAgB,MAAM,CAAC,MAAM,CAAC;IAC1D,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/create/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAoBH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,iBAAiB,GAAgB,MAAM,CAAC,MAAM,CAAC;IAC1D,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,cAAc,CAAC,KAAkB;IAC/C,OAAO,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AACtD,CAAC;AA2CD,SAAS,QAAQ,CAAC,KAAkB;IAClC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IACvC,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACrE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAAC,KAAkB,EAAE,OAAsB;IACtE,MAAM,IAAI,GAAG,CAAC,GAAgB,EAAE;QAC9B,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,OAAO;gBACV,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAC9D,KAAK,QAAQ;gBACX,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;YAC3C,KAAK,MAAM;gBACT,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC9C,KAAK,QAAQ;gBACX,OAAO,iBAAiB,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,wEAAwE;IACxE,4EAA4E;IAC5E,6EAA6E;IAC7E,uEAAuE;IACvE,6EAA6E;IAC7E,yEAAyE;IACzE,EAAE;IACF,2EAA2E;IAC3E,6EAA6E;IAC7E,oEAAoE;IACpE,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAE3D,4EAA4E;IAC5E,2EAA2E;IAC3E,2EAA2E;IAC3E,sEAAsE;IACtE,OAAO;QACL,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE;KACnF,CAAC;AACJ,CAAC"}
|