mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-11 16:34:02 +01:00
Some checks failed
crdt-sync pre-commit / pre-commit (push) Waiting to run
crdt-sync tests / test (3.10) (push) Waiting to run
crdt-sync tests / test (3.11) (push) Waiting to run
crdt-sync tests / test (3.12) (push) Waiting to run
design_system tests / test (push) Waiting to run
file length / file-length (push) Waiting to run
palette drift / palette (push) Waiting to run
sync_settings_ui tests / test (push) Waiting to run
web_ui tests / test (push) Waiting to run
gatelock pre-commit / pre-commit (push) Has been cancelled
gatelock tests / test (3.10) (push) Has been cancelled
gatelock tests / test (3.11) (push) Has been cancelled
gatelock tests / test (3.12) (push) Has been cancelled
operability.md pointed at README.md#pointer-free--small-screen-per-stack-patterns, written before that section was moved out of README into operability-patterns.md. The link now targets the file that holds the content. My earlier link check only validated the *file* part of each link and silently ignored the fragment, which is why this survived. Re-checked with the anchor compared against the target file's actual headings; all links in the directory now resolve, fragment included. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CFSGeWxHPY5rHUGrPqhcmG
70 lines
3.6 KiB
Markdown
70 lines
3.6 KiB
Markdown
# Pointer-free operability and screen size (required)
|
|
|
|
Split out of [`tokens.md`](tokens.md), which freezes the palette and the
|
|
scales. These are the *behavioural* requirements that use those tokens — a
|
|
token file should be readable as a table of values, and these are rules with
|
|
reasons attached.
|
|
|
|
Per-stack implementations of everything here are in
|
|
[`operability-patterns.md`](operability-patterns.md).
|
|
|
|
## Pointer-free operability (required)
|
|
|
|
**Every action must be reachable and activatable with the keyboard alone.** No
|
|
mouse, no touchpad, no touch. This is not an accessibility nicety here: several
|
|
of these apps are *lockers* that hold a global input grab with VT switching
|
|
disabled, so a control only a pointer can reach is not an inconvenience — it is
|
|
a bricked machine.
|
|
|
|
Six things must hold on every surface:
|
|
|
|
1. **No pointer-only handler.** Any `onTap`/`onLongPress`/`<Button-1>`/click
|
|
handler needs a keyboard-reachable equivalent on the same action. A bare
|
|
`GestureDetector` and an `onLongPress`-only destructive action are both
|
|
defects. Long-press in particular has *no* keyboard analogue — never make it
|
|
the only path to an action.
|
|
2. **Everything interactive is a focus stop.** Widgets that opt out of the focus
|
|
ring (`takefocus=0`, which Tk's `Menubutton`/`OptionMenu` default to) are
|
|
unreachable. Verify by walking the real ring, not by reading the code.
|
|
3. **Focus is visible.** See the focus-ring token below — the platform default
|
|
is a black ring, which vanishes on `ink`.
|
|
4. **Focus never lands somewhere invisible.** If a container scrolls, focus
|
|
entering a clipped child must scroll it into view. Clipping does not remove a
|
|
widget from the focus ring, so this is the default failure, not an edge case.
|
|
5. **Scrolling is keyboard-driven.** A scroll container needs `PageUp`/`PageDown`
|
|
and arrow keys, not just a draggable thumb and a wheel.
|
|
6. **Confirm/submit and cancel/back have accelerators.** `Enter` submits, `Escape`
|
|
cancels. On Tk, note `Enter` does **not** activate a `tk.Button` on X11 (only
|
|
`Space` does) and is bound to nothing on `Entry`/`Spinbox` — you must bind it.
|
|
|
|
### The focus-ring token
|
|
|
|
`focus-ring` is `#B8862E` (= `accent`), 2px at 1px offset. It is defined in
|
|
[`tokens.md`](tokens.md#focus-ring) with the rest of the palette, because
|
|
`scripts/palette_check.py` parses that file — a token it cannot see is a token
|
|
nothing compares across the four stacks.
|
|
|
|
Platform defaults are wrong on this palette: Tk ships
|
|
`highlightcolor="#000000"` with `highlightthickness=1`, i.e. a black ring on
|
|
`ink` (`#211D1B`) — invisible. Set `focus-ring` explicitly. Never
|
|
`highlightthickness=0` on something focusable.
|
|
|
|
⚠️ On Tk, `highlightbackground` is the **unfocused** ring and `highlightcolor`
|
|
is the **focused** one. Setting only `highlightbackground` inverts the
|
|
affordance — the widget outlines when it is *not* focused and goes black when
|
|
it *is*. Set `highlightcolor`.
|
|
|
|
### Escape hatches vs. deliberate gating
|
|
|
|
Some apps intentionally resist dismissal (an alarm you must solve a challenge to
|
|
silence, a meal gate you must log a meal to clear). That gating is a feature and
|
|
this rule does not override it. What the rule requires is that the *sanctioned*
|
|
paths — solve the challenge, use the budgeted escape hatch, submit the form — are
|
|
fully keyboard-operable. Making a gate keyboard-reachable is not weakening it.
|
|
|
|
## Screen size (required)
|
|
|
|
Moved to `screen-size.md` (250-line cap): the 1366x768 / 1024x600 targets, the
|
|
height-budgeting rules, and why centring unscrollable content clips
|
|
symmetrically. Still part of this spec — read it for any layout work.
|