Files
vue-tui/packages/runtime-tests
Yunfei He 90713177bb fix(runtime): drop empty focus-subscriber sets so auto-id focusables don't leak (#196)
createFocusController()'s subscribe() returned an unsubscribe that did
`set.delete(fn)` but never removed the now-empty Set from the `subs` Map, and
remove(id) never touched `subs` either. useFocus() with no explicit id mints a
fresh `__auto-N` id per mount, so every mount/unmount of a no-id focusable
permanently leaked one empty-Set Map entry — unbounded growth over a long
session (300 mount/unmount cycles leaked 300 empty Sets).

The unsubscribe closure now drops the Set once its last subscriber leaves,
guarded by `subs.get(id) === set` so a stale double-unsubscribe after a
re-subscribe can't delete the fresh subscriber's Set (idempotency preserved).
remove() is left untouched on purpose: useFocus unsubscribes before calling it,
and deleting a Set with live subscribers would silence duplicate-id focus
delivery.

createFocusController + a test-only `__subscriberMapSize()` probe are exposed via
the ./internal entry so a unit test can assert the Map stays flat across 300
cycles, focus delivery still works (notify + re-subscribe re-creates the Set),
stale double-unsubscribe is a no-op, and multi-subscriber Sets are retained until
the last unsubscribe.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 02:40:42 +08:00
..