static/js/dom.js (203 lines) — esc, _escAttr, _isElementVisible, _trapFocusInModal,
_confirmDialog, uiPrompt. Bodies VERBATIM. app.js 10,593 → 10,414.
A GATHER, not a slice — the six lived in six different places (108, 635, 659,
2617, 2623, 8892). They belong together because they are the BOTTOM of the UI
stack: `esc` alone has 25 call sites and `_escAttr` 23, and every later carve that
renders HTML will need them.
That is the actual point of doing this one now. Give them a home and the next
carve imports them; leave them in app.js and the next carve that renders HTML has
to invent a host seam to reach back into app.js — exactly the trap the
plugin-loader carve had to work around until the viz layer became a module. This
is the cheapest possible way to stop that recurring.
app.js -> { plugin-loader, viz, diagnostics-export, dom }
plugin-loader -> viz
viz, diagnostics-export, dom -> (nothing)
Zero imports. Six exports (every one is used outside the cluster).
VERIFIED BY DRIVING THE MODALS, not just booting — they are interactive, so a
green suite says little. A/B against origin/main in two browsers:
* window.uiPrompt / _confirmDialog / _trapFocusInModal all resolve
* uiPrompt() mounts its modal, accepts typed input, and resolves with the typed
value ('typed') — IDENTICAL on both
* _confirmDialog() mounts and resolves true on confirm — IDENTICAL
* zero console/page errors either side
pytest 2396, node 1038/1038, ESLint 0, tailwind-fresh clean, Codex 0.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>