docs: Iris's second 2026-09-08 phone report, and the workaround list closed
RUST.md gets the report verbatim with what each of the four defects actually was, the tests that pin them, and two traps worth not re-finding (a fixed-coordinate tap that "failed" by 544px because it had toggled a tool group, and a layer-1 repro that only reproduces inside a `List`). IRIS.md and DECISIONS.md get the design half: one `Flinger` whose seam puts the sign convention and the content's end with the caller, a cancel as a first-class end to a gesture, and why a row is drawn twice on the frame its height changes. LAYOUT.md gains the two rules those turned on, since both govern the layout rather than this pass: padding works in any container and is an inset or an outset depending on how tight the parent's region is (Iris's own words), and a widget offered a box it does not fit is drawn again at its true box in the same frame rather than the next one. IRIS_TODO.md's "worked around in tool.rs rather than fixed here" is gone -- Iris, 2026-09-08: "There should never be workaround code." Two of the four entries are ticked; the two that remain are missing capabilities rather than defects being dodged, and each now carries a diagnosis of what building it costs instead of a workaround: an overflow ellipsis needs `TextBuffer` to have a displayed string distinct from its source (parley has none of its own, and every byte-offset consumer -- spans, `byte_at`, `Selection`, `apply_delta` -- moves if the buffer is truncated), and selectable tool-card text needs a register/unregister lifecycle across the three routes that rebuild a card, which is where a stale `Selection` handle panics. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
02b277e7ad
commit
fe7dc9c728
5 files changed
+353
-16
No files matched your search
@@ -12,6 +12,69 @@ things still stay out.
|
||||
An entry gives the date, what changed, why, and a short before/after where
|
||||
it helps judge the change without the session that made it. Newest first.
|
||||
|
||||
## 2026-09-08: what a cancel means, what a row's box is, and one fling for every scroll area
|
||||
|
||||
Iris's second 2026-09-08 report, from the bench on her phone. Four items,
|
||||
and each turned out to be a rule stated in one place and missing from its
|
||||
siblings rather than a special case.
|
||||
|
||||
**A gesture the *platform* takes away is a cancel, not a release**
|
||||
(`CursorState::cancelled`). Android's `ACTION_CANCEL` used to take the
|
||||
same arm as `ACTION_UP`, so the system's own swipe up from the bottom
|
||||
edge to leave the app arrived as a flick released at speed: the
|
||||
transcript flung while the app was in the background, and came back
|
||||
somewhere else. A cancelled sample now hands `CursorSense::Cancel` to
|
||||
the capture holder *and* every widget still tracking the press, clears
|
||||
both, and derives nothing else from that sample -- no tap, no selection,
|
||||
no fling. That is the same sense a widget already gets when it loses a
|
||||
capture race; what is new is that the platform can raise it, and that
|
||||
the *winner* hears it too when the platform is the one cancelling.
|
||||
|
||||
**A `DragGesture` ignores a cancel when it is the one holding the
|
||||
capture.** A cancel goes to every pressed widget that did not capture,
|
||||
and one gesture is routinely driven by several of those: a transcript
|
||||
row's text block feeds the shared gesture that captures under the
|
||||
*list's* id, so the block is a "loser" on the very frame its own pan
|
||||
committed. `Cancel` means "somebody else won", so the question is
|
||||
whether the holder is us -- and now it is asked. With that, a row's
|
||||
block registers the whole `drag_senses()` set, which is what the doc on
|
||||
that set has always said a widget driving a gesture must do; it was the
|
||||
one place that did not, and it is why panning a code fence sideways and
|
||||
then tapping made the transcript jump.
|
||||
|
||||
**A row is drawn at the box its own height implies, in the frame that
|
||||
height changes** (`List::place`). A row is offered its *cached* height
|
||||
so that an unchanged row takes `draw_inner`'s cheap path; a
|
||||
`.background(rect(..))` fills whatever box it is handed. So on the frame
|
||||
a row changed height its text laid out at the new height and its
|
||||
background painted at the old one -- collapsing or opening a tool card
|
||||
looked closed while its text was there, then open while it was not. When
|
||||
the measurement disagrees with the offer, the row is now drawn again at
|
||||
its true box. The bottom-anchored half had a `reposition` for this,
|
||||
which writes an offset and never a size, so it could not fix it either:
|
||||
the same rule, applied to one member of a set of two.
|
||||
|
||||
**Every scroll area flings, on either axis** (`iris::sense::Flinger`).
|
||||
The fling was `List`'s alone -- the curve, the clock, the incremental
|
||||
delta, Compose's two release thresholds -- and a `Scroll` dropped its
|
||||
released velocity on the floor, with a comment explaining that the areas
|
||||
it wrapped were only a screenful. That stopped being true the moment a
|
||||
code fence became one. `Flinger` is that machinery as a type both use;
|
||||
what it deliberately does not know is which way a positive delta moves
|
||||
the content or where the content ends, because a `List` and a `Scroll`
|
||||
answer those oppositely. The caller applies `tick`'s delta in its own
|
||||
convention and calls `stop` at its own wall. `Scroll::drag` now answers
|
||||
whether it started a fling, which is what `scroll_area` needs to call
|
||||
`UiData::animate` -- the same split `List::fling` already documented,
|
||||
for the same reason: only the caller can reach the frame loop.
|
||||
|
||||
**Removed, not worked around**: `tool.rs` no longer flattens its two
|
||||
`Span`s into one, so a tool group holds its cards 4dp off its own edge
|
||||
again. The defect that shape was avoiding -- "a `Span` of `Pad`ded
|
||||
children inside another `Span` places those children a slot out of step"
|
||||
-- is not reproducible on 2026-09-08, checked both with a headless
|
||||
render and with a new layer-1 test.
|
||||
|
||||
## 2026-09-08: a gesture can be cancelled, and the pointer belongs to the input handler
|
||||
|
||||
Two changes to how a drag ends, from defects on Iris's phone (a code
|
||||
|
||||
Reference in new issue
Block a user