Kitten yields to panels too; redo bug not reproducible

The overlap hook only watched .petal-rail-card, so the History and Garden
drawers still sat under the mascot — with a real control ("写作证明 ·
Writing passport") buried under the halo on the live build.

Match [role="dialog"][aria-modal="true"] as well. Both drawers already
render it, so this covers them and any future drawer without a selector
list to keep in sync.

Two things the follow-up note didn't anticipate:

- The hook now reports { cards, modal } separately. A card overlap still
  lets the kitten wake for a bubble; a modal overlap yields
  unconditionally — a cheer isn't worth covering the panel she just
  opened on purpose.
- The speech bubble is its own layer, so fading the badge didn't hide it.
  Hold it back while a panel is open; useCompanion keeps it in state, so
  it reappears when she closes the panel.

Also guard the poll's setState on value equality, so the 500 ms tick
stops re-rendering the companion for an unchanged answer.

UX_REVIEW item 1 (redo does not re-apply an accepted suggestion) is
recorded as NOT REPRODUCIBLE. Read the prosemirror-history state directly
and hooked view.dispatch: redo works pressed immediately, after an 18 s
pause that lets a full re-check land, and with the editor never focused.
The doc's hypothesis is false — every re-check transaction is
decoration-only, which prosemirror-history ignores, and canRedo stayed
true throughout. Two real findings from that dig are written into the doc
instead: keyboard undo dies when focus isn't in the editor, and an undone
suggestion stays accepted server-side so its card doesn't reliably return.

Item 5's premise is also partly wrong and now re-scoped: the Chinese
sentence does produce a card with an English rendering, just labeled
Clarity rather than a first-class Translate type.

Claude-Session: https://claude.ai/code/session_016y6gyuHkQXPiEuW8RGQyua
This commit is contained in:
prosolis
2026-07-27 22:12:30 -07:00
parent ec9fba9252
commit be9aa13287
3 changed files with 116 additions and 27 deletions
@@ -92,9 +92,10 @@ export function PetalCompanion({
// When suggestion cards stack down into the corner, the kitten fades to
// translucent and shrinks a step so the card stays readable and clickable.
// It wakes back up whenever it has something to say (bubble) or is being
// interacted with (picker open).
// interacted with (picker open) — except under an open History or Garden
// panel, where even a cheer would cover the controls she just reached for.
const crowded = useCardOverlap(badgeRef)
const faded = crowded && !pickerOpen && !bubble
const faded = crowded.modal || (crowded.cards && !pickerOpen && !bubble)
// Awake companions (no sleeping clip) don't visibly nap — when the engine
// dozes them, keep their normal idle pose instead of a sleepy face. Only a
@@ -185,7 +186,10 @@ export function PetalCompanion({
</div>
)}
{bubble && !pickerOpen && (
{/* The bubble is its own layer, so fading the badge doesn't hide it —
hold it back explicitly while a panel is open. useCompanion keeps the
bubble in state, so it reappears when she closes the panel. */}
{bubble && !pickerOpen && !crowded.modal && (
<div
role="status"
onClick={dismiss}