Summary
createOverlayController configures a MutationObserver on document.body with attributes: true and no attributeFilter, so the handler fires on every attribute mutation in the body subtree — style, class, id, aria-*, data-anything — even though the only attribute the library reads is data-sanity. Any per-frame attribute writer (GSAP, anime.js, framer-motion's style mode, hand-rolled rAF) anywhere in the page cascades reducer dispatches at frame rate, which can blow React's render-depth limit when an unrelated state update lands on top.
Source
src/ui/shared-state/SharedStateContext.ts, compiled in 3.2.4 to dist/_chunks-es/SharedStateContext.js and dist/_chunks-cjs/SharedStateContext.cjs:
```js
mo = new MutationObserver(handleMutation)
mo.observe(document.body, {
attributes: true, // ← over-collection
characterData: true,
childList: true,
subtree: true,
})
```
Proposed fix
Add attributeFilter: ['data-sanity']. The library's only consumer of attribute mutations is the data-sanity parser; nothing else in handleMutation's downstream path reads any other attribute, so this is a strict narrowing of what the observer sees with no behavior change for editors.
```diff
mo.observe(document.body, {
attributes: true,
- attributeFilter: ['data-sanity'],
characterData: true,
childList: true,
subtree: true,
})
```
Repro
Any GSAP-animated element with a few data-sanity descendants will surface the cascade. Minimal recipe:
- Sanity Presentation iframe with Visual Editing enabled.
- A section that renders ~15 elements with
data-sanity attributes inside a parent that GSAP animates per frame (e.g. `gsap.to(parent, { x: '-50%', repeat: -1, duration: 35 })`).
- Trigger any unrelated state update on top of the running animation (route change, theme switch, perspective toggle).
- React surfaces `Maximum update depth exceeded` from `Overlays.tsx:162` reducer dispatch.
Stack trace pattern: `MutationObserver.handleMutation` → `parseElements` → `updateElement` → `Overlays.tsx:162` reducer dispatch.
Why this matters
The library's docs encourage rich animations on content-driven pages, and the standard tools for those animations write to `style` attributes per frame. The current observer config makes Visual Editing incompatible with any of them in practice unless authors hand-suppress mutations subtree-by-subtree.
Workaround
Patching the dist chunks locally with pnpm patch / patch-package works fine. Happy to send a PR with the one-line fix if useful.
Summary
createOverlayControllerconfigures aMutationObserverondocument.bodywithattributes: trueand noattributeFilter, so the handler fires on every attribute mutation in the body subtree —style,class,id,aria-*,data-anything— even though the only attribute the library reads isdata-sanity. Any per-frame attribute writer (GSAP, anime.js, framer-motion'sstylemode, hand-rolled rAF) anywhere in the page cascades reducer dispatches at frame rate, which can blow React's render-depth limit when an unrelated state update lands on top.Source
src/ui/shared-state/SharedStateContext.ts, compiled in 3.2.4 todist/_chunks-es/SharedStateContext.jsanddist/_chunks-cjs/SharedStateContext.cjs:```js
mo = new MutationObserver(handleMutation)
mo.observe(document.body, {
attributes: true, // ← over-collection
characterData: true,
childList: true,
subtree: true,
})
```
Proposed fix
Add
attributeFilter: ['data-sanity']. The library's only consumer of attribute mutations is thedata-sanityparser; nothing else inhandleMutation's downstream path reads any other attribute, so this is a strict narrowing of what the observer sees with no behavior change for editors.```diff
mo.observe(document.body, {
attributes: true,
characterData: true,
childList: true,
subtree: true,
})
```
Repro
Any GSAP-animated element with a few
data-sanitydescendants will surface the cascade. Minimal recipe:data-sanityattributes inside a parent that GSAP animates per frame (e.g. `gsap.to(parent, { x: '-50%', repeat: -1, duration: 35 })`).Stack trace pattern: `MutationObserver.handleMutation` → `parseElements` → `updateElement` → `Overlays.tsx:162` reducer dispatch.
Why this matters
The library's docs encourage rich animations on content-driven pages, and the standard tools for those animations write to `style` attributes per frame. The current observer config makes Visual Editing incompatible with any of them in practice unless authors hand-suppress mutations subtree-by-subtree.
Workaround
Patching the dist chunks locally with
pnpm patch/patch-packageworks fine. Happy to send a PR with the one-line fix if useful.