@sendsay-ru/guidely-frame-bridge
v0.5.0
Published
Cross-origin iframe target resolver for Guidely.
Maintainers
Readme
@sendsay-ru/guidely-frame-bridge
Cross-origin iframe target resolver for Guidely.
Use this package when a Guidely tour runs in a host application, but some step targets live inside a strict cross-origin iframe. The host cannot read iframe DOM directly, so the bridge exchanges a small postMessage protocol with a cooperating script inside the iframe.
The protocol only transfers target status, rectangles, and target events. It never transfers DOM nodes or user-authored HTML.
The child announces when its bridge is ready. If the parent started watching targets before the child installed its message listener, the parent automatically requests those targets again after the readiness handshake.
Install
yarn add @sendsay-ru/guidely-frame-bridge@sendsay-ru/guidely is a peer dependency.
Quick Start
Parent application:
import { createGuidely } from "@sendsay-ru/guidely";
import { createFrameTargetResolver } from "@sendsay-ru/guidely-frame-bridge";
const iframe = document.querySelector<HTMLIFrameElement>("#email-builder-frame");
if (!iframe) {
throw new Error("Email builder iframe was not found");
}
const frameTargets = createFrameTargetResolver({
iframe,
bridgeId: "account-email-builder",
targetOrigin: "https://builder.example.com",
allowedOrigins: ["https://builder.example.com"],
timeout: 1000,
});
const guidely = createGuidely({
config,
adapter,
targetResolver: frameTargets,
});Iframe application:
import { connectGuidelyFrameBridge } from "@sendsay-ru/guidely-frame-bridge";
const disconnectGuidely = connectGuidelyFrameBridge({
bridgeId: "account-email-builder",
targetOrigin: "https://account.example.com",
allowedOrigins: ["https://account.example.com"],
attributePrefix: "guidely",
});Targets inside the iframe use the same Guidely target config:
<input data-guidely-id="email-subject" /> <button data-guidely-id="send-test">Send test</button>const config = {
version: 1,
flows: [
{
id: "builder-tour",
steps: [
{
id: "subject",
type: "tooltip",
target: { type: "data-id", value: "email-subject" },
content: { en: { body: "This target is inside the iframe." } },
},
{
id: "send-test",
type: "tooltip",
target: { type: "data-id", value: "send-test" },
advanceOn: { event: "click" },
content: { en: { body: "Click inside the iframe to continue." } },
},
],
},
],
};Mixed Host and Iframe Targets
Guidely core composes custom target resolvers with the default DOM resolver. That means a single host Guidely instance can resolve:
- regular host application targets through
data-guidely-idor CSS selectors; - iframe targets through
createFrameTargetResolver.
No manual resolver composition is required for the common one-iframe setup.
Parent API
createFrameTargetResolver(options)
Creates a Guidely targetResolver for the parent application.
const resolver = createFrameTargetResolver({
iframe,
bridgeId,
targetOrigin,
allowedOrigins,
timeout,
});Options:
iframe: the iframe element containing the child application.bridgeId: shared identifier used by parent and child to reject unrelated messages.targetOrigin: exact origin used when posting messages to the iframe.*is rejected.allowedOrigins: origins accepted from incoming iframe messages. Defaults to[targetOrigin].timeout: request timeout in milliseconds. Defaults to1000.window: optional window override, mainly for tests.
Return value:
- A
TTargetResolvercompatible object. destroy(): removes parent message listeners and clears pending requests.
Child API
connectGuidelyFrameBridge(options)
Connects the iframe application to the parent resolver.
const cleanup = connectGuidelyFrameBridge({
bridgeId,
targetOrigin,
allowedOrigins,
attributePrefix,
});Options:
bridgeId: same value as the parent resolver.targetOrigin: exact parent origin used when posting messages.*is rejected.allowedOrigins: origins accepted from incoming parent messages. Defaults to[targetOrigin].attributePrefix: prefix fordata-${prefix}-idtargets. Defaults toguidely.window,document,parentWindow: optional overrides, mainly for tests.
Return value:
- A cleanup function that removes listeners, observers, and event subscriptions.
Protocol and Security
Every message includes:
source:@sendsay-ru/guidely-frame-bridge;version: protocol version;bridgeId: shared parent/child bridge identifier;requestId: per-message request identifier.
The bridge validates:
- explicit
targetOrigin; wildcard origins are rejected; event.originagainstallowedOrigins;event.sourceagainst the expected frame or parent window;bridgeId;- protocol version;
- required protocol fields.
Messages carry only:
- bridge readiness;
- target selectors from the Guidely config;
rectvalues in iframe viewport coordinates;statusvalues;- target event names.
The parent converts iframe-local rects to parent viewport coordinates by adding iframe.getBoundingClientRect().
Updates
The child bridge sends rect updates after:
- iframe document scroll;
- iframe window resize;
- DOM mutations;
- target
ResizeObserverchanges when available.
The parent resolver also watches the iframe element position, so a host-page scroll or iframe movement updates the final parent-viewport rect.
Example
See examples/frame-bridge for a runnable parent + iframe demo.
