@storybook/addon-designs
Version:
Storybook addon for embedding your design preview in addon panel
30 lines (27 loc) • 3.86 kB
JavaScript
import {useState,useEffect,useMemo,Fragment}from'react';import {FigspecFileViewer,FigspecFrameViewer}from'@figspec/react';import {Placeholder}from'storybook/internal/components';import {css,jsx}from'storybook/theming';var v=({config:e,defer:t=false})=>{let[r,a]=useState(t?void 0:e.url),[s,o]=useState(false);return useEffect(()=>{if(!t)return;let n=requestAnimationFrame(()=>{a(e.url);});return ()=>cancelAnimationFrame(n)},[t,e.url]),useEffect(()=>{o(false);},[r]),jsx("div",{css:A},!s&&jsx(Placeholder,{css:N},"Loading..."),jsx("iframe",{css:O,src:r,allowFullScreen:e.allowFullscreen,onLoad:()=>o(true)}))};var A=css`
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
`,N=css`
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
`,O=css`
position: relative;
width: 100%;
height: 100%;
border: none;
z-index: 1;
`;var F=/https:\/\/[\w.-]+\.?figma.com\/([\w-]+)\/([0-9a-zA-Z]{22,128})(?:\/.*)?$/,V=e=>F.test(e),te=({config:e})=>{let t=useMemo(()=>V(e.url)?{url:M(e.url,e.embedHost||location.hostname),allowFullscreen:e.allowFullscreen}:(console.warn(`[storybook-addon-designs] The URL you specified is not valid Figma URL.
The addon fallbacks to normal iframe mode.For more detail, please check <https://www.figma.com/developers/embed>.`),e),[e.url,e.allowFullscreen,e.embedHost]);return jsx(v,{defer:true,config:t})};function M(e,t){let r=new URL(e);r.hostname=r.hostname.replace(/^www\./,"embed."),r.searchParams.delete("embed_origin"),r.searchParams.set("embed-host",t);for(let[a,s]of r.searchParams)r.searchParams.delete(a),r.searchParams.set(a.replace(/_/g,"-"),s);return r.href}var I=css`
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
`;function p(e){return e.status!==200?Promise.reject(e.statusText):e.json()}function q(e){if(e.accessToken)return e.accessToken;try{return process.env.STORYBOOK_FIGMA_ACCESS_TOKEN??null}catch{return null}}var z=({config:e})=>{let[t,r]=useState({state:"loading"}),a=async s=>{r({state:"loading"});try{let o=e.url.match(F);if(!o)throw new Error(e.url+" is not a valid Figma URL.");let[,,n]=o,u=new URL(e.url).searchParams.get("node-id"),P=q(e);if(!P)throw new Error("Personal Access Token is required.");let d={"X-FIGMA-TOKEN":P},f=new URL(`https://api.figma.com/v1/files/${n}`),c=new URL(`https://api.figma.com/v1/images/${n}`);if(c.searchParams.set("format","svg"),!u){let l=await fetch(f.href,{headers:d,signal:s}).then(m=>p(m)),E=T(l.document);c.searchParams.set("ids",E.map(m=>m.id).join(","));let L=await fetch(c.href,{headers:d,signal:s}).then(m=>p(m));r({state:"fetched",value:{type:"file",props:{documentNode:l,renderedImages:L.images,link:e.url}}});return}f.pathname+="/nodes",f.searchParams.set("ids",u),c.searchParams.set("ids",u);let[k,y]=await Promise.all([fetch(f.href,{headers:d,signal:s}).then(l=>p(l)),fetch(c.href,{headers:d,signal:s}).then(l=>p(l))]);r({state:"fetched",value:{type:"frame",props:{nodes:k,renderedImage:Object.values(y.images)[0],link:e.url}}});}catch(o){if(o instanceof DOMException&&o.code===DOMException.ABORT_ERR)return;console.error(o),r({state:"failed",error:o instanceof Error?o.message:String(o)});}};switch(useEffect(()=>{let s=false,o=()=>{s=true;},n=new AbortController;return a(n.signal).then(o,o),()=>{s||n.abort();}},[e.url]),t.state){case "loading":return jsx(Placeholder,null,jsx(Fragment,null,"Loading Figma file..."));case "failed":return jsx(Placeholder,null,jsx(Fragment,null,"Failed to load Figma file"),jsx(Fragment,null,t.error));case "fetched":return t.value.type==="file"?jsx(FigspecFileViewer,{css:I,...t.value.props}):jsx(FigspecFrameViewer,{css:I,...t.value.props})}},pe=z;function T(e){return "absoluteBoundingBox"in e?[e]:!e.children||e.children.length===0?[]:e.children.map(T).reduce((t,r)=>t.concat(r),[])}
export{v as a,te as b,z as c,pe as d};