PageSourceSearch

https://toolbreezy.com/_next/static/chunks/21938-bac482d8852f0a5b.js

js toolbreezy.com collected 2026-09-24 14:58:10 UTC 51,314 bytes, 95 lines download raw bytes

1"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[21938],{21938:(e,t,r)=>{r.r(t),r.d(t,{allowValue:()=>U,buildAttrs:()=>I,buildCss:()=>q,buildFacade:()=>X,buildHtml:()=>J,buildJsx:()=>Y,buildMdx:()=>B,buildWordpress:()=>_,checkSrc:()=>z,configFromAttrs:()=>Q,default:()=>er,detectProvider:()=>F,htmlTag:()=>E,parseRatio:()=>O,parseSnippet:()=>Z,parseTimestamp:()=>L,ratioPercent:()=>R,runChecklist:()=>K,swapNoCookie:()=>W});var s=r(95155),a=r(12115),i=r(27784),n=r(97003),o=r(33789),l=r(90235),d=r(67001),c=r(33534),h=r(69869),u=r(12513),m=r(25016),p=r(52863);let f="6 seconds",g="toolbreezy:html-iframe-generator",b=["s","c"];function x(e){if(!e)return{};try{let t=JSON.parse(e);return t&&"object"==typeof t?t:{}}catch{return{}}}let w=[{v:"allow-scripts",what:"Runs JavaScript inside the frame.",breaks:"No script runs, so most widgets show a blank panel or a static shell."},{v:"allow-same-origin",what:"Keeps the page on its real origin instead of a throwaway one.",breaks:"The frame loses cookies, localStorage and IndexedDB, which signs the user out of anything they were logged into.",risk:"Combined with allow-scripts on content from your own origin, the frame can reach its own frame element and delete the sandbox attribute."},{v:"allow-forms",what:"Lets the framed page submit a form.",breaks:"Form submissions fail with no error at all. The button just does nothing."},{v:"allow-popups",what:"Lets the frame open a new window or tab.",breaks:'A target="_blank" link inside the frame does nothing when clicked.'},{v:"allow-downloads",what:"Lets the frame start a file download.",breaks:"A download button inside the frame does nothing."},{v:"allow-modals",what:"Lets the frame open alert, confirm and prompt boxes.",breaks:"Calls to alert and confirm are ignored, which some older widgets rely on.",risk:"The framed page can put a blocking dialog over your page whenever it likes."},{v:"allow-popups-to-escape-sandbox",what:"Windows opened from the frame start with no sandbox.",risk:"Anything the frame pops open runs unrestricted, which undoes the sandbox one click later."},{v:"allow-top-navigation",what:"Lets the frame navigate the whole tab.",risk:"The framed page can send your visitor somewhere else with no click and no warning."},{v:"allow-top-navigation-by-user-activation",what:"Lets the frame navigate the whole tab, but only after a real click.",risk:"The framed page can still take over the tab, it just needs the visitor to click something first."},{v:"allow-top-navigation-to-custom-protocols",what:"Lets the frame open links that hand off to an installed app.",risk:"The frame can trigger an external app handler from your page."},{v:"allow-presentation",what:"Lets the frame cast to a second screen.",breaks:"Casting from inside the frame is refused."},{v:"allow-pointer-lock",what:"Lets the frame capture the mouse.",breaks:"Games and 3D viewers cannot lock the pointer, so drag-to-look stops working."},{v:"allow-orientation-lock",what:"Lets the frame lock screen orientation.",breaks:"A video player cannot force landscape on a phone."},{v:"allow-storage-access-by-user-activation",what:"Lets the frame ask for access to its own cookies after a click.",breaks:"The frame cannot even ask, so third-party login flows have no route back in."}],y=new Map(w.map(e=>[e.v,e])),v=[{v:"fullscreen",plain:"Going fullscreen from inside the frame."},{v:"autoplay",plain:"Starting media without a click. Browsers still mute it in most cases."},{v:"encrypted-media",plain:"Playing DRM protected video. Netflix style players need this."},{v:"picture-in-picture",plain:"Popping the video out into a floating window."},{v:"clipboard-write",plain:"Writing to the clipboard, used by share and copy-link buttons."},{v:"web-share",plain:"Opening the operating system share sheet."},{v:"camera",plain:"Reading the camera. Grant this only to a video call or scanner widget."},{v:"microphone",plain:"Reading the microphone."},{v:"geolocation",plain:"Reading the visitor location."},{v:"display-capture",plain:"Screen sharing from inside the frame."},{v:"payment",plain:"Using the Payment Request API."},{v:"accelerometer",plain:"Reading motion sensors. Some 360 video players use it."},{v:"gyroscope",plain:"Reading rotation sensors, same story as accelerometer."},{v:"midi",plain:"Talking to MIDI devices."}],k=[{v:"",note:"Attribute left off. The browser falls back to whatever the page sets."},{v:"no-referrer",note:"Sends nothing. The safest, and it breaks referrer based allowlists."},{v:"no-referrer-when-downgrade",note:"Sends the full URL except when going from https to http."},{v:"origin",note:"Sends only your domain, never the path."},{v:"origin-when-cross-origin",note:"Full URL to your own site, domain only to anyone else."},{v:"same-origin",note:"Sends the referrer to your own site only."},{v:"strict-origin",note:"Domain only, and nothing at all on an https to http downgrade."},{v:"strict-origin-when-cross-origin",note:"The modern browser default, so setting it changes nothing unless your page overrides it."},{v:"unsafe-url",note:"Sends the full URL to everyone. Leaks paths and query strings."}],j="strict-origin-when-cross-origin",N=["16:9","4:3","1:1","3:2","21:9","9:16"],$=[{v:"aspect",label:"Aspect ratio",blurb
1:"Fills the width it is given and keeps its shape. The right default for video."},{v:"padding",label:"Padding fallback",blurb:"The same result using the old percentage trick, for very old browsers."},{v:"fullwidth",label:"Full width, fixed height",blurb:"For forms, calendars and anything that scrolls internally."},{v:"fixed",label:"Fixed pixels",blurb:"Exact size, no wrapper. It will overflow a narrow phone."},{v:"fill",label:"Fill the parent",blurb:"Stretches to whatever box you drop it in. That box needs a real height."}],S=["allow-top-navigation","allow-top-navigation-by-user-activation","allow-top-navigation-to-custom-protocols","allow-modals","allow-popups-to-escape-sandbox"],T=["allow-scripts","allow-same-origin","allow-forms","allow-popups"],C=["javascript:","data:","file:","blob:","vbscript:"];function z(e){let t,r,s=e.trim();if(!s)return{ok:!1,url:""};let a=s.toLowerCase();for(let e of C)if(a.startsWith(e))return{ok:!1,url:s,scheme:e.replace(":",""),problem:`A ${e.replace(":","")} URL is refused here. An iframe src has to be http or https.`};let i=s;if(!/^[a-z][a-z0-9+.-]*:/i.test(i))if(i.startsWith("//"))i=`https:${i}`,t="Added https: to a protocol relative URL.";else{if(i.startsWith("/"))return{ok:!0,url:i,scheme:"relative"};i=`https://${i}`,t="Added https:// because the URL had no scheme."}try{r=new URL(i)}catch{return{ok:!1,url:s,problem:"That is not a URL a browser can load."}}let n=r.protocol.replace(":","");return"http"!==n&&"https"!==n?{ok:!1,url:i,scheme:n,problem:`The ${n} scheme cannot be used as an iframe src.`}:{ok:!0,url:i,repaired:t,scheme:n}}function L(e){if(!e)return null;let t=e.trim().toLowerCase();if(!t)return null;if(/^\d+$/.test(t)){let e=Number(t);return Number.isFinite(e)&&e>0?e:null}let r=t.match(/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/);if(!r||!r[1]&&!r[2]&&!r[3])return null;let s=3600*Number(r[1]??0)+60*Number(r[2]??0)+Number(r[3]??0);return s>0?s:null}function O(e){let t=e.trim().match(/^(\d+(?:\.\d+)?)\s*[:/x]\s*(\d+(?:\.\d+)?)$/i);if(!t)return null;let r=Number(t[1]),s=Number(t[2]);return!Number.isFinite(r)||!Number.isFinite(s)||r<=0||s<=0?null:{w:r,h:s}}function R(e,t){return`${Number((t/e*100).toFixed(4))}%`}function A(e,t,r){if(!Number.isFinite(e))return t;let s=Math.round(e);return s<t?t:s>r?r:s}let M=e=>e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;");function F(e){let t;try{t=new URL(e)}catch{return null}let r=t.hostname.replace(/^www\./,"").toLowerCase(),s=t.pathname.split("/").filter(Boolean),a=[];if("youtu.be"===r||r.endsWith("youtube.com")||r.endsWith("youtube-nocookie.com")){let e=null;if("youtu.be"===r?e=s[0]??null:"watch"===s[0]?e=t.searchParams.get("v"):("shorts"===s[0]||"live"===s[0]||"embed"===s[0]||"v"===s[0])&&(e=s[1]??null),e&&/^[A-Za-z0-9_-]{6,}$/.test(e)){let i=L(t.searchParams.get("t"))??L(t.searchParams.get("start")),n=r.endsWith("youtube-nocookie.com"),o=i?`?start=${i}`:"";return"embed"!==s[0]&&a.push("Rewrote the watch link to the /embed/ form, which is the only one that loads in a frame."),i&&a.push(`Carried the ${i} second start time across as start=${i}. Share links use t=, the embed uses start=.`),"shorts"===s[0]&&a.push("A Shorts link is a normal video, so 9:16 is set for you."),{name:"YouTube",src:`${n?"https://www.youtube-nocookie.com":"https://www.youtube.com"}/embed/${e}${o}`,notes:a,allow:["accelerometer","autoplay","clipboard-write","encrypted-media","gyroscope","picture-in-picture","web-share","fullscreen"],title:"YouTube video player",ratio:"shorts"===s[0]?"9:16":"16:9",size:"aspect",noCookieCapable:!0}}}if(r.endsWith("vimeo.com")){let e=function(e){for(let t=e.length-1;t>=0;t--)if(/^\d+$/.test(e[t]))return e[t];return null}(s);if(e){let s=L(t.hash.replace(/^#t=/,""))??L(t.searchParams.get("t"));return"player.vimeo.com"!==r&&a.push("Rewrote the page link to the player.vimeo.com form."),s&&a.push(`Carried the start time across as #t=${s}s.`),{name:"Vimeo",src:`https://player.vimeo.com/video/${e}${s?`#t=${s}s`:""}`,notes:a,allow:["autoplay","fullscreen","picture-in-picture","clipboard-write"],title:"Vimeo video player",ratio:"16:9",size:"aspect"}}}if(r.endsWith("loom.com")&&("share"===s[0]||"embed"===s[0])&&s[1])return"share"===s[0]&&a.push("Swapped /share/ for /embed/. The share page itself refuses to be framed."),{name:"Lo
1om",src:`https://www.loom.com/embed/${s[1]}`,notes:a,allow:["fullscreen"],title:"Loom recording",ratio:"16:9",size:"aspect"};if("docs.google.com"===r){let e=s[0],r="d"===s[1]?s[2]:null;if("document"===e&&r)return a.push("Swapped /edit for /preview so viewers get the read-only version instead of the editor."),{name:"Google Docs",src:`https://docs.google.com/document/d/${r}/preview`,notes:a,title:"Google Docs document",size:"fullwidth",height:780};if("spreadsheets"===e&&r)return a.push("Swapped /edit for /preview. Sharing has to be set to anyone with the link or your visitors see a sign-in wall."),{name:"Google Sheets",src:`https://docs.google.com/spreadsheets/d/${r}/preview`,notes:a,title:"Google Sheets spreadsheet",size:"fullwidth",height:640};if("presentation"===e&&r)return a.push("Rewrote to the /embed form with autoplay off, which is the version that behaves in a frame."),{name:"Google Slides",src:`https://docs.google.com/presentation/d/${r}/embed?start=false&loop=false&delayms=3000`,notes:a,title:"Google Slides presentation",ratio:"16:9",size:"aspect",allow:["fullscreen"]};if("forms"===e){let e=new URL(t.toString());return e.searchParams.set("embedded","true"),a.push("Added embedded=true, which strips the Google chrome from the form."),{name:"Google Forms",src:e.toString(),notes:a,title:"Google Form",size:"fullwidth",height:760}}}if(r.endsWith("google.com")&&"maps"===s[0])return"embed"===s[1]?{name:"Google Maps",src:t.toString(),notes:["This is already the official embed URL, so it is left alone."],title:"Google Map",ratio:"4:3",size:"aspect",allow:["fullscreen"]}:{name:"Google Maps",src:t.toString(),notes:["Google Maps only frames its own embed URL, and it is not something that can be built from a normal map link. Open the map, press Share, choose Embed a map, and paste the src from the code it gives you."],title:"Google Map",ratio:"4:3",size:"aspect"};if(r.endsWith("openstreetmap.org")){if(t.pathname.includes("/export/embed.html"))return{name:"OpenStreetMap",src:t.toString(),notes:["Already the embed URL, left alone."],title:"OpenStreetMap map",ratio:"4:3",size:"aspect"};let e=t.hash.match(/map=(\d+(?:\.\d+)?)\/(-?\d+(?:\.\d+)?)\/(-?\d+(?:\.\d+)?)/);if(e){let t=Number(e[1]),r=Number(e[2]),s=Number(e[3]),i=360/Math.pow(2,t),n=i/2,o=[s-i/2,r-n/2,s+i/2,r+n/2].map(e=>Number(e.toFixed(5))).join(",");return a.push("Built the export embed URL from the zoom and center in your link. The box is worked out from the zoom level, so nudge the bbox numbers if the framing is slightly off."),{name:"OpenStreetMap",src:`https://www.openstreetmap.org/export/embed.html?bbox=${encodeURIComponent(o)}&layer=mapnik&marker=${r},${s}`,notes:a,title:"OpenStreetMap map",ratio:"4:3",size:"aspect"}}}if("open.spotify.com"===r){let e="embed"===s[0]?s[1]:s[0],t="embed"===s[0]?s[2]:s[1];if(e&&t&&["track","album","playlist","episode","show","artist"].includes(e))return"embed"!==s[0]&&a.push("Rewrote to the /embed/ path. The normal Spotify page refuses to be framed."),{name:"Spotify",src:`https://open.spotify.com/embed/${e}/${t}`,notes:a,allow:["autoplay","clipboard-write","encrypted-media","fullscreen","picture-in-picture"],title:`Spotify ${e}`,size:"fullwidth",height:"track"===e||"episode"===e?152:352}}return r.endsWith("calendly.com")&&s.length>=1?{name:"Calendly",src:t.toString(),notes:["Calendly frames its normal booking link as-is, so the URL is unchanged. It needs room, so a fixed height is set."],title:"Calendly booking calendar",size:"fullwidth",height:700}:r.endsWith("codepen.io")&&"pen"===s[1]&&s[2]?(a.push("Swapped /pen/ for /embed/ and asked for the result tab first."),{name:"CodePen",src:`https://codepen.io/${s[0]}/embed/${s[2]}?default-tab=result`,notes:a,allow:["fullscreen"],title:"CodePen example",size:"fullwidth",height:420}):null}function W(e,t){return t?e.replace(/(^https?:\/\/(?:www\.)?)youtube\.com/i,"$1youtube-nocookie.com"):e.replace(/(^https?:\/\/(?:www\.)?)youtube-nocookie\.com/i,"$1youtube.com")}let P={src:"",useSrcdoc:!1,srcdoc:'<p style="font:16px system-ui">Hello from inside the frame.</p>',title:"",size:"aspect",ratio:"16:9",width:560,height:400,maxWidth:0,lazy:!0,referrer:"strict-origin",sandboxOn:!0,sandboxTokens:["allow-scripts","allow-same-origin","allow-popups","allow-forms"],features:["fullscreen"],featureOrigins:{},perOrigin:!1,legacyFullscreen:!1,credentialless:!1,className:"responsive-embed",noCookie:!1};function U(e){return e.features.length?e.features.map(t=>{if(!e.perOrigin)return t;let r=(e.featureOrigins[t]??"'src'").trim();return r?`${t} ${r}`:t}).join("; "):""}function H(e){switch(e.size){case"fixed":return"border:0";case"fullwidth":return`width:100%;height:${e.height}px;border:0`;case"fill":return"width:100%;height:100%;border:0";default:return""}}function I(e){let t=[];e.useSrcdoc?t.push({name:"srcdoc",value:e.srcdoc}):t.push({name:"src",value:e.src}),t.push({name:"title",value:e.title}),"fixed"===e.size&&(t.push({name:"width",value:String(e.width)}),t.push({name:"height",value:String(e.height)})),e.lazy&&t.push({name:"loading",value:"lazy"}),e.referrer&&t.push({name:"referrerpolicy",value:e.referrer}),e.sandboxOn&&t.push({name:"sandbox",value:e.sandboxTokens.join(" ")});let r=U(e);if(e.legacyFullscreen){let r=U({...e,features:e.features.filter(e=>"fullscreen"!==e)});r&&t.push({name:"allow",value:r}),e.features.includes("fullscreen")&&t.push({name:"allowfullscreen",value:null})}else r&&t.push({name:"allow",value:r});e.credentialless&&t.push({name:"credentialless",value:null});let s=H(e);
1return s&&t.push({name:"style",value:s}),t}function G(e){return"aspect"===e.size||"padding"===e.size}function q(e){if(!G(e))return"";let t=O(e.ratio)??{w:16,h:9},r=e.className||"responsive-embed",s=e.maxWidth>0?`
2  max-width: ${e.maxWidth}px;
3  margin-inline: auto;`:"";return"aspect"===e.size?`.${r} {
4  width: 100%;${s}
5  aspect-ratio: ${t.w} / ${t.h};
6}
7.${r} > iframe {
8  display: block;
9  width: 100%;
10  height: 100%;
11  border: 0;
12}`:`.${r} {
13  position: relative;
14  width: 100%;${s}
15  padding-top: ${R(t.w,t.h)};
16}
17.${r} > iframe {
18  position: absolute;
19  top: 0;
20  left: 0;
21  width: 100%;
22  height: 100%;
23  border: 0;
24}`}function E(e){let t=I(e).map(e=>null===e.value?`  ${e.name}`:`  ${e.name}="${M(e.value)}"`).join("\n");return`<iframe
25${t}
26></iframe>`}function J(e){let t=q(e),r=E(e);if(!G(e))return r;let s=e.className||"responsive-embed",a=r.split("\n").map(e=>`  ${e}`).join("\n");return`<style>
27${t}
28</style>
29
30<div class="${M(s)}">
31${a}
32</div>`}let D={srcdoc:"srcDoc",referrerpolicy:"referrerPolicy",allowfullscreen:"allowFullScreen",class:"className"};function Y(e){let t=I(e).filter(e=>"style"!==e.name).map(e=>(function(e,t){let r=D[e]??e;return null===t?`  ${r}`:t.includes("&")||t.includes('"')||t.includes("\n")?`  ${r}={${JSON.stringify(t)}}`:`  ${r}="${t}"`})(e.name,e.value)),r=H(e);if(r){let e=r.split(";").filter(Boolean).map(e=>{let[t,r]=e.split(":"),s=(t??"").trim().replace(/-([a-z])/g,(e,t)=>t.toUpperCase()),a=(r??"").trim();return/^\d+$/.test(a)?`${s}: ${a}`:`${s}: '${a}'`}).join(", ");t.push(`  style={{ ${e} }}`)}let s=`<iframe
33${t.join("\n")}
34/>`;if(!G(e))return s;let a=e.className||"responsive-embed",i=s.split("\n").map(e=>`  ${e}`).join("\n");return`/* Put this in your stylesheet or CSS module */
35${q(e)}
36
37<div className="${a}">
38${i}
39</div>`}function _(e){let t=J(e).split("\n").join("\n");return`<!-- Paste into a Custom HTML block, not the visual editor. -->
40<!-- wp:html -->
41${t}
42<!-- /wp:html -->
43
44<!-- If the iframe vanishes after you save, your host or a security plugin is stripping it.
45     That is a server-side filter, not a mistake in this code. Ask them to allow iframes for
46     your role, or move the markup into a child theme template where the filter does not run. -->`}function B(e){return`{/* MDX renders JSX, so this works. Plain .md files only render raw HTML when the site
47    has HTML passthrough switched on, and many do not. Check before you rely on it. */}
48
49`+Y(e)}function X(e,t){let r=e.className||"responsive-embed",s=O(e.ratio)??{w:16,h:9},a=I(e).filter(e=>"src"!==e.name&&"srcdoc"!==e.name&&"style"!==e.name&&"loading"!==e.name).map(e=>null===e.value?`${e.name}`:`${e.name}=&quot;${M(e.value).replace(/"/g,"&quot;")}&quot;`).join(" "),i=t.trim()?`
50  background: #111 url('${t.trim().replace(/'/g,"\\'")}') center/cover no-repeat;`:"\n  background: #111;";return`<style>
51.${r}-facade {
52  position: relative;
53  width: 100%;
54  aspect-ratio: ${s.w} / ${s.h};
55  border: 0;
56  padding: 0;
57  cursor: pointer;${i}
58}
59.${r}-facade::after {
60  content: '';
61  position: absolute;
62  top: 50%;
63  left: 50%;
64  width: 0;
65  height: 0;
66  transform: translate(-40%, -50%);
67  border-style: solid;
68  border-width: 22px 0 22px 36px;
69  border-color: transparent transparent transparent #fff;
70}
71.${r} {
72  width: 100%;
73  aspect-ratio: ${s.w} / ${s.h};
74}
75.${r} > iframe {
76  display: block;
77  width: 100%;
78  height: 100%;
79  border: 0;
80}
81</style>
82
83<button class="${r}-facade" type="button" aria-label="Load ${M(e.title||"the embedded content")}"
84        data-embed-src="${M(e.src)}"></button>
85
86<script>
87document.querySelectorAll('.${r}-facade').forEach(function (btn) {
88  btn.addEventListener('click', function () {
89    var wrap = document.createElement('div');
90    wrap.className = '${r}';
91    wrap.innerHTML = '<iframe src=&quot;' + btn.dataset.embedSrc + '&quot; ${a}></iframe>';
92    btn.replaceWith(wrap);
93  }, { once: true });
94});
95</script>`}let V={frameborder:"frameborder is gone from the spec. Replaced with border:0 in CSS, which is what it always meant.",marginwidth:"marginwidth was dropped from HTML5 and no browser has honored it for years. Removed.",marginheight:"marginheight was dropped from HTML5 and no browser has honored it for years. Removed.",align:"align w
95as dropped from HTML5. Position the wrapper with CSS instead.",longdesc:"longdesc was dropped and screen readers never supported it well. A visible link near the frame does the job.",hspace:"hspace was dropped from HTML5. Use CSS margin.",vspace:"vspace was dropped from HTML5. Use CSS margin.",scrolling:"scrolling is gone and there is no replacement you can apply from outside. Setting overflow on the iframe element does not control the framed page, only the framed page own CSS can do that. Nothing has been substituted for it here, because nothing works."};function Z(e){let t,r=(e.length>8e3?e.slice(0,8e3):e).match(/<iframe\b([\s\S]*?)>/i);if(!r)return null;let s=r[1]??"",a={},i=/([a-zA-Z_:][-a-zA-Z0-9_:.]*)\s*(?:=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+)))?/g;for(;null!==(t=i.exec(s));){let e=(t[1]??"").toLowerCase();e&&(a[e]=t[2]??t[3]??t[4]??"")}a.srcdoc&&(a.srcdoc=a.srcdoc.replace(/&quot;/g,'"').replace(/&amp;/g,"&")),a.src&&(a.src=a.src.replace(/&amp;/g,"&"));let n=[];for(let[e,t]of Object.entries(V))e in a&&n.push(t);return a.title&&a.title.trim()||n.push('There was no title, so a screen reader announced this frame as just "iframe". A title is now required before any code comes out.'),"loading"in a||n.push('Added loading="lazy" so the embed does not fetch until it is close to the viewport.'),"sandbox"in a||n.push("No sandbox was set, so the framed page ran with every capability. Turn the sandbox on and grant back what it needs."),"referrerpolicy"in a||n.push("No referrerpolicy, so the full URL of your page was being sent to the framed site."),e.length>8e3&&n.push("Only the first 8000 characters of what you pasted were read. Anything after that was not included."),{attrs:a,changes:n}}function Q(e,t){let r={...e,featureOrigins:{...e.featureOrigins}};if(t.srcdoc?(r.useSrcdoc=!0,r.srcdoc=t.srcdoc):t.src&&(r.useSrcdoc=!1,r.src=t.src),t.title&&(r.title=t.title),("lazy"===t.loading||"eager"===t.loading)&&(r.lazy="lazy"===t.loading),t.referrerpolicy&&k.some(e=>e.v===t.referrerpolicy)&&(r.referrer=t.referrerpolicy),"sandbox"in t&&(r.sandboxOn=!0,r.sandboxTokens=t.sandbox.split(/\s+/).filter(e=>y.has(e))),t.allow){let e=[],s={},a=!1;for(let r of t.allow.split(";")){let t=r.trim().split(/\s+/).filter(Boolean),i=t[0];i&&v.some(e=>e.v===i)&&(e.push(i),t.length>1&&(s[i]=t.slice(1).join(" "),a=!0))}e.length&&(r.features=e,r.featureOrigins={...r.featureOrigins,...s},r.perOrigin=a)}"allowfullscreen"in t&&(r.legacyFullscreen=!0,r.features.includes("fullscreen")||(r.features=[...r.features,"fullscreen"])),"credentialless"in t&&(r.credentialless=!0);let s=Number(t.width),a=Number(t.height);return Number.isFinite(s)&&s>0&&(r.width=A(s,1,4e3)),Number.isFinite(a)&&a>0&&(r.height=A(a,1,4e3)),Number.isFinite(s)&&Number.isFinite(a)&&s>0&&a>0&&(r.size="aspect",r.ratio=`${Math.round(s)}:${Math.round(a)}`),r}function K(e,t){let r=[];r.push({ok:e.title.trim().length>=3,label:"The frame has an accessible name",detail:e.title.trim().length>=3?`A screen reader announces "${e.title.trim()}, frame".`:"With no title, a screen reader announces this as an unnamed frame and the user has no idea what is in it. This is technique H64, the accepted way of meeting success criterion 4.1.2."});let s=e.useSrcdoc||"https"===t.scheme||"relative"===t.scheme;r.push({ok:s,label:"The source is https",detail:s?"No mixed content problem.":"An http source inside an https page is mixed content. The browser blocks it outright and you get an empty box with a console warning."}),r.push({ok:e.sandboxOn,label:"A sandbox is set",detail:e.sandboxOn?`Granting ${e.sandboxTokens.length} of the ${w.length} tokens back.`:"Without a sandbox attribute the framed page runs with everything: scripts, forms, popups, storage, the lot."});let a=e.sandboxOn&&e.sandboxTokens.includes("allow-scripts")&&e.sandboxTokens.includes("allow-same-origin");r.push({ok:!a,label:"The sandbox is not cancelling itself out",detail:a?"allow-scripts and allow-same-origin together let content from your own origin reach its own frame element and strip the sandbox attribute off. For third-party content this pair is normal and fine. For anything you host yourself it means the sandbox is decoration.":"No self-cancelling pair."}
95),r.push({ok:e.lazy,label:"Loading is deferred",detail:e.lazy?'loading="lazy" holds the request until the frame is near the viewport. It has no effect on a frame that is already on screen at load.':"The embed downloads with the rest of the page, third-party scripts and all."}),r.push({ok:""!==e.referrer,label:"A referrer policy is set",detail:""===e.referrer?"With no policy the frame inherits the page setting, which usually sends your domain to the third party.":e.referrer===j?"This is the modern browser default, so the attribute is doing nothing unless your page overrides it elsewhere.":`Set to ${e.referrer}.`});let i="fixed"!==e.size;r.push({ok:i,label:"It survives a narrow screen",detail:i?"The generated code sizes itself against the container rather than a fixed pixel width.":"A fixed pixel width wider than the phone it lands on pushes a horizontal scrollbar onto the whole page."});let n=e.features.filter(e=>["camera","microphone","geolocation","display-capture","payment","midi"].includes(e));return r.push({ok:0===n.length,label:"No sensitive capability handed over",detail:0===n.length?"The allow list holds nothing that reaches hardware or personal data.":`You are granting ${n.join(", ")}. Fine if the widget genuinely needs it, worth deleting if you copied the allow list from somewhere.`}),r}function ee({title:e,hint:t,children:r}){return(0,s.jsxs)("section",{className:"rounded-lg border border-input p-4",children:[(0,s.jsx)("h3",{className:"text-sm font-semibold",children:e}),t?(0,s.jsx)("p",{className:"mt-0.5 text-xs text-muted-foreground",children:t}):null,(0,s.jsx)("div",{className:"mt-3 space-y-3",children:r})]})}function et({checked:e,onChange:t,label:r,hint:a}){return(0,s.jsxs)("label",{className:"flex cursor-pointer items-start gap-2 text-sm",children:[(0,s.jsx)("input",{type:"checkbox",checked:e,onChange:e=>t(e.target.checked),className:"mt-0.5 h-4 w-4 shrink-0 accent-primary"}),(0,s.jsxs)("span",{children:[(0,s.jsx)("span",{className:"font-medium",children:r}),a?(0,s.jsx)("span",{className:"block text-xs text-muted-foreground",children:a}):null]})]})}function er(){let[e,t]=(0,a.useState)(P),[r,C]=(0,a.useState)(""),[L,M]=(0,a.useState)([]),[H,I]=(0,a.useState)(null),[D,V]=(0,a.useState)(!1),[er,es]=(0,a.useState)(null),[ea,ei]=(0,a.useState)(""),[en,eo]=(0,a.useState)(null),[el,ed]=(0,a.useState)(!1),[ec,eh]=(0,a.useState)("html"),[eu,em]=(0,a.useState)(""),[ep,ef]=(0,a.useState)(null),[eg,eb]=(0,a.useState)(null),[ex,ew]=(0,a.useState)(0),[ey,ev]=(0,a.useState)(!1),[ek,ej]=(0,a.useState)({kind:"idle",url:""}),[eN,e$]=(0,a.useState)(null),[eS,eT]=(0,a.useState)(0),[eC,ez]=(0,a.useState)("this page"),eL=(0,a.useRef)(null),eO=(0,a.useRef)(0),eR=(0,a.useRef)(null),eA=(0,a.useMemo)(()=>z(e.src),[e.src]);(0,a.useEffect)(()=>{ez(window.location.origin);let e=(0,h.qA)(window.location.search,window.location.hash),r=(0,h.Yc)(e,b),s=r?null:(0,u.y5)(g);if(r||s?.found)try{let a=r?{...x(e.get("s")),...x(e.get("c"))}:s?.value??{};if(a&&"object"==typeof a){let e={...P,...a,sandboxTokens:Array.isArray(a.sandboxTokens)?a.sandboxTokens.filter(e=>y.has(e)):P.sandboxTokens,features:Array.isArray(a.features)?a.features.filter(e=>v.some(t=>t.v===e)):P.features,featureOrigins:a.featureOrigins&&"object"==typeof a.featureOrigins?a.featureOrigins:{}};r||(e.src=""),t(e),C(e.src)}}catch{}},[]),(0,i.Vd)(g,()=>JSON.stringify({...e,src:"",srcdoc:P.srcdoc}),[e],{debounceMs:400}),(0,a.useEffect)(()=>()=>{eR.current&&clearTimeout(eR.current)},[]);let eM=(0,a.useCallback)(e=>{t(t=>({...t,...e})),ef(null)},[]);function eF(e,t,r){e===eO.current&&(eR.current&&(clearTimeout(eR.current),eR.current=null),ej(e=>({kind:t,url:e.url,reason:r})))}let eW=(0,a.useMemo)(()=>q(e),[e]),eP=(0,a.useMemo)(()=>J(e),[e]),eU=(0,a.useMemo)(()=>Y(e),[e]),eH=(0,a.useMemo)(()=>_(e),[e]),eI=(0,a.useMemo)(()=>B(e),[e]),eG=(0,a.useMemo)(()=>X(e,eu),[e,eu]),eq=(0,a.useMemo)(()=>K(e,eA),[e,eA]),eE=0===e.title.trim().length,eJ=!e.useSrcdoc&&!eA.ok,eD=eE||eJ,eY=eD?"":"html"===ec?eP:"jsx"===ec?eU:"wordpress"===ec?eH:"mdx"===ec?eI:eG,e_=e.sandboxOn?e.sandboxTokens.filter(e=>!S.includes(e)):T,eB=e.sandboxOn?e.sandboxTokens.filter(e=>S.includes(e)):[],eX=e.sandboxOn?e.sandboxTokens.map(e=>y.get(e)).filter(e=>!!e?.risk):[],eV=e.sandboxOn?w.filter(t=>t.breaks&&!e.sandboxTokens.includes(t.v)):[],eZ=e.sandboxOn&&e.sandboxTokens.includes("allow-scripts")&&e.sandboxTokens.includes("allow-same-origin"),eQ=[];e.useSrcdoc&&e.srcdoc.length>600&&eQ.push(`Your inline HTML is ${e.srcdoc.length} characters and the share link carries at most 600, so it is left out of the link entirely. Everything else travels.`);let eK=e.perOrigin?Object.keys(e.featureOrigins).filter(t=>e.features.includes(t)).length:0;eK>12&&eQ.push(`The share link holds the first 12 per-feature origin lists. ${eK-12} more were not included in the link.`);let e0=(0,a.useCallback)(()=>{let{src:t,srcdoc:r,title:s,className:a,featureOrigins:i,...n}=e,o={src:t,srcdoc:r,title:s,className:a,featureOrigins:i};if(e.useSrcdoc&&r.length>600&&(o.srcdoc="",n.useSrcdoc=!1),e.perOrigin){let t={},r=0;for(let[s,a]of Object.entries(i))if(e.features.includes(s)){if(r>=12)break;t[s]=a,r++}o.featureOrigins=t}return(0,h.CZ)([{key:"s",value:JSON.stringify(n)},{key:"c",value:JSON.stringify(o),personal:"the URL or inline HTML you framed, its title, class name and per-feature origins"}])},[e]);async function e1(e,t){if(!e)return;let{ok:r,note:s}=await (0,p.copyText)(e);r&&(ef(t),setTimeout(()=>ef(e=>e===t?null:e),1600)),eb(s)}let e2=O(e.ratio),e3="fixed"===e.size?{width:e.width,height:e.height,border:0,maxWidth:"100%"}:"fullwidth"===e.size?{width:"100%",height:e.height,border:0}:"fill"===e.size?{width:"100%",height:320,border:0}:{width:"100%",aspectRatio:e2?`${e2.w} / ${e2.h}`:"16 / 9",border:0,display:"block"};return(0,s.jsxs)("div",{className:"space-y-5",children:[(0,s.jsxs)(ee,{title:"What are you embedding?",hint:"Paste the normal page URL. If it is one we know, the embed URL gets built for you.",children:[(0,s.jsxs)("div",{className:"flex flex-col gap-2 sm:flex-row",children:[(0,s.jsx)(o.p,{id:"iframe-src",value:r,onChange:t=>(function(t){C(t);let r=z(t);es(r.repaired??null);let s=r.ok?r.url:t.trim(),a=r.ok?F(s):null;a?(I(a.name),M(a.notes),V(!!a.noCookieCapable),eM({src:a.noCookieCapable?W(a.src,e.noCookie):a.src,title:e.title.trim()?e.title:a.title??"",ratio:a.ratio??e.ratio,size:a.size??e.size,height:a.height??e.height,features:a.allow?a.allow.filter(e=>v.some(t=>t.v===e)):e.features,useSrcdoc:!1})):(I(null),M([]),V(!1),eM({src:s,useSrcdoc:!1})),ej({kind:"idle",url:""})})(t.target.value),placeholder:"https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=1m30s","aria-label":"Page URL to embed",className:"font-mono text-sm"}),(0,s.jsx)(n.$,{type:"button",variant:"default",onClick:function(){if(!eA.ok||e.useSrcdoc)return;let t=eO.current+1;eO.current=t,eR.current&&clearTimeout(eR.current),ej({kind:"running",url:eA.url}),eT(t),e$(eA.url),eR.current=setTimeout(()=>{eF(t,"unknown",`The check gave up after ${f} without the frame finishing either way.`)},6e3)},disabled:!eA.ok||e.useSrcdoc||"running"===ek.kind,className:"shrink-0",children:"running"===ek.kind?"Checking...":"Will it frame?"})]}),eA.problem?(0,s.jsx)("p",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm",children:eA.problem}):null,er?(0,s.jsx)("p",{className:"text-xs text-muted-foreground",children:er}):null,eA.ok&&"http"===eA.scheme?(0,s.jsx)("p",{className:"rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm",children:"This is an http URL. Inside an https page the browser treats it as mixed content and blocks it, so you get an empty box no matter what else is set here."}):null,H?(0,s.jsxs)("div",{className:"rounded-md border border-input bg-muted/40 px-3 py-2 text-sm",children:[(0,s.jsxs)("span",{className:"font-medium",children:[H," detected."]}),(0,s.jsx)("ul",{className:"mt-1 list-disc space-y-1 pl-5 text-muted-foreground",children:L.map(e=>(0,s.jsx)("li",{children:e},e))}),D?(0,s.jsx)("div",{className:"mt-2",children:(0,s.jsx)(et,{checked:e.noCookie,onChange:function(t){eM({noCookie:t,src:W(e.src,t)}),r.trim()===e.src&&C(W(r.trim(),t))},label:"Use the youtube-nocookie.com host",hint:"YouTube holds off on its tracking cookies until somebody actually presses play."})}):null]}):null,(0,s.jsxs)("div",{role:"status","aria-live":"polite",children:["running"===ek.kind?(0,s.jsxs)("p",{className:"rounded-md border border-input bg-muted/40 px-3 py-2 text-sm",children:["Loading it in a real frame and watching what happens. Up to ",f,"."]}):null,"framed"===ek.kind?(0,s.jsxs)("div",{className:"rounded-md border border-emerald-600/40 bg-emerald-500/10 px-3 py-2 text-sm",children:[(0,s.jsxs)("p",{className:"font-medium",children:["It loaded in a frame served from ",eC,"."]}),(0,s.jsx)("p",{className:"mt-1 text-muted-foreground",children:'Nothing in the response stopped it. Since permission is decided per embedding origin, a site that allows us will normally allow your domain too, but the only conclusive test is the page you are actually building. Two things can still surprise you: a page that frames f
95ine and then renders its own "not available here" screen inside the frame, and an old script-based frame buster, which cannot run during this check because scripts are off for it.'})]}):null,"refused"===ek.kind?(0,s.jsxs)("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm",children:[(0,s.jsxs)("p",{className:"font-medium",children:["It refused to load in a frame served from ",eC,"."]}),(0,s.jsx)("p",{className:"mt-1 text-muted-foreground",children:"That is X-Frame-Options or a CSP frame-ancestors rule on their server, and no attribute you set here can override it. Both of those are decided per embedding origin, so this exact result can flip on your own domain: SAMEORIGIN always refuses us and always works on their own pages, and a frame-ancestors list that names your customer domain refuses us and works there. What usually gets you unstuck is their official embed URL, an oEmbed link, or a screenshot linking out to the page."})]}):null,"unknown"===ek.kind?(0,s.jsxs)("div",{className:"rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm",children:[(0,s.jsx)("p",{className:"font-medium",children:"Could not tell."}),(0,s.jsxs)("p",{className:"mt-1 text-muted-foreground",children:[ek.reason??"The load did not finish."," An ad blocker, tracking protection, a slow network or a site that wants a login all look the same from out here, so this is a real outcome rather than a fault."]})]}):null,"idle"!==ek.kind?(0,s.jsx)("p",{className:"mt-1 text-xs text-muted-foreground",children:"How this works: your browser attempts the same navigation the finished embed would, and the result is read from whether the frame ended up holding a real document. It is a heuristic, not a header read, because a page running in your browser cannot see the response headers of a cross-origin frame. Scripts are switched off for the check, which leaves the header decision untouched, since the browser makes that call before anything on the page runs."}):null]}),(0,s.jsx)(et,{checked:e.useSrcdoc,onChange:e=>eM({useSrcdoc:e}),label:"Use inline HTML instead of a URL (srcdoc)",hint:"Good for a small isolated widget. The inline document inherits the sandbox but not your origin, so it cannot read your page."}),e.useSrcdoc?(0,s.jsx)(d.T,{value:e.srcdoc,onChange:e=>eM({srcdoc:e.target.value}),"aria-label":"Inline HTML for srcdoc",className:"min-h-[110px] font-mono text-xs"}):null,(0,s.jsxs)("div",{children:[(0,s.jsx)(n.$,{type:"button",variant:"ghost",size:"sm",onClick:()=>ed(e=>!e),children:el?"Hide":"I already have an iframe, modernize it"}),el?(0,s.jsxs)("div",{className:"mt-2 space-y-2",children:[(0,s.jsx)(d.T,{value:ea,onChange:e=>ei(e.target.value),placeholder:'<iframe src="https://example.com" width="560" height="315" frameborder="0" scrolling="no"></iframe>',"aria-label":"Paste an existing iframe tag",className:"min-h-[90px] font-mono text-xs"}),(0,s.jsx)(n.$,{type:"button",variant:"outline",size:"sm",onClick:function(){let r=Z(ea);if(!r)return void eo(["No <iframe> tag found in what you pasted."]);let s=Q(e,r.attrs);t(s),C(s.src),eo(r.changes.length?r.changes:["Nothing needed changing. That snippet was already in decent shape."]),I(null),M([]),ej({kind:"idle",url:""})},disabled:!ea.trim(),children:"Read it and tell me what is wrong"}),en?(0,s.jsx)("ul",{className:"list-disc space-y-1 rounded-md border border-input bg-muted/40 px-3 py-2 pl-7 text-sm text-muted-foreground",children:en.map(e=>(0,s.jsx)("li",{children:e},e))}):null]}):null]})]}),(0,s.jsxs)("div",{className:"grid gap-4 lg:grid-cols-2",children:[(0,s.jsxs)(ee,{title:"Size and shape",hint:"This is the half that decides whether it fits on a phone.",children:[(0,s.jsx)("div",{className:"flex flex-wrap gap-1",role:"group","aria-label":"Sizing mode",children:$.map(t=>(0,s.jsx)(n.$,{type:"button",size:"sm",variant:e.size===t.v?"default":"outline","aria-pressed":e.size===t.v,onClick:()=>eM({size:t.v}),children:t.label},t.v))}),(0,s.jsx)("p",{className:"text-xs text-muted-foreground",children:$.find(t=>t.v===e.size)?.blurb}),G(e)?(0,s.jsxs)("div",{className:"space-y-2",children:[(0,s.jsx)(l.J,{htmlFor:"ratio-input",children:"Aspect ratio"}),(0,s.jsx)("div",{className:"flex flex-wrap gap-1",children:N.map(t=>(0,s.jsx)(n.$,{type:"button",size:"sm",variant:e.ratio===t?"secondary":"ghost",onClick:()=>eM({ratio:t}),children:t},t))}),(0,s.jsx)(o.p,{id:"ratio-input",value:e.ratio,onChange:e=>eM({ratio:e.target.value}),"aria-label":"Aspect ratio, width to height",className:"h-9 w-32 font-mono text-sm"}),e2?(0,s.jsx)("p",{className:"text-xs text-muted-foreground",children:"padding"===e.size?`Padding percentage worked out as ${e2.h} divided by ${e2.w}, which is ${R(e2.w,e2.h)}.`:`aspect-ratio: ${e2.w} / ${e2.h}. Switch to the padding fallback if you still support browsers from before 2021.`}):(0,s.jsx)("p",{className:"text-xs text-destructive",children:"That ratio is not readable. Write it as width:height, for example 16:9."})]}):null,"fixed"===e.size?(0,s.jsxs)("div",{className:"flex flex-wrap items-end gap-3",children:[(0,s.jsxs)("div",{children:[(0,s.jsx)(l.J,{htmlFor:"w-input",children:"Width"}),(0,s.jsx)(o.p,{id:"w-input",type:"number",min:1,max:4e3,value:e.width,onChange:e=>eM({width:A(Number(e.target.value),1,4e3)}),className:"h-9 w-28"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)(l.J,{htmlFor:"h-input",children:"Height"}),(0,s.jsx)(o.p,{id:"h-input",type:"number",min:1,max:4e3,value:e.height,onChange:e=>eM({height:A(Number(e.target.value),1,4e3)}),className:"h-9 w-28"})]})]}):null,"fullwidth"===e.size?(0,s.jsxs)("div",{children:[(0,s.jsx)(l.J,{htmlFor:"fh-input",children:"Height in pixels"}),(0,s.jsx)(o.p,{id:"fh-input",type:"number",min:1,max:4e3,value:e.height,onChange:e=>eM({height:A(Number(e.target.value),1,4e3)}),className:"h-9 w-28"})]}):null,"fill"===e.size?(0,s.jsx)("p",{className:"rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-xs",children:"A percentage height only resolves if the parent has a real height of its own. Drop this into a plain div and it collapses to nothing, which is the single most reported iframe bug."}):null,G(e)?(0,s.jsxs)("div",{children:[(0,s.jsx)(l.J,{htmlFor:"mw-input",children:"Maximum width in pixels (0 for none)"}),(0,s.jsx)(o.p,{id:"mw-input",type:"number",min:0,max:4e3,value:e.maxWidth,onChange:e=>eM({maxWidth:A(Number(e.target.value),0,4e3)}),className:"h-9 w-28"})]}):null]}),(0,s.jsxs)(ee,{title:"Name, loading and referrer",hint:"The three attributes an audit comes back asking for.",children:[(0,s.jsxs)("div",{children:[(0,s.jsxs)(l.J,{htmlFor:"title-input",children:["Title ",(0,s.jsx)("span",{className:"text-destructive",children:"(required)"})]}),(0,s.jsx)(o.p,{id:"title-input",value:e.title,onChange:e=>eM({title:e.target.value}),placeholder:"Office location on Google Maps",className:"mt-1"}),(0,s.jsx)("p",{className:"mt-1 text-xs text-muted-foreground",children:eE?'Nothing comes out until this is filled in. Without it a screen reader reads the frame as "iframe" and moves on.':`Announced as "${e.title.trim()}, frame". Describe the content, not the technology.`})]}),(0,s.jsx)(et,{checked:e.lazy,onChange:e=>eM({lazy:e}),label:'loading="lazy"',hint:"Holds the request until the frame is close to the viewport. No effect on a frame that is already visible when the page loads."}),(0,s.jsxs)("div",{children:[(0,s.jsx)(l.J,{htmlFor:"ref-select",children:"Referrer policy"}),(0,s.jsx)("select",{id:"ref-select",className:(0,m.cn)("h-9 w-full rounded-md border border-input bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring","mt-1"),value:e.referrer,onChange:e=>eM({referrer:e.target.value}),children:k.map(e=>(0,s.jsxs)("option",{value:e.v,children:[""===e.v?"(no attribute)":e.v,e.v===j?"  - browser default":""]},e.v))}),(0,s.jsx)("p",{className:"mt-1 text-xs text-muted-foreground",children:k.find(t=>t.v===e.referrer)?.note})]}),(0,s.jsx)(et,{checked:e.credentialless,onChange:e=>eM({credentialless:e}),label:"credentialless",hint:"Loads the frame with no cookies or storage of its own. Not in every browser yet, so treat it as an extra rather than something to depend on."})]})]}),(0,s.jsxs)(ee,{title:"Sandbox",hint:"An empty sandbox attribute is the maximum restriction. Every token below hands one capability back.",children:[(0,s.jsx)(et,{checked:e.sandboxOn,onChange:e=>eM({sandboxOn:e}),label:"Add a sandbox attribute",hint:"Off means the framed page runs with everything, the same as any normal page on your site."}),e.sandboxOn?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("div",{className:"grid gap-1.5 sm:grid-cols-2",children:w.map(t=>{let r=e.sandboxTokens.includes(t.v);return(0,s.jsxs)("label",{className:"flex cursor-pointer items-start gap-2 rounded border border-input p-2 text-xs",children:[(0,s.jsx)("input",{type:"checkbox",checked:r,onChange:r=>eM({sandboxTokens:r.target.checked?[...e.sandboxTokens,t.v]:e.sandboxTokens.filter(e=>e!==t.v)}),className:"mt-0.5 h-4 w-4 shrink-0 accent-primary"}),(0,s.jsxs)("span",{children:[(0,s.jsx)("span",{className:"font-mono font-medium",children:t.v}),(0,s.jsx)("span",{className:"block text-muted-foreground",children:t.what})]})]},t.v)})}),eZ?(0,s.jsxs)("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm",children:[(0,s.jsx)("p",{className:"font-medium",children:"allow-scripts and allow-same-origin are both on."}),(0,s.jsx)("p",{className:"mt-1 text-muted-foreground",children:"If the framed page comes from your own origin, that pair lets it reach its own frame element and remove the sandbox attribute, so the sandbox stops meaning anything. For genuinely third-party content it is the normal combination and it is fine, because the framed page has no route to your document."})]}):null,(0,s.jsxs)("div",{className:"grid gap-3 sm:grid-cols-2",children:[(0,s.jsxs)("div",{className:"rounded-md border border-input p-3",children:[(0,s.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:"What this set opens up"}),eX.length?(0,s.jsx)("ul",{className:"mt-2 space-y-1.5 text-xs",children:eX.map(e=>(0,s.jsxs)("li",{children:[(0,s.jsx)("span",{className:"font-mono font-medium",children:e.v}),(0,s.jsx)("span",{className:"block text-muted-foreground",children:e.risk})]},e.v))}):(0,s.jsx)("p",{className:"mt-2 text-xs text-muted-foreground",children:"Nothing here reaches back out at your page."})]}),(0,s.jsxs)("div",{className:"rounded-md border border-input p-3",children:[(0,s.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:"What will silently stop w
95orking"}),eV.length?(0,s.jsx)("ul",{className:"mt-2 space-y-1.5 text-xs",children:eV.map(e=>(0,s.jsxs)("li",{children:[(0,s.jsx)("span",{className:"font-mono font-medium",children:e.v}),(0,s.jsx)("span",{className:"block text-muted-foreground",children:e.breaks})]},e.v))}):(0,s.jsx)("p",{className:"mt-2 text-xs text-muted-foreground",children:"Every capability is granted, so nothing breaks."})]})]})]}):null]}),(0,s.jsxs)(ee,{title:"Permissions (the allow attribute)",hint:"Separate features with a semicolon. Origins inside one feature are separated by spaces, and 'src' means the frame own origin.",children:[(0,s.jsx)("div",{className:"grid gap-1.5 sm:grid-cols-2 lg:grid-cols-3",children:v.map(t=>{let r=e.features.includes(t.v);return(0,s.jsxs)("label",{className:"flex cursor-pointer items-start gap-2 rounded border border-input p-2 text-xs",children:[(0,s.jsx)("input",{type:"checkbox",checked:r,onChange:r=>eM({features:r.target.checked?[...e.features,t.v]:e.features.filter(e=>e!==t.v)}),className:"mt-0.5 h-4 w-4 shrink-0 accent-primary"}),(0,s.jsxs)("span",{children:[(0,s.jsx)("span",{className:"font-mono font-medium",children:t.v}),(0,s.jsx)("span",{className:"block text-muted-foreground",children:t.plain})]})]},t.v)})}),(0,s.jsx)(et,{checked:e.perOrigin,onChange:e=>eM({perOrigin:e}),label:"Name an allowed origin per feature",hint:'Instead of allow="camera", you get allow="camera \'src\' https://widget.example", which limits the grant to those origins.'}),e.perOrigin&&e.features.length?(0,s.jsx)("div",{className:"space-y-2",children:e.features.map(t=>(0,s.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,s.jsx)("span",{className:"w-40 shrink-0 font-mono text-xs",children:t}),(0,s.jsx)(o.p,{value:e.featureOrigins[t]??"'src'",onChange:r=>eM({featureOrigins:{...e.featureOrigins,[t]:r.target.value}}),"aria-label":`Allowed origins for ${t}`,className:"h-8 flex-1 font-mono text-xs"})]},t))}):null,(0,s.jsx)(et,{checked:e.legacyFullscreen,onChange:e=>eM({legacyFullscreen:e}),label:"Write fullscreen the old way, as allowfullscreen",hint:'allowfullscreen is the legacy spelling of allow="fullscreen". You get one or the other here, never both quietly emitted at once.'})]}),(0,s.jsxs)(ee,{title:"Preview",hint:"The collapse bugs only show up narrow, so start at 320.",children:[(0,s.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,s.jsx)(n.$,{type:"button",size:"sm",variant:ey?"secondary":"default",onClick:()=>ev(e=>!e),disabled:!eA.ok&&!e.useSrcdoc,children:ey?"Stop the preview":"Load the preview"}),(0,s.jsx)("div",{className:"flex flex-wrap gap-1",role:"group","aria-label":"Preview width",children:[320,768,0].map(e=>(0,s.jsx)(n.$,{type:"button",size:"sm",variant:ex===e?"default":"outline","aria-pressed":ex===e,onClick:()=>ew(e),children:0===e?"Full width":`${e}px`},e))})]}),ey&&(eA.ok||e.useSrcdoc)?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("div",{className:"overflow-x-auto rounded-md border border-input bg-muted/30 p-3",children:(0,s.jsx)("div",{style:{width:0===ex?"100%":ex,maxWidth:"100%"},children:(0,s.jsx)("iframe",{title:e.title.trim()||"Embed preview",src:e.useSrcdoc?void 0:eA.url,srcDoc:e.useSrcdoc?e.srcdoc:void 0,sandbox:e_.join(" "),referrerPolicy:e.referrer||void 0,allow:U(e)||void 0,style:e3},`${e.src}-${e.srcdoc}-${ex}-${e_.join(" ")}`)})}),(0,s.jsxs)("p",{className:"text-xs text-muted-foreground",children:['This preview is running with sandbox="',e_.join(" ")||"(empty, maximum restriction)",'".',eB.length?` It is held back from ${eB.join(", ")}, because those act on this page rather than the framed one, so your generated tag grants more than you are seeing here.`:e.sandboxOn?" That matches the tag below.":" Your generated tag has no sandbox at all, so the real thing runs with more freedom than this."]})]}):(0,s.jsx)("p",{className:"text-xs text-muted-foreground",children:"The preview loads the third-party page for real, so it is off until you ask for it."})]}),(0,s.jsx)(ee,{title:"Pre-flight check",hint:"The list to paste into the ticket when someone asks whether the embed is safe.",children:(0,s.jsx)("ul",{className:"space-y-2",children:eq.map(e=>(0,s.jsxs)("li",{className:"flex items-start gap-2 text-sm",children:[(0,s.jsx)("span",{"aria-hidden":"true",className:(0,m.cn)("mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-xs font-bold",e.ok?"bg-emerald-500/15 text-emerald-700 dark:text-emerald-400":"bg-amber-500/15 text-amber-700 dark:text-amber-400"),children:e.ok?"✓":"!"}),(0,s.jsxs)("span",{children:[(0,s.jsxs)("span",{className:"font-medium",children:[e.label," ",(0,s.jsx)("span",{className:"sr-only",children:e.ok?"passes":"needs attention"})]}),(0,s.jsx)("span",{className:"block text-xs text-muted-foreground",children:e.detail})]})]},e.label))})}),(0,s.jsxs)(ee,{title:"Your code",hint:"Copy the whole block. The CSS is part of the answer, not an optional extra.",children:[(0,s.jsx)("div",{className:"flex flex-wrap gap-1",role:"group","aria-label":"Output format",children:[{v:"html",label:"HTML"},{v:"jsx",label:"React / JSX"},{v:"wordpress",label:"WordPress"},{v:"mdx",label:"MDX"},{v:"facade",label:"Click to load"}].map(e=>(0,s.jsx)(n.$,{type:"button",size:"sm",variant:ec===e.v?"default":"outline","aria-pressed":ec===e.v,onClick:()=>eh(e.v),children:e.label},e.v))}),"facade"===ec?(0,s.jsxs)("div",{className:"space-y-2",children:[(0,s.jsx)("p",{className:"text-xs text-muted-foreground",children:"A poster image with a play button that swaps in the real iframe on click. The third-party request does not happen until somebody clicks, which is the point of it."}),(0,s.jsx)(o.p,{value:eu,onChange:e=>em(e.target.value),placeholder:"https://example.com/poster.jpg (optional)","aria-label":"Poster image URL for the click to load facade",className:"font-mono text-sm"})]}):null,eD?(0,s.jsxs)("div",{className:"rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm",children:[eE?(0,s.jsx)("p",{children:"Fill in the title first. An unnamed frame is an accessibility failure and it is not worth shipping."}):null,eJ?(0,s.jsx)("p",{children:"Add a URL to embed, or switch on inline HTML."}):null]}):(0,s.jsx)(d.T,{readOnly:!0,value:eY,"aria-label":"Generated embed code",onFocus:e=>e.currentTarget.select(),className:"min-h-[260px] font-mono text-xs"}),(0,s.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,s.jsx)(n.$,{type:"button",variant:"outline",size:"sm",onClick:()=>e1(eY,"all"),disabled:!eY,children:"all"===ep?"Copied!":"Copy everything"}),(0,s.jsx)(n.$,{type:"button",variant:"outline",size:"sm",onClick:()=>e1(E(e),"tag"),disabled:eD||"facade"===ec,children:"tag"===ep?"Copied!":"Copy the tag only"}),(0,s.jsx)(n.$,{type:"button",variant:"outline",size:"sm",onClick:()=>e1(eW,"css"),disabled:!eW,children:"css"===ep?"Copied!":"Copy the CSS only"}),(0,s.jsx)(n.$,{type:"button",variant:"ghost",size:"sm",onClick:function(){t({...P,sandboxTokens:[...P.sandboxTokens],features:[...P.features]}),C(""),ei(""),eo(null),I(null),M([]),es(null),ej({kind:"idle",url:""}),e$(null),ev(!1),ef(null)},children:"Reset"})]}),eQ.length?(0,s.jsx)("ul",{className:"list-disc space-y-1 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2 pl-7 text-xs",children:eQ.map(e=>(0,s.jsx)("li",{children:e},e))}):null]}),eg&&(0,s.jsx)("p",{role:"status","aria-live":"polite",className:"text-xs text-destructive",children:eg}),(0,s.jsx)(c.ToolActions,{share:e0,title:"HTML Iframe Generator",embedCarriesPersonal:!1}),eN?(0,s.jsx)("iframe",{ref:eL,src:eN,title:"Framability check","aria-hidden":"true",tabIndex:-1,sandbox:"allow-same-origin",referrerPolicy:"no-referrer",onLoad:()=>(function(e){let t=eL.current;if(t&&e===eO.current)try{let r=t.contentWindow?.location?.href;"string"!=typeof r||""===r||"about:blank"===r?eF(e,"refused"):eF(e,"framed")}catch{eF(e,"framed")}})(eS),style:{position:"absolute",width:1,height:1,opacity:0,pointerEvents:"none",border:0,left:-9999,top:0}},eS):null]})}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.