@printloop/frame-sync
Version:
Minimal iframe synchronization for React with Zod validation
2 lines • 2.01 kB
JavaScript
import{z as m}from"zod";import{useCallback as h,useEffect as y,useRef as g,useState as M,useSyncExternalStore as R,forwardRef as v}from"react";import{jsx as E}from"react/jsx-runtime";function z(o){return r=>{o.forEach(e=>{typeof e=="function"?e(r):e!=null&&(e.current=r)})}}function F({src:o,schema:r,targetOrigin:e="*"}){return v(function({onPropsChange:l,...i},c){let d=g(null),[,p]=M(!1),u=r.parse(i),t=g(u),n=h(async a=>{d?.current?.contentWindow?.postMessage({type:"change",value:a},e),t.current=a},[e]);return y(()=>{async function a(s){if(s.source!==window){if(s.data.type==="ready"){await n(t.current);return}if(s.data.type==="change"){let T=r.safeParse(s.data.value);if(!T.success)return;l?.(T.data)}}}return window.addEventListener("message",a),()=>{window.removeEventListener("message",a)}},[n]),y(()=>{let a=d.current;async function s(){a?.contentWindow?.postMessage({type:"change",value:t.current},e),await n(t.current),p(!1)}return a?.addEventListener("load",s),()=>{a?.removeEventListener("load",s)}},[n]),y(()=>{n(u)},[u,n]),E("iframe",{title:i.title,...i,src:o,ref:z([c,d])})})}var w=(e=>(e.Ready="ready",e.Change="change",e))(w||{}),b=m.object({type:m.nativeEnum(w),value:m.any()}),C=function({schema:o,initial:r,targetOrigin:e="*"}){let f,l=o.parse(r);function i(){return f??l}let c=new Set;function d(t){return c.add(t),()=>{c.delete(t)}}function p(t){if(t.data.source==="react-devtools-content-script"||t.source===window)return;let n=b.safeParse(t.data);if(n.success&&n.data.type!=="ready"&&n.data.type==="change"){let a=o.safeParse(n.data.value);if(!a.success)return;f=a.data;for(let s of c)s(f)}}function u(){window.addEventListener("message",p),window.parent.postMessage({type:"ready"},e)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",u,{once:!0}):u(),{useHostProps(){return R(d,i)},dispatchChange(t){let n={type:"change",value:t};window.parent.postMessage(n,e)}}};export{F as getGuestFrame,C as getHost};
//# sourceMappingURL=frame-sync.js.map