mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
feat(sdk): attachSync mirrors composition edits onto a live document
Adds attachSync(comp) to PreviewAdapter/IframePreviewAdapter — does an
immediate full sync via the existing applyOverrideSet, then subscribes to
comp.on('patch', ...) and replays every future patch (forward or inverse —
undo/redo included) via the existing applyPatchesToDocument, pointed at the
iframe's live document instead of the offscreen linkedom one. No new
mutation logic; both functions already work against any
{document, wrapped, stamped}-shaped object.
Also adds a no-op attachSync stub to HeadlessPreviewAdapter, required to
keep it satisfying the widened PreviewAdapter interface.
Closes the gap that made pacific's canvas-react hand-roll its own
override-application code (applyOverrideToIframe.ts) with two separate
mechanisms (diffing for normal edits, verbatim op-replay for undo/redo) —
subscribing to the patch stream directly needs only one.
This commit is contained in:
@@ -37,7 +37,8 @@ import {
|
||||
readCurrentTranslate,
|
||||
} from "@hyperframes/core/runtime/position-edits";
|
||||
import type { PreviewAdapter, ElementAtPointResult, DraftProps } from "./types.js";
|
||||
import type { EditOp } from "../types.js";
|
||||
import type { EditOp, Composition } from "../types.js";
|
||||
import { applyPatchesToDocument, applyOverrideSet } from "../engine/apply-patches.js";
|
||||
|
||||
// ─── Pure resolver (testable without a browser) ───────────────────────────────
|
||||
|
||||
@@ -511,6 +512,9 @@ class IframePreviewAdapter implements PreviewAdapter {
|
||||
*/
|
||||
private _draftPrevInlineTranslate: string | null = null;
|
||||
|
||||
/** Unsubscribe for the current attachSync subscription, if any. */
|
||||
private _syncDetach: (() => void) | null = null;
|
||||
|
||||
constructor(iframe: HTMLIFrameElement, dispatch?: (op: EditOp) => void) {
|
||||
this.iframe = iframe;
|
||||
this._dispatch = dispatch;
|
||||
@@ -740,6 +744,31 @@ class IframePreviewAdapter implements PreviewAdapter {
|
||||
const ids = [...this._selection];
|
||||
for (const h of this._handlers) h(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mirror `comp`'s edits onto this.iframe.contentDocument. See the
|
||||
* PreviewAdapter interface doc for the full contract.
|
||||
*/
|
||||
attachSync(comp: Composition): () => void {
|
||||
this._syncDetach?.();
|
||||
|
||||
const doc = this.iframe.contentDocument;
|
||||
if (doc) {
|
||||
applyOverrideSet({ document: doc, wrapped: false, stamped: "" }, comp.getOverrides());
|
||||
}
|
||||
|
||||
const unsubscribe = comp.on("patch", ({ patches }) => {
|
||||
const liveDoc = this.iframe.contentDocument;
|
||||
if (!liveDoc) return;
|
||||
applyPatchesToDocument(
|
||||
{ document: liveDoc, wrapped: false, stamped: "" },
|
||||
patches.filter((p) => p.path !== "/script/gsap"),
|
||||
);
|
||||
});
|
||||
|
||||
this._syncDetach = unsubscribe;
|
||||
return unsubscribe;
|
||||
}
|
||||
}
|
||||
|
||||
export function createIframePreviewAdapter(
|
||||
|
||||
Reference in New Issue
Block a user