diff options
Diffstat (limited to 'docs/prototypes/README.org')
| -rw-r--r-- | docs/prototypes/README.org | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/docs/prototypes/README.org b/docs/prototypes/README.org index 651636a..1cb75c6 100644 --- a/docs/prototypes/README.org +++ b/docs/prototypes/README.org @@ -60,6 +60,51 @@ Widget-owned animation (the R17 scope trace, R31 radar sweep, R44 servo chase, R52 pseudo-PC, R53 day clock, R10 TIME page) runs inside the builder, gated on =prefers-reduced-motion=. +** Keyboard contract (widgets that take keys) + +Sibling of the tick contract above, and the same split: focus is an ambient +resource like the clock — exactly one thing holds it across the whole page — +so *the target owns focus and delivery, the builder declares what it accepts*. +Neither half works alone. Only the page knows which widget is live; only the +widget knows that Backspace means DEL. + +*The builder declares* a =KEYS= table on itself, mapping a canonical key name +to the argument its handle's =press= takes: + +: GW.abcKeypad.KEYS = { A:'A', ..., '0':'0', ..., Space:'SPC', Backspace:'DEL', Enter:'ENT' } + +One declaration, wired natively per target: + +- *Web* — the builder attaches a =keydown= listener *to its own focusable + element* (=tabindex=0=, focused on click). =GW.slideRule= is the precedent: + arrows step it, scoped to its own element. The browser's focus system does + the arbitration, which is why it doesn't fight the gallery's own global + Escape handler. +- *Emacs* — the SVG region is an image and never sees a keypress, so the mode + installs the same table into its keymap and calls =press=. This is why the + declaration is a table and not a function over a DOM event: a port that + can't read the widget's intent has to re-derive it, and then the two drift. +- *waybar* — GTK focus, same shape. + +Rules, each of them a bug someone will otherwise ship: + +- *Never listen on =document= or =window=.* A widget that does fights every + sibling and the page's own handlers; on the gallery, every keystroke + anywhere would type into whichever card bound last. +- *=preventDefault= only what has a default worth suppressing* — Space scrolls + the page, Backspace can navigate back. Nothing else. +- *Let Tab and Escape bubble.* Tab is how the page is navigable at all, and + the gallery's audit stepper owns Escape. A widget that swallows either + breaks something it can't see. +- *=press= filters, it does not trust.* A handle that appends whatever it is + handed will cheerfully append "F1". The table is the allowlist. +- *Click and key must land in the same place* — both route through =press=, so + the two paths cannot drift apart or fire different events. + +A widget with no =KEYS= table takes no keys, which is most of them: the kit is +click-first and that is what makes it port. Keys are additive, and in Emacs +they are the *more* native idiom, not the less. + ** Style options Widgets with named style axes take them as constructor opts backed by a |
