Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quiet-dialogs-close.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@abstract-foundation/wallet-sdk": patch
---

Align the iframe dialog with the wallet host overlay model and close the dialog when wallet requests finish.
51 changes: 9 additions & 42 deletions packages/wallet-sdk/src/core/Dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export type DialogFactory = (parameters: {
// ---------- Internals ----------

const DEFAULT_POPUP_SIZE = { width: 420, height: 720 };
const DRAWER_BREAKPOINT = 460;

function getReferrer(): { title: string; icon?: string } {
if (typeof document === "undefined") return { title: "" };
Expand Down Expand Up @@ -162,16 +163,11 @@ export function iframe(options: IframeOptions = {}): DialogFactory {
if (!UserAgent.isFirefox()) allow.push("clipboard-write");
frame.setAttribute("allow", allow.join("; "));
frame.setAttribute("src", buildHostUrl(host, DIALOG_PATH));
// `position: fixed; left/top: 0; 100% × 100%` — the iframe escapes the
// <dialog> box and covers the entire viewport. Without this the dialog
// and iframe size each other circularly: the dialog auto-sizes to fit
// the iframe (`width: 100%`), the iframe sizes to fit the dialog, and
// the resolved size collapses to the user-agent default tiny box.
// Mirrors Porto's iframe positioning.
// Mirrors Porto's iframe positioning: the parent SDK backdrop stays
// transparent and the wallet host iframe owns the in-frame overlay/chrome.
Object.assign(frame.style, {
backgroundColor: "transparent",
border: "0",
colorScheme: "light dark",
position: "fixed",
left: "0",
top: "0",
Expand Down Expand Up @@ -203,44 +199,16 @@ export function iframe(options: IframeOptions = {}): DialogFactory {
waitForReady: true,
});

const applyHostResize = (
payload: Extract<Messenger.InternalPayload, { type: "resize" }>,
) => {
if (
typeof payload.width !== "number" &&
typeof payload.height !== "number"
)
return;

const width =
typeof payload.width === "number"
? Math.min(Math.max(payload.width, 1), window.innerWidth)
: window.innerWidth;
const height =
typeof payload.height === "number"
? Math.min(Math.max(payload.height, 1), window.innerHeight)
: window.innerHeight;
const drawer = width <= 460 || window.innerWidth <= 460;

Object.assign(frame.style, {
width: drawer ? "100%" : `${width}px`,
height: `${height}px`,
left: drawer ? "0" : "50%",
top: drawer ? "auto" : "50%",
bottom: drawer ? "0" : "auto",
transform: drawer ? "none" : "translate(-50%, -50%)",
} as CSSStyleDeclaration);
};
const offHostResize = messenger.on("__internal", (payload) => {
if (payload.type === "resize") applyHostResize(payload);
});

const drawerModeQuery = window.matchMedia("(max-width: 460px)");
const drawerModeQuery = window.matchMedia(
`(max-width: ${DRAWER_BREAKPOINT}px)`,
);
const sendResize = () => {
messenger.send("__internal", {
type: "resize",
// Match Porto's contract: 460 = drawer mode, 461 = floating mode.
width: drawerModeQuery.matches ? 460 : 461,
width: drawerModeQuery.matches
? DRAWER_BREAKPOINT
: DRAWER_BREAKPOINT + 1,
});
};
const onDrawerModeChange = () => {
Expand Down Expand Up @@ -354,7 +322,6 @@ export function iframe(options: IframeOptions = {}): DialogFactory {
}
inertObserver.disconnect();
drawerModeQuery.removeEventListener("change", onDrawerModeChange);
offHostResize();
messenger.destroy();
root.remove();
},
Expand Down
2 changes: 2 additions & 0 deletions packages/wallet-sdk/src/core/Wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,13 @@ export function createWallet(config: WalletConfig): Wallet {
}),
);
else p.resolve(response.result);
if (pending.size === 0) handle.close();
});
handle.messenger.on("__internal", (payload) => {
if (payload.type === "switch") void switchMode(payload.mode);
});
handle.messenger.on("close", () => {
handle.close();
// Reject every outstanding request with a user-rejected style error.
for (const [id, p] of pending) {
pending.delete(id);
Expand Down
1 change: 1 addition & 0 deletions turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"cache": true
},
"dev": {
"dependsOn": ["^build"],
"cache": false,
"persistent": true
}
Expand Down
Loading