@stealthscale/component-a11y 0.1.0 → 0.1.3

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.
@@ -0,0 +1,584 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { n as recipe$1, r as recipe, t as recipe$2 } from "./recipes-BM8WGKWH.js";
3
+ import { c } from "react/compiler-runtime";
4
+ import { createContext, use, useEffect, useId, useRef, useState } from "react";
5
+ import { useCallbackRef, useControllableState } from "@stealthscale/hooks";
6
+ import { createRecipeContext, createSlotRecipeContext } from "@stealthscale/theme";
7
+ import { jsx } from "react/jsx-runtime";
8
+ //#region src/roving-focus/context.ts
9
+ /**
10
+ * Binds the roving-focus slot recipe to React.
11
+ *
12
+ * @remarks
13
+ * The binding is a separate module from the recipe, because the theme compiler imports the recipe
14
+ * at build time and must not load the React runtime. The root resolves the variants, and each
15
+ * item reads its slot class from the root's context.
16
+ */
17
+ /**
18
+ * Creates the roving-focus recipe's `withProvider` binding for the root and `withContext` for the
19
+ * items.
20
+ */
21
+ const { withContext: withContext$1, withProvider: withProvider$1 } = createSlotRecipeContext(recipe);
22
+ //#endregion
23
+ //#region src/roving-focus/use-roving-focus.ts
24
+ /**
25
+ * Implements a roving tabindex: Tab enters the group once, and the arrow keys move focus inside it.
26
+ *
27
+ * @remarks
28
+ * A toolbar, a tab list and a menu bar each take one stop in the page's tab order. Items register
29
+ * themselves, because the root cannot see through the components its children are composed
30
+ * from. Registration follows effect order, which differs from source order once an item renders
31
+ * conditionally, so the registry sorts by document position and the arrows follow the order on
32
+ * screen.
33
+ */
34
+ /**
35
+ * Maps each block-axis arrow key to its step.
36
+ */
37
+ const DOWN_THE_PAGE = {
38
+ ArrowDown: 1,
39
+ ArrowUp: -1
40
+ };
41
+ /**
42
+ * Maps each inline-axis arrow key to its step in a left-to-right group.
43
+ */
44
+ const ALONG_THE_LINE = {
45
+ ArrowLeft: -1,
46
+ ArrowRight: 1
47
+ };
48
+ /**
49
+ * Context that a root publishes its group on and every item below it reads.
50
+ */
51
+ const RovingFocusContext = createContext(void 0);
52
+ /**
53
+ * Compares two registrations by document position, for sorting in on-screen order.
54
+ */
55
+ function byDocumentPosition(first, second) {
56
+ return (first.element.compareDocumentPosition(second.element) & Node.DOCUMENT_POSITION_FOLLOWING) === 0 ? 1 : -1;
57
+ }
58
+ /**
59
+ * Translates a key press into the movement it requests.
60
+ *
61
+ * @param key - The `key` value of the keyboard event.
62
+ * @param orientation - The axes the group responds to.
63
+ * @param forward - 1 in a left-to-right group and -1 in a right-to-left one, applied to the
64
+ * inline arrows only.
65
+ * @returns The requested step or end, or undefined when the group does not handle the key.
66
+ */
67
+ function intentOf(key, orientation, forward) {
68
+ if (key === "Home") return "start";
69
+ if (key === "End") return "end";
70
+ const block = DOWN_THE_PAGE[key];
71
+ if (block !== void 0) return orientation === "horizontal" ? void 0 : block;
72
+ const inline = ALONG_THE_LINE[key];
73
+ if (inline !== void 0) return orientation === "vertical" ? void 0 : inline * forward;
74
+ }
75
+ /**
76
+ * Returns the destination item as the bounds of a one-item slice of the registration list.
77
+ *
78
+ * @remarks
79
+ * Slice bounds keep the caller free of a branch. An index is typed as possibly undefined even
80
+ * when it is in range, and slicing an empty list returns an empty list, so a group with no items
81
+ * needs no special case.
82
+ * @param list - The registrations in document order.
83
+ * @param intent - The step or end the key requested.
84
+ * @param from - The identifier of the item with the tab stop.
85
+ * @param wrap - Whether a step past one end continues at the other.
86
+ * @returns The start and end bounds of a slice that contains the destination item.
87
+ */
88
+ function spanOf(list, intent, from, wrap) {
89
+ const last = list.length - 1;
90
+ const at = list.findIndex((item) => item.id === from);
91
+ const here = at === -1 ? 0 : at;
92
+ const to = intent === "start" ? 0 : intent === "end" ? last : wrap ? (here + intent + list.length) % list.length : Math.min(last, Math.max(0, here + intent));
93
+ return [to, to + 1];
94
+ }
95
+ /**
96
+ * Creates a registry backed by a ref.
97
+ *
98
+ * @remarks
99
+ * Rendering depends on the active identifier and not on the list, so a list in state would
100
+ * re-render the whole group each time an item mounted, with no visible change.
101
+ */
102
+ function useRegistry() {
103
+ const $ = c(5);
104
+ let t0;
105
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
106
+ t0 = [];
107
+ $[0] = t0;
108
+ } else t0 = $[0];
109
+ const items = useRef(t0);
110
+ let t1;
111
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
112
+ t1 = (registration) => {
113
+ items.current = [...items.current, registration];
114
+ };
115
+ $[1] = t1;
116
+ } else t1 = $[1];
117
+ const add = t1;
118
+ let t2;
119
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
120
+ t2 = (node) => items.current.some((item) => item.element.contains(node));
121
+ $[2] = t2;
122
+ } else t2 = $[2];
123
+ const contains = t2;
124
+ let t3;
125
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
126
+ t3 = () => items.current.toSorted(byDocumentPosition);
127
+ $[3] = t3;
128
+ } else t3 = $[3];
129
+ const ordered = t3;
130
+ let t4;
131
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
132
+ const remove = (id) => {
133
+ items.current = items.current.filter((item_0) => item_0.id !== id);
134
+ };
135
+ t4 = {
136
+ add,
137
+ contains,
138
+ ordered,
139
+ remove
140
+ };
141
+ $[4] = t4;
142
+ } else t4 = $[4];
143
+ return t4;
144
+ }
145
+ /**
146
+ * Tracks which item has the tab stop, and defers to the caller when the group is controlled.
147
+ */
148
+ function useTabStop(props) {
149
+ const $ = c(12);
150
+ const { activeId: driven, defaultActiveId, onActiveIdChange } = props;
151
+ let t0;
152
+ if ($[0] !== defaultActiveId || $[1] !== driven || $[2] !== onActiveIdChange) {
153
+ t0 = {
154
+ defaultValue: defaultActiveId,
155
+ onChange: onActiveIdChange,
156
+ value: driven
157
+ };
158
+ $[0] = defaultActiveId;
159
+ $[1] = driven;
160
+ $[2] = onActiveIdChange;
161
+ $[3] = t0;
162
+ } else t0 = $[3];
163
+ const [activeId, setActiveId] = useControllableState(t0);
164
+ const stop = useRef(activeId);
165
+ let t1;
166
+ let t2;
167
+ if ($[4] !== activeId) {
168
+ t1 = () => {
169
+ stop.current = activeId;
170
+ };
171
+ t2 = [activeId];
172
+ $[4] = activeId;
173
+ $[5] = t1;
174
+ $[6] = t2;
175
+ } else {
176
+ t1 = $[5];
177
+ t2 = $[6];
178
+ }
179
+ useEffect(t1, t2);
180
+ let t3;
181
+ if ($[7] !== setActiveId) {
182
+ t3 = (next) => {
183
+ stop.current = next;
184
+ setActiveId(next);
185
+ };
186
+ $[7] = setActiveId;
187
+ $[8] = t3;
188
+ } else t3 = $[8];
189
+ const claim = useCallbackRef(t3);
190
+ let t4;
191
+ if ($[9] !== activeId || $[10] !== claim) {
192
+ t4 = {
193
+ activeId,
194
+ claim,
195
+ stop
196
+ };
197
+ $[9] = activeId;
198
+ $[10] = claim;
199
+ $[11] = t4;
200
+ } else t4 = $[11];
201
+ return t4;
202
+ }
203
+ /**
204
+ * Moves one tab stop across the items that register with the group.
205
+ *
206
+ * @remarks
207
+ * The first item to register takes the stop, so Tab reaches the group from its first render.
208
+ * When the item with the stop unmounts, the stop passes to the first remaining item in document
209
+ * order, so the group stays in the tab order.
210
+ * @returns The context value for the items and the key handler for the root.
211
+ */
212
+ function useRovingFocus(props) {
213
+ const $ = c(22);
214
+ const { orientation, wrap } = props;
215
+ const { add, contains, ordered, remove } = useRegistry();
216
+ const { activeId, claim, stop } = useTabStop(props);
217
+ let t0;
218
+ if ($[0] !== add || $[1] !== claim || $[2] !== ordered || $[3] !== remove || $[4] !== stop.current) {
219
+ t0 = (registration) => {
220
+ add(registration);
221
+ if (stop.current === void 0) claim(registration.id);
222
+ return () => {
223
+ remove(registration.id);
224
+ if (stop.current === registration.id) claim(ordered()[0]?.id);
225
+ };
226
+ };
227
+ $[0] = add;
228
+ $[1] = claim;
229
+ $[2] = ordered;
230
+ $[3] = remove;
231
+ $[4] = stop.current;
232
+ $[5] = t0;
233
+ } else t0 = $[5];
234
+ const register = useCallbackRef(t0);
235
+ let t1;
236
+ if ($[6] !== claim || $[7] !== contains || $[8] !== ordered || $[9] !== orientation || $[10] !== stop.current || $[11] !== wrap) {
237
+ t1 = (event) => {
238
+ if (event.ctrlKey || event.metaKey || event.altKey) return;
239
+ const { target } = event;
240
+ if (!(target instanceof Node) || !contains(target)) return;
241
+ const rightToLeft = globalThis.getComputedStyle(event.currentTarget).direction === "rtl";
242
+ const intent = intentOf(event.key, orientation, rightToLeft ? -1 : 1);
243
+ if (intent === void 0) return;
244
+ for (const moving of ordered().slice(...spanOf(ordered(), intent, stop.current, wrap))) {
245
+ claim(moving.id);
246
+ moving.element.focus();
247
+ }
248
+ event.preventDefault();
249
+ };
250
+ $[6] = claim;
251
+ $[7] = contains;
252
+ $[8] = ordered;
253
+ $[9] = orientation;
254
+ $[10] = stop.current;
255
+ $[11] = wrap;
256
+ $[12] = t1;
257
+ } else t1 = $[12];
258
+ const onKeyDown = useCallbackRef(t1);
259
+ let t2;
260
+ if ($[13] !== claim) {
261
+ t2 = (id) => {
262
+ claim(id);
263
+ };
264
+ $[13] = claim;
265
+ $[14] = t2;
266
+ } else t2 = $[14];
267
+ const onFocus = useCallbackRef(t2);
268
+ let t3;
269
+ if ($[15] !== activeId || $[16] !== onFocus || $[17] !== register) {
270
+ t3 = {
271
+ activeId,
272
+ onFocus,
273
+ register
274
+ };
275
+ $[15] = activeId;
276
+ $[16] = onFocus;
277
+ $[17] = register;
278
+ $[18] = t3;
279
+ } else t3 = $[18];
280
+ const t4 = t3;
281
+ let t5;
282
+ if ($[19] !== onKeyDown || $[20] !== t4) {
283
+ t5 = {
284
+ group: t4,
285
+ onKeyDown
286
+ };
287
+ $[19] = onKeyDown;
288
+ $[20] = t4;
289
+ $[21] = t5;
290
+ } else t5 = $[21];
291
+ return t5;
292
+ }
293
+ //#endregion
294
+ //#region src/roving-focus/item.tsx
295
+ /**
296
+ * Renders one item of a roving focus group.
297
+ *
298
+ * @remarks
299
+ * One item has `tabIndex` 0 and every other has -1, so the group is one stop in the tab order. A
300
+ * disabled item does not register, so the arrows step past it. It also refuses the stop when a
301
+ * pointer focuses it, because a stop on an unregistered item is unreachable by the arrows and
302
+ * removes the group from the tab order. The element is in state and not in a ref, so the
303
+ * registering effect runs again once the node exists. The group keys on the registration, so
304
+ * the item writes the DOM `id` only when the caller passes one, and a control rendered as an item
305
+ * keeps an id it needs, such as the one a menu trigger references. The item with the stop has
306
+ * `data-stop` and not `data-active`, because the theme styles `[data-active]` as a pressed
307
+ * control.
308
+ */
309
+ /**
310
+ * Renders a `div` element with the item slot's classes.
311
+ */
312
+ const Shell$1 = withContext$1("div", "item");
313
+ /**
314
+ * Renders an item with `tabIndex` 0 while it has the tab stop and -1 otherwise.
315
+ *
316
+ * @throws {@link Error} When rendered outside a root.
317
+ */
318
+ function Item(props) {
319
+ const $ = c(26);
320
+ let handed;
321
+ let named;
322
+ let rest;
323
+ let t0;
324
+ if ($[0] !== props) {
325
+ ({disabled: t0, id: named, ref: handed, ...rest} = props);
326
+ $[0] = props;
327
+ $[1] = handed;
328
+ $[2] = named;
329
+ $[3] = rest;
330
+ $[4] = t0;
331
+ } else {
332
+ handed = $[1];
333
+ named = $[2];
334
+ rest = $[3];
335
+ t0 = $[4];
336
+ }
337
+ const disabled = t0 === void 0 ? false : t0;
338
+ const group = use(RovingFocusContext);
339
+ if (group === void 0) throw new Error("RovingFocus.Item must be rendered inside RovingFocus.Root.");
340
+ const generated = useId();
341
+ const id = named ?? generated;
342
+ const { activeId, onFocus, register } = group;
343
+ const [element, setElement] = useState(null);
344
+ let t1;
345
+ if ($[5] !== handed) {
346
+ t1 = (node) => {
347
+ setElement(node);
348
+ if (typeof handed === "function") handed(node);
349
+ else if (handed !== null && handed !== void 0) handed.current = node;
350
+ };
351
+ $[5] = handed;
352
+ $[6] = t1;
353
+ } else t1 = $[6];
354
+ const attach = useCallbackRef(t1);
355
+ let t2;
356
+ if ($[7] !== disabled || $[8] !== id || $[9] !== onFocus) {
357
+ t2 = () => {
358
+ if (!disabled) onFocus(id);
359
+ };
360
+ $[7] = disabled;
361
+ $[8] = id;
362
+ $[9] = onFocus;
363
+ $[10] = t2;
364
+ } else t2 = $[10];
365
+ const claim = useCallbackRef(t2);
366
+ let t3;
367
+ let t4;
368
+ if ($[11] !== disabled || $[12] !== element || $[13] !== id || $[14] !== register) {
369
+ t3 = () => {
370
+ if (element === null || disabled) return;
371
+ return register({
372
+ element,
373
+ id
374
+ });
375
+ };
376
+ t4 = [
377
+ disabled,
378
+ element,
379
+ id,
380
+ register
381
+ ];
382
+ $[11] = disabled;
383
+ $[12] = element;
384
+ $[13] = id;
385
+ $[14] = register;
386
+ $[15] = t3;
387
+ $[16] = t4;
388
+ } else {
389
+ t3 = $[15];
390
+ t4 = $[16];
391
+ }
392
+ useEffect(t3, t4);
393
+ const t5 = disabled || void 0;
394
+ const t6 = disabled ? "" : void 0;
395
+ const t7 = activeId === id ? "" : void 0;
396
+ const t8 = !disabled && activeId === id ? 0 : -1;
397
+ let t9;
398
+ if ($[17] !== attach || $[18] !== claim || $[19] !== named || $[20] !== rest || $[21] !== t5 || $[22] !== t6 || $[23] !== t7 || $[24] !== t8) {
399
+ t9 = /* @__PURE__ */ jsx(Shell$1, {
400
+ "aria-disabled": t5,
401
+ "data-disabled": t6,
402
+ "data-stop": t7,
403
+ id: named,
404
+ onFocus: claim,
405
+ ref: attach,
406
+ tabIndex: t8,
407
+ ...rest
408
+ });
409
+ $[17] = attach;
410
+ $[18] = claim;
411
+ $[19] = named;
412
+ $[20] = rest;
413
+ $[21] = t5;
414
+ $[22] = t6;
415
+ $[23] = t7;
416
+ $[24] = t8;
417
+ $[25] = t9;
418
+ } else t9 = $[25];
419
+ return t9;
420
+ }
421
+ //#endregion
422
+ //#region src/roving-focus/root.tsx
423
+ /**
424
+ * Renders a `div` element with the root slot's classes.
425
+ */
426
+ const Shell = withProvider$1("div", "root");
427
+ /**
428
+ * Keeps one tab stop for the items below it and moves the stop on the arrow keys.
429
+ */
430
+ function Root(props) {
431
+ const $ = c(26);
432
+ let activeId;
433
+ let children;
434
+ let defaultActiveId;
435
+ let onActiveIdChange;
436
+ let rest;
437
+ let t0;
438
+ let t1;
439
+ if ($[0] !== props) {
440
+ ({activeId, children, defaultActiveId, onActiveIdChange, orientation: t0, wrap: t1, ...rest} = props);
441
+ $[0] = props;
442
+ $[1] = activeId;
443
+ $[2] = children;
444
+ $[3] = defaultActiveId;
445
+ $[4] = onActiveIdChange;
446
+ $[5] = rest;
447
+ $[6] = t0;
448
+ $[7] = t1;
449
+ } else {
450
+ activeId = $[1];
451
+ children = $[2];
452
+ defaultActiveId = $[3];
453
+ onActiveIdChange = $[4];
454
+ rest = $[5];
455
+ t0 = $[6];
456
+ t1 = $[7];
457
+ }
458
+ const orientation = t0 === void 0 ? "horizontal" : t0;
459
+ const wrap = t1 === void 0 ? false : t1;
460
+ let t2;
461
+ if ($[8] !== activeId || $[9] !== defaultActiveId || $[10] !== onActiveIdChange || $[11] !== orientation || $[12] !== wrap) {
462
+ t2 = {
463
+ activeId,
464
+ defaultActiveId,
465
+ onActiveIdChange,
466
+ orientation,
467
+ wrap
468
+ };
469
+ $[8] = activeId;
470
+ $[9] = defaultActiveId;
471
+ $[10] = onActiveIdChange;
472
+ $[11] = orientation;
473
+ $[12] = wrap;
474
+ $[13] = t2;
475
+ } else t2 = $[13];
476
+ const { group, onKeyDown } = useRovingFocus(t2);
477
+ let t3;
478
+ if ($[14] !== orientation || $[15] !== rest.role) {
479
+ t3 = rest.role !== void 0 && orientation !== "both" ? { "aria-orientation": orientation } : void 0;
480
+ $[14] = orientation;
481
+ $[15] = rest.role;
482
+ $[16] = t3;
483
+ } else t3 = $[16];
484
+ const told = t3;
485
+ let t4;
486
+ if ($[17] !== children || $[18] !== onKeyDown || $[19] !== orientation || $[20] !== rest || $[21] !== told) {
487
+ t4 = /* @__PURE__ */ jsx(Shell, {
488
+ onKeyDown,
489
+ orientation,
490
+ ...told,
491
+ ...rest,
492
+ children
493
+ });
494
+ $[17] = children;
495
+ $[18] = onKeyDown;
496
+ $[19] = orientation;
497
+ $[20] = rest;
498
+ $[21] = told;
499
+ $[22] = t4;
500
+ } else t4 = $[22];
501
+ let t5;
502
+ if ($[23] !== group || $[24] !== t4) {
503
+ t5 = /* @__PURE__ */ jsx(RovingFocusContext, {
504
+ value: group,
505
+ children: t4
506
+ });
507
+ $[23] = group;
508
+ $[24] = t4;
509
+ $[25] = t5;
510
+ } else t5 = $[25];
511
+ return t5;
512
+ }
513
+ //#endregion
514
+ //#region src/roving-focus/index.ts
515
+ var roving_focus_exports = /* @__PURE__ */ __exportAll({
516
+ Item: () => Item,
517
+ Root: () => Root
518
+ });
519
+ //#endregion
520
+ //#region src/skip-nav/context.ts
521
+ /**
522
+ * Binds the skip-nav slot recipe to React.
523
+ *
524
+ * @remarks
525
+ * The binding is a separate module from the recipe, because the theme compiler imports the recipe
526
+ * at build time and must not load the React runtime. The link and the target each use
527
+ * `withProvider`, because neither is rendered inside the other.
528
+ */
529
+ /**
530
+ * Creates the skip-nav recipe's `withProvider` binding.
531
+ */
532
+ const { withProvider } = createSlotRecipeContext(recipe$1);
533
+ //#endregion
534
+ //#region src/skip-nav/link.ts
535
+ /**
536
+ * Fragment identifier that the link's `href` and the target's `id` default to.
537
+ */
538
+ const SKIP_NAV_TARGET = "content";
539
+ /**
540
+ * Renders an `a` element with the link slot's classes, pointing at `#content` by default.
541
+ */
542
+ const Link = withProvider("a", "link", { defaultProps: { href: `#${SKIP_NAV_TARGET}` } });
543
+ //#endregion
544
+ //#region src/skip-nav/target.ts
545
+ /**
546
+ * Renders a `div` element with the target slot's classes, `id="content"` and `tabIndex` -1 by
547
+ * default.
548
+ */
549
+ const Target = withProvider("div", "target", { defaultProps: {
550
+ id: SKIP_NAV_TARGET,
551
+ tabIndex: -1
552
+ } });
553
+ //#endregion
554
+ //#region src/skip-nav/index.ts
555
+ var skip_nav_exports = /* @__PURE__ */ __exportAll({
556
+ Link: () => Link,
557
+ SKIP_NAV_TARGET: () => SKIP_NAV_TARGET,
558
+ Target: () => Target
559
+ });
560
+ //#endregion
561
+ //#region src/visually-hidden/context.ts
562
+ /**
563
+ * Binds the visually-hidden recipe to React.
564
+ *
565
+ * @remarks
566
+ * The binding is a separate module from the recipe, because the theme compiler imports the recipe
567
+ * at build time and must not load the React runtime.
568
+ */
569
+ /**
570
+ * Creates the visually-hidden recipe's `withContext` binding and its `PropsProvider`.
571
+ *
572
+ * @remarks
573
+ * `PropsProvider` sets variants on every element bound below it. The package exports it as
574
+ * `VisuallyHiddenPropsProvider`.
575
+ */
576
+ const { PropsProvider, withContext } = createRecipeContext(recipe$2);
577
+ //#endregion
578
+ //#region src/visually-hidden/visually-hidden.ts
579
+ /**
580
+ * Renders a `span` element with the classes of the visually-hidden recipe.
581
+ */
582
+ const VisuallyHidden = withContext("span");
583
+ //#endregion
584
+ export { Link as a, Item as c, Target as i, PropsProvider as n, roving_focus_exports as o, skip_nav_exports as r, Root as s, VisuallyHidden as t };
package/dist/theme.d.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  //#region src/theme.d.ts
2
2
  /**
3
- * Publishes the preset that registers every recipe in this package, for an application's compiler
4
- * to install.
3
+ * Declares the preset an application's compiler installs to pick up this package's recipes.
5
4
  *
6
5
  * @remarks
7
- * The list is written by hand. The package's own specification reports a recipe file the list
8
- * leaves out, so no generator runs here.
6
+ * The list is maintained by hand. Nothing generates it, because the package's own specification
7
+ * fails when a recipe file in `src/` is missing from the preset.
9
8
  */
