Commit b36cfed
committed
fix(admin/spa): drop redundant abort guard and add Modal a11y
Two follow-ups from the review of #649:
1. useApi.ts: removed the `if (ctrl.signal.aborted) return;` check
inside the catch handler. The cleanup function sets
`cancelled = true` *before* calling `ctrl.abort()`, so any abort
path is already covered by the preceding `cancelled` check. The
second guard was harmless belt-and-suspenders dead code; the
comment now records why one check is enough.
2. Modal.tsx: added the WAI-ARIA dialog contract (`role="dialog"`,
`aria-modal="true"`, `aria-labelledby` pointing at the title)
and a focus trap:
- On open: store the previously-focused element, then focus the
first focusable inside the dialog so keyboard users do not stay
stranded on the page underneath. Empty dialogs fall back to
focusing the dialog container itself with tabindex=-1.
- Tab / Shift+Tab cycle within the dialog instead of escaping to
the page underneath.
- On close: restore focus to whoever opened the dialog (skipped
when that element has been unmounted, e.g. the dialog deleted
the row whose button opened it).
- Escape and backdrop click stay wired through the existing
`busy` gate so a half-applied operation cannot be dismissed.
Implementation is vanilla DOM querying — focus-trap-react /
react-focus-lock would have added 5–7 KB gzip for what is a
~40 line vanilla solution. Bundle delta from this PR is +0.4 KB
gzip (60.23 -> 60.59 KB).
Verified with `npm run build` and `npm run lint` (tsc --strict
--noUnusedLocals --noUncheckedSideEffectImports), and `go build ./...`.
Stacked on top of #649 (feat/admin-dashboard-spa); merge that one
first, then this rebases cleanly onto main.1 parent fb8085c commit b36cfed
2 files changed
Lines changed: 101 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
18 | 28 | | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
19 | 33 | | |
20 | 34 | | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
21 | 43 | | |
22 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
23 | 67 | | |
| 68 | + | |
24 | 69 | | |
25 | | - | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
26 | 81 | | |
27 | 82 | | |
28 | 83 | | |
| |||
33 | 88 | | |
34 | 89 | | |
35 | 90 | | |
36 | | - | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
37 | 98 | | |
38 | | - | |
| 99 | + | |
39 | 100 | | |
40 | 101 | | |
41 | 102 | | |
| |||
51 | 112 | | |
52 | 113 | | |
53 | 114 | | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
47 | 50 | | |
48 | | - | |
49 | 51 | | |
50 | 52 | | |
51 | 53 | | |
| |||
0 commit comments