Skip to content

Commit 0c37ae8

Browse files
authored
Scroll REPL readings with the mouse wheel (#1027)
* ✨ Add mounted wheel viewport foundation for chat and drawers * ✅ Observe both wheel directions in the entry question viewport * 🐛 Preserve focused reading anchors across control-only wheel pages * Migrate remaining REPL viewport owners and retire window buttons * 🐛 Fit retained drawer details before row admission * fix(cli): fit complete permission explanations before admission * 🧪 Complete REPL wheel consumer migration evidence * Complete measured scrolling guidance * Repair scrolling guidance transitions and consumer evidence * test(cli): await cleared native Draft before locating Exit
1 parent 62832c6 commit 0c37ae8

36 files changed

Lines changed: 2472 additions & 684 deletions

‎architecture.md‎

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6844,6 +6844,15 @@ action; the tree walks that target's own ancestry, and the first node to handle
68446844
the event produces the typed action the root acts on. An event nothing handles
68456845
is an explicit failure.
68466846

6847+
Wheel is coordinate-targeted physical input, separate from control activation.
6848+
A nonfocusable viewport component owns its admitted content descendants. It
6849+
returns a semantic scroll action through the same ancestry walk and ends with
6850+
its mounted branch. Drawer Content handles PageUp/PageDown left by descendants;
6851+
fields retain their arrows and Home/End. Deliberate paging can remove a focused
6852+
row and use the existing survivor recovery. Wheel instead stops before hiding
6853+
its focused content control, using that control's fitted extent. A reading
6854+
anchor keeps viewport identity as the displayed rows change.
6855+
68476856
**Keyboard focus moves by regions, and the structure is derived, not stored.**
68486857
A focusable description may carry a placement: its region — a key, a rank in
68496858
the Tab cycle, an axis and an optional recovery preference — the nested groups
@@ -7054,7 +7063,7 @@ resize changes what a window holds and a delta added to a stale number would
70547063
spend a press on state nobody can see. The canonical location is bounded the
70557064
same way and for the same reason: in a narrow frame it shares one region with
70567065
every control on the screen, so it takes at most three rows and says what it is
7057-
not showing. Their window controls and
7066+
not showing. Their fixed headings, composers, actions and
70587067
the two surface controls stay outside the moving window. A narrow frame mounts
70597068
one routed outlet and both surface controls, so the outlet the route did not
70607069
select is absent everywhere — `mounted()`, the frame, the target map — while the
@@ -7103,8 +7112,9 @@ work on the left, the selected work with its breadcrumbs, exact source, state,
71037112
results and its own multi-row Draft in the centre, and Bindings/Sidekick on the
71047113
right with the trays this build offers above the composer and the Sidekick's
71057114
Send/Stop beside them, under one identity row and above one compact History row
7106-
and one guidance row. It is selected by a view carrying the inert workspace
7107-
presentation, and the root supplies that presentation from what this execution
7115+
and a guidance block whose fitted rows determine its height. It is selected by
7116+
a view carrying the inert workspace presentation, and the root supplies that
7117+
presentation from what this execution
71087118
actually holds: the selected tray, no queued rows because this build has no
71097119
shared queue, and the entries its Sidekick's acknowledged Submits admitted. A
71107120
build without the continuation Follow governs offers neither Follow nor a QUEUE
@@ -7152,7 +7162,7 @@ move what it was moved clear of.
71527162
**Measurement comes first, and it is not a frame.** The application builds inert
71537163
ordered candidates and a paired manifest from one semantic reading, and the
71547164
measuring pass draws that manifest with every scrolling viewport genuinely
7155-
empty — surrounding headings, both window controls and complete action labels
7165+
empty — surrounding headings, composers and complete action labels
71567166
included, so the room it reports is the region's rather than whatever is
71577167
currently overflowing it. That pass mounts nothing, publishes no target,
71587168
advances no revision and acknowledges nothing. Capacity is the measured viewport
@@ -7173,7 +7183,7 @@ survives whole and the name keeps what is left in front of it, because a state
71737183
cut in half says something untrue and two rows that are only their state are two
71747184
rows a reader cannot tell apart.
71757185

7176-
Whatever a column states *around* its window — a heading, both window controls,
7186+
Whatever a column states *around* its window — a heading, fixed actions,
71777187
the placeholder for a reading that holds nothing — it states in the measuring
71787188
pass too, and a row stated around a window is not one of that window's own rows.
71797189
A placeholder described only once the window had been admitted would take a row
@@ -7216,6 +7226,18 @@ the text underneath it. A pointer that does resolve becomes the same normalized
72167226
event a key produces and walks the same ancestry, so clicking a control and
72177227
pressing Enter on it are one action.
72187228

7229+
Viewport wheel regions are copied separately from activation targets. Each
7230+
manifest slot may name its owner's description key; the committed pass pairs
7231+
that key with a live mounted node and the renderer snapshots the viewport's
7232+
bounds in draw order. Missing owners and zero-size viewports produce no wheel
7233+
region. Text, trailing spaces and blank cells inside it name that owner; headings,
7234+
gutters, composers and fixed actions do not. Wheel resolution carries the
7235+
presented tree revision, after current terminal dimensions agree with that
7236+
frame. Stale revisions, removed owners and owners outside the top modal reach
7237+
nothing; a forbidden target is never skipped to reach background. An edge or
7238+
fitting viewport consumes without moving a neighbour. No registry or extra
7239+
Context owns these associations.
7240+
72197241
An open drawer is one floating, opaque rectangle over the body and above the
72207242
footer. The background is coverage rather than style: an element without one
72217243
lets what it covers show through from wherever its own text stops, so the blank
@@ -8589,8 +8611,8 @@ while the screen shows something else owns nothing. Agent is an exact-name field
85898611
because which agents exist is the provider's to answer, and `select()` validates
85908612
what was typed against the real one. Model and effort are the provider's own
85918613
ids on their actions, with the provider's words as labels. Its content is
8592-
windowed like every other drawer's and scrolled by the same two controls, which
8593-
move Configure's own offset: an agent may advertise more choices than a pane
8614+
windowed like every other drawer's. Wheel input and Content paging move
8615+
Configure's own offset: an agent may advertise more choices than a pane
85948616
can draw, and a choice nobody can scroll to is a choice the drawer removed.
85958617

85968618
**On the screen that question is a form in the pane that owns it, and the two

0 commit comments

Comments
 (0)