feat(popup): add native declarative glass popup host
Web popup overflow currently scrapes hidden DOM rows, which loses rich controls and splits material ownership. Leo requested: “popovers in general need glassier bg blur / try to match liquid glass somehow”. This foundation adds declarative popup descriptions rendered by AppKit using the existing Glass.makeOverlayPanel material and Reduce Transparency fallback. Consumer migrations stack separately.
The local UI protocol supports search/text fields, sections, descriptions, icons, shortcuts, toggles, segmented choices, sliders, accessory actions, submenus, and model-picker rail/footer descriptors. The web hook binds events to popup identity/revision and accepts virtual anchors. Native controls emit typed actions, open instantly, restore keyboard ownership, keep child Escape local, and report root dismissal reasons. Legacy overflow listeners are isolated from native events.
Validation:
- Remote full web check and two transport tests passed in run 40845240352, covering the final web changes including virtual anchors and dismissal reasons.
- Native submenu regression reproduced parent dismissal/key restoration failure at
e90d829a3d3d9f6ce74a06cbfc476789810cdcce; the same runtime test passed at13d560310df6f940bc1ca964e7ac63d18522d924after the fix. Expanded ancestry/dismissal/content regressions are pending at the final head. - Exact native compile at
4ea584f480ef238ad4ca34082fca8029b904e67epassed in 263 seconds. Compile/runtime verification and whole-diff independent review for final head326bf3dd949704be844212b0961e3e1eb83d5e50are pending; older receipts do not approve it. - Previous review findings addressed stale-hide tombstones, search descriptor refresh, child/root dismissal, disabled ancestry, event isolation, IME Escape, and viewport width. Final review remains required.
- Wire types are hand-written (no generator): Swift in
Overlay/PopupProtocol/, TypeScript inwebviews/src/ui/popupProtocol.ts. The earliergen-popup-protocol.pyand its 16 committed outputs were refused bycmux-next no new generated files; the files moved unchanged apart from the header line, andscripts/ci/generated_files_guard.py checkpasses against the base. - Keyboard toggle fix:
NativePopupContentTests.repeatedKeyboardToggleFlipsTheSwitchEachTimefailed at 589a0c31 (fleet step 825ed411,changes == ["true","true"]) and passed at 4df13dbb (fleet step ca1ea5a9; NativePopupContentTests and NativePopupProtocolTests passed). - Anchor-gone fix: a popup already shown now hides at its current revision and reports
dismiss("anchor-gone")when its anchor goes away; testa shown popup hides when its anchor goes awayinnativePopup.lifecycle.test.tsx. - Sol review at 4df13dbb: SHIP.
No native capture is claimed yet. Risk: shared popup protocol, focus, and keyboard lifecycle. The protocol and renderer remain together because the wire contract and native state machine must agree; consumer changes are separate.
Changelog: Added the native declarative popup host foundation and shared Liquid Glass material path.
Agent session: agent session