docs(sdk): document CompositionVariable, id/variable utilities, and attachSync in canvas guide

Follow-up to the previous commit in this PR — found while auditing whether
any SDK-surface documentation gaps existed beyond this stack:

- types.mdx: EditOp's own union listing was missing declareVariable/
  removeVariable (present in edit-operations.mdx's table but not mirrored
  here). Adds a full CompositionVariable reference section (base fields +
  all 7 variants) since composition.mdx's new declareVariable/listVariables
  docs reference it without it being defined anywhere in the type reference.
- utilities.mdx: documents 6 exported functions with zero prior docs —
  resolveScoped, findById, bareId, escapeHfId, isNewHostBoundary (Id & Scope
  Utilities) and readVariableDefault (Variable Utilities). Pre-existing gaps,
  unrelated to this stack.
- canvas-integration.mdx: adds a "Keeping the preview in sync" section
  covering attachSync right where the guide already sets up preview + comp —
  previously the guide never mentioned it despite being exactly the answer
  to "how do I keep the iframe in sync with edits."
This commit is contained in:
Vance Ingalls
2026-07-09 11:52:14 -07:00
parent 91cc67a007
commit f169d5fad6
3 changed files with 184 additions and 0 deletions
+17
View File
@@ -32,6 +32,23 @@ The callback references `comp` before it is declared — that is intentional and
The `dispatch` callback is optional. Omitting it means `commitPreview()` is a no-op, which is useful if you want to handle op derivation yourself.
## Keeping the preview in sync
Everything above wires up hit-testing and drag — but the iframe still won't reflect edits made any other way (an inspector panel calling `comp.setStyle()` directly, an undo, a collaborator's change replayed via `applyPatches()`). `attachSync` closes that gap: call it once you have both `preview` and `comp`, and every future edit — including undo/redo — mirrors onto the live iframe automatically.
```typescript
const detach = preview.attachSync(comp);
// later, when the editor unmounts or swaps compositions:
detach();
```
`attachSync` does an immediate full sync of `comp`'s current state first (so re-opening a composition with existing overrides isn't a blank iframe), then subscribes to the same `patch` event your other listeners use. You don't need to write your own mirroring code, and you don't need a separate mechanism for undo/redo — both flow through the same subscription. Script-tag edits (GSAP script rewrites) are the one thing it never mirrors, since replaying a live `<script>` tag doesn't re-execute it.
<Note>
Calling `attachSync` again with a different `comp` detaches the previous subscription first — useful if your editor swaps which composition an iframe is bound to without remounting it.
</Note>
## Hit-testing: finding what the user clicked
`preview.elementAtPoint(x, y)` performs a synchronous hit-test at coordinates in the iframe's own coordinate space and returns the nearest `[data-hf-id]` element, or `null` for a transparent hit.