10
9
  declare const _default: import("@stealthscale/theme/authoring").Preset;
11
10
  //#endregion
package/dist/theme.js CHANGED
@@ -1,13 +1,12 @@
1
- import { n as recipe$2, r as recipe$1, t as recipe } from "./recipe-BKojQp6r.js";
1
+ import { n as recipe$2, r as recipe$1, t as recipe } from "./recipes-BM8WGKWH.js";
2
2
  import { definePreset } from "@stealthscale/theme/authoring";
3
3
  //#region src/theme.ts
4
4
  /**
5
- * Publishes the preset that registers every recipe in this package, for an application's compiler
6
- * to install.
5
+ * Declares the preset an application's compiler installs to pick up this package's recipes.
7
6
  *
8
7
  * @remarks
9
- * The list is written by hand. The package's own specification reports a recipe file the list
10
- * leaves out, so no generator runs here.
8
+ * The list is maintained by hand. Nothing generates it, because the package's own specification
9
+ * fails when a recipe file in `src/` is missing from the preset.
11
10
  */
12
11
  var theme_default = definePreset({
13
12
  name: "@stealthscale/component-a11y",
@@ -0,0 +1,35 @@
1
+ {
2
+ "about": "Keeps one tab stop for a set of controls. Tab reaches the set, and the arrow keys move focus inside it.",
3
+ "bold": "Bold",
4
+ "both": {
5
+ "about": "Eight filters in a 320px room, wrapping onto three lines. With `orientation=\"both\"` every arrow key moves focus to the next or previous filter.",
6
+ "title": "Both"
7
+ },
8
+ "draw": "Draw",
9
+ "erase": "Erase",
10
+ "filters": "Filters",
11
+ "formatting": "Formatting",
12
+ "italic": "Italic",
13
+ "select": "Select",
14
+ "statuses": {
15
+ "disputed": "Disputed",
16
+ "draft": "Draft",
17
+ "overdue": "Overdue",
18
+ "paid": "Paid",
19
+ "pending": "Pending",
20
+ "refunded": "Refunded",
21
+ "scheduled": "Scheduled",
22
+ "void": "Void"
23
+ },
24
+ "title": "Roving focus",
25
+ "toolbar": {
26
+ "about": "A formatting toolbar with `wrap`. Tab reaches Bold, the item with the tab stop, and the second cell renders its focused state. ArrowRight moves to Italic, and on Underline it moves back to Bold.",
27
+ "title": "Toolbar"
28
+ },
29
+ "tools": "Tools",
30
+ "underline": "Underline",
31
+ "vertical": {
32
+ "about": "A vertical toolbar. ArrowDown and ArrowUp move focus, and ArrowLeft and ArrowRight reach the page.",
33
+ "title": "Vertical"
34
+ }
35
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "about": "Moves keyboard focus past a repeated block of content. `SkipNav.Link` is hidden until keyboard focus, and `SkipNav.Target` receives focus when the link is followed.",
3
+ "all": "All",
4
+ "filters": "Filters",
5
+ "overdue": "Overdue",
6
+ "pair": {
7
+ "about": "An invoice list whose skip link moves focus past the filters to the results. Press Tab into the scene: the link appears at the start corner of the list, and Enter moves focus to the results.",
8
+ "title": "Link and target"
9
+ },
10
+ "paid": "Paid",
11
+ "results": "24 invoices match the filters.",
12
+ "skip": "Skip to invoices",
13
+ "title": "Skip nav"
14
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "about": "Renders content that a screen reader announces and the browser does not paint.",
3
+ "close": "Close",
4
+ "create": "New invoice",
5
+ "focusable": {
6
+ "about": "A page section whose first control, Keyboard shortcuts, is hidden until keyboard focus. Press Tab into the scene: `focusable` fixes the control to the start corner of the section.",
7
+ "title": "Focusable"
8
+ },
9
+ "invoices": "Invoices",
10
+ "name": {
11
+ "about": "An icon-only close button. The icon has `aria-hidden`, and the hidden text Close is the button's accessible name.",
12
+ "title": "Accessible name"
13
+ },
14
+ "shortcuts": "Keyboard shortcuts",
15
+ "summary": "24 invoices, 3 of them overdue.",
16
+ "title": "Visually hidden"
17
+ }