Skip to content

0.5.0: every piece of chrome that looks clickable takes a click - #86

Merged
ralyodio merged 1 commit into
mainfrom
feat/mouse-hooks
Sep 12, 2026
Merged

ralyodio merged 1 commit into
mainfrom
feat/mouse-hooks

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Status bar items (onPress), modal buttons (onPress) and backdrops (onDismiss), and panels (onClick) all take a click now. A double-click exists: the app counts presses on the same row within 400ms, delivers clicks on the event and to every region, and scrollable widgets turn the second press into onActivateRow after onSelectRow.

A modal now owns the screen while it is up: its body and its backdrop both swallow clicks, so a table underneath never selects a row a click was aimed past it at.

The hit-test moved out of the app into dispatchHit, and the test screen gained click() and scroll() that run it. The demo's key bar and both dialogs are wired through the new hooks.

Version bump to 0.5.0 across the usual surface. No rendering change, so the port fixtures are untouched.

Verified: bun run typecheck (lib, build, demo, examples), 367 bun tests, node runner, and the compiled demo prints hqtui-demo 0.5.0.

Needed by diskpush's TUI, which is getting clickable panes, footer keys and dialogs on top of this.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DWtLsmAescX4Nb8QiBJd37

A status bar that says `F1 Help`, a dialog with a `Yes` button and a panel
with a title were all things a mouse could point at, and none of them
answered. Rows did, because the scrollable widgets register the region they
draw; nothing else registered anything. An app built on hqtui was therefore
keyboard-only at the exact places a user reaches for the mouse first.

Every one of them now claims its cells:

- `statusBar` items take `onPress`. The bar returns the span it drew for each
  item, and the container registers a region for the key cap and the label
  only, so the gap between two items belongs to neither.
- `modal` buttons take `onPress`, and the dialog takes `onDismiss` for a click
  on the backdrop. Whether or not it is given one, the dialog now owns the
  screen while it is up: its body swallows clicks, and so does the backdrop,
  because a table drawn underneath must not select a row a click was aimed
  past it at. The button layout is shared between drawing and hit-testing so
  the cell that shows a button is the cell that presses it.
- `panel` takes `onClick`, registered before its children draw, so it only
  answers for the cells nothing inside it claimed: the border, the title
  row, the blank space under a short list.
- A double-click exists. The app counts presses on the same row within
  400ms and delivers `clicks` on the event and to every region; scrollable
  widgets turn the second press into `onActivateRow`, after `onSelectRow`,
  which is how a file manager selects and then opens.

The hit-test itself moved out of the app into `dispatchHit`, and the test
screen gained `click()` and `scroll()` that run it, so a test can prove the
cell showing `F2 Theme` is the cell that changes the theme, and that a click
on a backdrop closes the dialog without also selecting the row behind it.
The demo's key bar and both of its dialogs are wired through it.

Bumps the library, the demo, the COBOL adapter and every workspace range that
points at them, plus the CLI's VERSION, the demo's --version and the site's
badge. Rendering is untouched, so the port fixtures do not move.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DWtLsmAescX4Nb8QiBJd37
@ralyodio
ralyodio merged commit 7ece82a into main Sep 12, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant