Public: anyone can read this; the crew can change it.
The forge pill on an app or preview is reachable by keyboard alone #10846
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/10823-the-forge-pill-on-an-app-or-preview-is-r → main 2 commits fork 2 threads · 2 unresolved
2 files
changed +22
−0
src/apps/toolbar.ts +6
| @@ -459,6 +459,10 @@ export const toolbarJs = `(function () { | ||
| 459 | 459 | } |
| 460 | 460 | pill.addEventListener("pointerup", drop); |
| 461 | 461 | pill.addEventListener("pointercancel", drop); |
| 462 | var sr = document.createElement("div"); | |
| 463 | sr.setAttribute("role", "status"); | |
| 464 | sr.style.cssText = "position:absolute;opacity:0"; | |
| 465 | box.appendChild(sr); | |
| 462 | 466 | pill.addEventListener("keydown", function (e) { |
| 463 | 467 | var t = corner.charAt(0), l = corner.charAt(1); |
| 464 | 468 | if (e.key === "ArrowLeft") l = "l"; |
| @@ -467,8 +471,10 @@ export const toolbarJs = `(function () { | ||
| 467 | 471 | else if (e.key === "ArrowDown") t = "b"; |
| 468 | 472 | else return; |
| 469 | 473 | e.preventDefault(); |
| 474 | if (t + l === corner) return; | |
| 470 | 475 | place(t + l); |
| 471 | 476 | store(KEY, corner); |
outdated
Announced even when the corner did not change. Compare t+l with corner before place() and skip or say "already there". |
||
| 477 | sr.textContent = "Moved to the " + (t > "b" ? "top " : "bottom ") + (l > "m" ? "right" : "left"); | |
| 472 | 478 | }); |
| 473 | 479 | // An inline display beats the UA [hidden] rule, so display carries the state. |
| 474 | 480 | function ring(b) { |
test/toolbar-move.test.ts +16
| @@ -70,6 +70,22 @@ describe("moving the pill", () => { | ||
| 70 | 70 | expect(store["forge-pill-corner"]).toBe("br"); |
| 71 | 71 | }); |
| 72 | 72 | |
| 73 | test("an arrow move is announced in plain words", () => { | |
| 74 | const { box, pill, fire } = boot({}); | |
| 75 | const sr = box.children.find((c: any) => c.attrs.role === "status")!; | |
| 76 | fire(pill, "keydown", { key: "ArrowLeft" }); | |
| 77 | expect(sr.textContent).toBe("Moved to the bottom left"); | |
| 78 | fire(pill, "keydown", { key: "ArrowUp" }); | |
| 79 | expect(sr.textContent).toBe("Moved to the top left"); | |
| 80 | }); | |
| 81 | ||
| 82 | test("an arrow that changes nothing says nothing", () => { | |
| 83 | const { box, pill, fire } = boot({ "forge-pill-corner": "tl" }); | |
| 84 | const sr = box.children.find((c: any) => c.attrs.role === "status")!; | |
| 85 | fire(pill, "keydown", { key: "ArrowLeft" }); | |
| 86 | expect(sr.textContent ?? "").toBe(""); | |
| 87 | }); | |
| 88 | ||
| 73 | 89 | test("a garbage stored corner is ignored; no storage at all still works", () => { |
| 74 | 90 | expect(boot({ "forge-pill-corner": "<x>" }).host.style.right).toBe("12px"); |
| 75 | 91 | const { host, pill, fire } = boot(null); |
This cssText is what pushes growth past 300 bytes. Shorten it or the message below, and verify the box is a positioned ancestor so absolute does not escape.