feat(ui): viewport geometry-invalidation hook ui.viewport.observe (SD-3311)#3570
Conversation
One "your cached getRect() coordinates may be stale, re-query" notification,
rAF-coalesced, payload { reason: 'layout'|'zoom'|'scroll'|'resize'|'mixed' }.
Sources: layout/pagination repaints (post-paint), zoom, and DOM scroll/resize.
The DOM scroll/resize listeners attach only while something is observing.
Lets overlays anchored via getRect re-query on a single signal instead of
hand-wiring scroll + resize + layout + zoom - which also fixes the cases that
wiring silently misses: reflow and zoom fire no scroll event.
Rewires the contract-templates field chip to use it. Before, zooming drifted
the chip ~230px because it only repositioned on scroll/resize/active-change.
Adds a demo regression (chip stays anchored after zoom) and viewport.observe
unit tests (coalescing, mixed reason, unsubscribe).
|
📖 Docs preview: https://superdoc-caio-sd-3311-viewport-observe.mintlify.app |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 20f684975d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
No issues found across 6 files
Tip: cubic could auto-approve low-risk PRs like this, if it thinks it's safe to merge. Learn more
Re-trigger cubic
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
layoutUpdated and paginationUpdate are emitted back-to-back with the same payload for the same paint (PresentationEditor.ts:6491-6492), so subscribing geometry invalidation to both double-counted one repaint: a zoom coalesced to 'mixed' and the 'zoom' reason was unreachable. Subscribe to layoutUpdated only - it covers every repaint. Adds regression coverage for the zoom and plain layout reasons.
|
🎉 This PR is included in superdoc-cli v0.15.0 The release is available on GitHub release |
|
🎉 This PR is included in superdoc-sdk v1.14.0 |
|
🎉 This PR is included in @superdoc-dev/mcp v0.10.0 The release is available on GitHub release |
|
🎉 This PR is included in superdoc v1.38.0 The release is available on GitHub release |
|
🎉 This PR is included in @superdoc-dev/react v1.9.0 The release is available on GitHub release |
|
🎉 This PR is included in vscode-ext v2.10.0 |
Overlays anchored to a content control / comment / tracked change via
ui.viewport.getRecthave no way to know when those coordinates go stale, so today consumers hand-wire scroll + resize + layout + zoom listeners - and still miss cases. This adds one signal to listen to instead.ui.viewport.observe(listener)fires (rAF-coalesced, once per frame) after anything that can move painted rectangles: layout/pagination repaints, zoom, and DOM scroll/resize. The payload is just{ reason }- re-querygetRectfrom the listener. The scroll/resize listeners attach only while something is observing.A correction worth noting: scroll was never the problem - the field chip's capture-phase window listener already catches the editor's internal scroll. The real gap is layout reflow and zoom, which fire no scroll event. A probe confirmed it: zooming moved a control 230px while the chip stayed put. Because
zoomChangefires before the re-paint, the hook tags the next post-paint layout flush as'zoom'rather than notifying early with stale rects.Rewires the contract-templates field chip to this single signal (dropping its hand-wired scroll/resize), which fixes the 230px zoom drift. The demo regression asserts the chip stays anchored after a zoom (red before, green after).
Verified:
viewport.observeunit tests (coalescing / mixed / unsubscribe);contract-templates-chip-anchor4/4 (no retries);pnpm check:typesclean;pnpm check:public:superdoc13/13; demo suite green