Parent window
Connecting…

Async return values

postMessagewindowId
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);
};