The return-value pattern
The return-value pattern over the legacy
postMessage transport. The call shape is identical to the BroadcastChannel demo — what differs is that the child shares the parent's event loop. Pick this transport when you want the simplest setup and the windows are short-lived; pick BroadcastChannel when the child runs alongside a busy parent.Last result
Whatever the child popup most recently returned.
// no result yet
Code
Both sides of the pattern. The parent awaits a typed value; the child turns user interaction into a procedure return.
parent.tsx
// Parent: open the popup and await a typed value.
// The postMessage transport keeps `window.opener` wired up, so the
// parent and child share an agent cluster and an event loop. Same shape
// as the BroadcastChannel demo — only the option differs.
const child = await iwpc.open(`./child4?kind=color`, {
width: 520,
height: 540
});
const hex = await child.invoke<void, string | null>(
'PICK_COLOR',
undefined,
{ timeout: 5 * 60 * 1000 } // generous, the user is in the loop
);
if (hex === null) {
// user cancelled
} else {
setColor(hex);
}child.tsx
// Child: turn a user interaction into a procedure return value.
// Identical to the BroadcastChannel child — the call shape is the same.
const resolverRef = useRef<((v: string | null) => void) | null>(null);
useEffect(() => {
iwpc?.register('PICK_COLOR', () => {
return new Promise<string | null>((resolve) => {
resolverRef.current = resolve;
});
});
return () => iwpc?.unregister('PICK_COLOR');
}, [iwpc]);
const onPick = (hex: string) => {
resolverRef.current?.(hex);
resolverRef.current = null;
setTimeout(() => iwpc?.close(), 120);
};