ReviewOS

stacks/stx

Preserve useRef ownership through nested component slots

#2127
Closed chris opened this 6 days ago ·
6 days ago

An input authored by a page inside maintained Dialog and DialogPanel components stops resolving through the page's useRef accessor. In the browser game this breaks invalid map seed recovery: validation displays the error, but focus stays on the submit button rather than returning to the input.

A standalone Chrome regression reproduces this on current main after the caller event correction in #2126. The page owns an input, its seed state, a useRef('seedInput') accessor and a validation handler calling nextTick(() => field.current?.focus()). The input is projected through the maintained dialog components. The error attribute updates, but focus remains on validate instead of seed.

The nested receiver's caller snapshot contains the page's accessor alongside the Dialog's own $refs map. Ref hydration writes the input to that receiving map, while the accessor correctly retains the page's original map. This needs a runtime ownership correction, including accessors whose variable name differs from their authored ref name.

Related consumer: stacksjs/the-settlers-iii-remake#226. The full browser gate caught this in the existing restart dialog after the focused demolition checks passed.

Acceptance:

  • Preserve the authored useRef map through nested caller scope snapshots.
  • Cover aliased accessors, component-local refs and repeated dialog openings without leaking refs into another component's map.
  • Retain a real Chrome regression for invalid input focus alongside cancellation, confirmation and opener restoration.
  • Pass relevant scope/compiler/component regressions, lint, types and normal patch release gates.
  • Adopt qualified published packages through Stacks and rerun the full game browser gate before consumer acceptance.
2 days ago

Fixed by 7161b32 (preserve caller refs through nested component slots), released in v0.2.722, with the ownership assertions in 8715833336. The remake's restart dialog returns focus to the invalid seed input in its browser gate (tests/browser/restart-dialog.ts).

6 days ago

The full browser gate found a separate regression in the existing restart dialog: an invalid map seed shows its error, but focus remains on the submit button. The demolition dialog's 117 focused checks and the unchanged ten-minute rival battle passed before that failure.

The failure reproduces in a standalone upstream Chrome test and is tracked in stacksjs/stx#2127. STX rendered the inner panel first, then retained its ref receiver when projecting that markup through the outer Dialog. The compiler correction forwards that caller boundary while preserving child-owned refs. The regression also covers an aliased accessor with the same ref name as the Dialog's own local ref, repeated openings, cancellation, confirmation and restored opener focus.

Focused checks, types and normal STX release preflight pass. The full source suite and published-package adoption still need to finish before rerunning the complete game gate. This issue remains open.

5 days ago

Published-package audit: the upstream fix (7161b32) is present and verified in STX/components 0.2.736. Fresh unmodified npm installs pass the maintained packages/components/test/dialog-caller-events-browser.test.ts scenarios in real Chrome, including an aliased useRef accessor projected through Dialog/DialogPanel, invalid-input focus, a ref name shared with the Dialog's own ref, repeated openings and restored opener focus. Source dialog/ref/library regressions: 38 passed, 0 failed; complete installed-package/sample audit: 12 passed, 0 failed, Bun 1.4.2. Original npm archives were SHA1/SHA512 verified, and all installed files match them. Latest main CI is green: https://github.com/stacksjs/stx/actions/runs/40673334028 .

Leaving this issue open for its explicit downstream adoption/acceptance requirement. The game's current committed package.json at 9d2c6f5 still pins STX/components/bun-plugin-stx 0.2.719; its latest successful game CI is not evidence for these newer compiler fixes. The earlier local adoption report in stacksjs/the-settlers-iii-remake#226 has not yet been followed by final downstream acceptance evidence. Next gate: the game owner adopts qualified packages through Stacks and reruns its full production browser check, including invalid-seed focus. No downstream dependencies or Craft code changed in this audit.

Sign in to comment on this issue.