sanity-plugin-iframe-pane 2.2.0 → 2.3.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Display any URL in a View Pane, along with helpful buttons to Copy the URL or op
7
7
 
8
8
  Accepts either a string or an async function to resolve a URL based on the current document.
9
9
 
10
- ![Iframe View Pane](https://user-images.githubusercontent.com/9684022/144389599-496e1e50-62a7-4d5c-903a-889885eb8aab.png)
10
+ ![Iframe View Pane](https://user-images.githubusercontent.com/9684022/226924036-ef9122e6-e498-42aa-ad01-8c4acdc9e65e.png)
11
11
 
12
12
  ## Installation
13
13
 
@@ -23,7 +23,7 @@ yarn add sanity-plugin-iframe-pane
23
23
 
24
24
  ## Usage
25
25
 
26
- This is designed to be used as a [Component inside of a View](https://www.sanity.io/docs/structure-builder-reference#c0c8284844b7).
26
+ This is designed to be used as a [Component inside of a View](https://www.sanity.io/docs/structure-builder-reference#c0c8284844b7).
27
27
 
28
28
  The simplest way to configure views is by customizing the `defaultDocumentNode` setting in the `deskTool()` plugin.
29
29
 
@@ -45,7 +45,6 @@ export default defineConfig({
45
45
  A basic example of a custom `defaultDocumentNode` function, to only show the Iframe Pane on `movie` type documents.
46
46
 
47
47
  ```ts
48
-
49
48
  // ./src/defaultDocumentNode.ts
50
49
 
51
50
  import {DefaultDocumentNodeResolver} from 'sanity/desk'
@@ -88,6 +87,9 @@ url: (doc) => resolveProductionUrl(doc),
88
87
  // OR a string
89
88
  url: `https://sanity.io`,
90
89
 
90
+ // Optional: Display the Url in the pane
91
+ showDisplayUrl: true // boolean. default `true`.
92
+
91
93
  // Optional: Set the default size
92
94
  defaultSize: `mobile`, // default `desktop`
93
95
 
@@ -124,6 +126,6 @@ on how to run this plugin with hotreload in the studio.
124
126
  ### Release new version
125
127
 
126
128
  Run ["CI & Release" workflow](https://github.com/sanity-io/sanity-plugin-iframe-pane/actions/workflows/main.yml).
127
- Make sure to select the studio-v3 branch and check "Release new version".
129
+ Make sure to select the `main` branch and check "Release new version".
128
130
 
129
131
  Semantic release will only release on configured branches, so it is safe to run release on any branch.
package/lib/index.esm.js CHANGED
@@ -1,2 +1,214 @@
1
- function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function t(t){for(var i=1;i<arguments.length;i++){var r=null!=arguments[i]?arguments[i]:{};i%2?e(Object(r),!0).forEach((function(e){n(t,e,r[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):e(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}import{jsx as i,jsxs as r}from"react/jsx-runtime";import{useState as o,useRef as l,useEffect as c}from"react";import{ThemeProvider as a,Flex as d,Spinner as s,Card as u,Button as p,Box as f,Text as g}from"@sanity/ui";import{MobileDeviceIcon as y,UndoIcon as h,CopyIcon as b,LeaveIcon as m}from"@sanity/icons";import{useCopyToClipboard as v}from"usehooks-ts";const O={desktop:{width:"100%",height:"100%",maxHeight:"100%"},mobile:{width:414,height:"100%",maxHeight:736}},j="desktop";function w(e){const{document:n,options:w}=e,{url:k,defaultSize:x=j,reload:P,loader:z,attributes:C={}}=w,[S,D]=o(k&&"string"==typeof k?k:""),[L,E]=o((null==O?void 0:O[x])?x:j),[B,H]=o(!1),R=l(null),_=l(null),{displayed:I}=n,[,N]=v();function T(){(null==_?void 0:_.current)&&(_.current.src=_.current.src,H(!0))}return c((()=>{((null==P?void 0:P.revision)||0==(null==P?void 0:P.revision))&&setTimeout((()=>{T()}),Number(null==P?void 0:P.revision))}),[I._rev,null==P?void 0:P.revision]),c((()=>{"function"==typeof k&&(async()=>{H(!0);const e="function"==typeof k?await k(I):"";e!==S&&e&&"string"==typeof e&&D(e)})()}),[I._rev]),S&&"string"==typeof S?r(a,{children:[i("textarea",{style:{position:"absolute",pointerEvents:"none",opacity:0},ref:R,value:S,readOnly:!0,tabIndex:-1}),r(d,{direction:"column",style:{height:"100%"},children:[i(u,{padding:2,borderBottom:!0,children:r(d,{align:"center",gap:2,children:[i(d,{align:"center",gap:1,children:i(p,{fontSize:[1],padding:2,tone:"primary",mode:"mobile"===L?"default":"ghost",icon:y,onClick:()=>E("mobile"===L?"desktop":"mobile")})}),i(f,{flex:1,children:i(g,{size:0,textOverflow:"ellipsis",children:S})}),r(d,{align:"center",gap:1,children:[(null==P?void 0:P.button)?i(p,{fontSize:[1],padding:2,icon:h,title:"Reload","aria-label":"Reload",onClick:()=>T()}):null,i(p,{fontSize:[1],icon:b,padding:[2],title:"Copy","aria-label":"Copy",onClick:()=>{var e;(null==(e=null==R?void 0:R.current)?void 0:e.value)&&N(R.current.value)}}),i(p,{fontSize:[1],icon:m,padding:[2],text:"Open",tone:"primary",onClick:()=>window.open(S)})]})]})}),i(u,{tone:"transparent",padding:"mobile"===L?2:0,style:{height:"100%"},children:r(d,{align:"center",justify:"center",style:{height:"100%",position:"relative"},children:[z&&B&&i(d,{justify:"center",align:"center",style:{inset:"0",position:"absolute"},children:i(d,{style:t(t({},O[L]),{},{backgroundColor:"rgba(0,0,0,0.2)"}),justify:"center",align:"center",children:i(u,{padding:4,radius:2,shadow:1,children:r(d,{align:"center",direction:"column",gap:3,height:"fill",justify:"center",children:[i(s,{}),z&&"string"==typeof z&&i(g,{size:1,children:z})]})})})}),i("iframe",t(t({ref:_,title:"preview",style:O[L],frameBorder:"0",src:S},C),{},{onLoad:function(){H(!1),C.onLoad&&"function"==typeof C.onLoad&&C.onLoad()}}))]})})]})]}):i(a,{children:i(d,{padding:5,align:"center",justify:"center",children:i(s,{})})})}export{w as default};
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useState, useRef, useEffect } from 'react';
3
+ import { ThemeProvider, Flex, Spinner, Card, Button, Box, Text } from '@sanity/ui';
4
+ import { MobileDeviceIcon, UndoIcon, CopyIcon, LeaveIcon } from '@sanity/icons';
5
+ import { useCopyToClipboard } from 'usehooks-ts';
6
+ const sizes = {
7
+ desktop: {
8
+ width: "100%",
9
+ height: "100%",
10
+ maxHeight: "100%"
11
+ },
12
+ mobile: {
13
+ width: 414,
14
+ height: "100%",
15
+ maxHeight: 736
16
+ }
17
+ };
18
+ const DEFAULT_SIZE = "desktop";
19
+ function Iframe(props) {
20
+ const {
21
+ document: sanityDocument,
22
+ options
23
+ } = props;
24
+ const {
25
+ url,
26
+ defaultSize = DEFAULT_SIZE,
27
+ reload,
28
+ loader,
29
+ attributes = {},
30
+ showDisplayUrl = true
31
+ } = options;
32
+ const [displayUrl, setDisplayUrl] = useState(url && typeof url === "string" ? url : "");
33
+ const [iframeSize, setIframeSize] = useState((sizes == null ? void 0 : sizes[defaultSize]) ? defaultSize : DEFAULT_SIZE);
34
+ const [loading, setLoading] = useState(false);
35
+ const input = useRef(null);
36
+ const iframe = useRef(null);
37
+ const {
38
+ displayed
39
+ } = sanityDocument;
40
+ const [, copy] = useCopyToClipboard();
41
+ function handleCopy() {
42
+ var _a;
43
+ if (!((_a = input == null ? void 0 : input.current) == null ? void 0 : _a.value)) return;
44
+ copy(input.current.value);
45
+ }
46
+ function handleReload() {
47
+ if (!(iframe == null ? void 0 : iframe.current)) {
48
+ return;
49
+ }
50
+ iframe.current.src = iframe.current.src;
51
+ setLoading(true);
52
+ }
53
+ function handleIframeLoad() {
54
+ setLoading(false);
55
+ if (attributes.onLoad && typeof attributes.onLoad === "function") {
56
+ attributes.onLoad();
57
+ }
58
+ }
59
+ useEffect(() => {
60
+ if ((reload == null ? void 0 : reload.revision) || (reload == null ? void 0 : reload.revision) == 0) {
61
+ setTimeout(() => {
62
+ handleReload();
63
+ }, Number(reload == null ? void 0 : reload.revision));
64
+ }
65
+ }, [displayed._rev, reload == null ? void 0 : reload.revision]);
66
+ useEffect(() => {
67
+ const getUrl = async () => {
68
+ setLoading(true);
69
+ const resolveUrl = typeof url === "function" ? await url(displayed) : "";
70
+ if (resolveUrl !== displayUrl && resolveUrl && typeof resolveUrl === "string") {
71
+ setDisplayUrl(resolveUrl);
72
+ }
73
+ };
74
+ if (typeof url === "function") {
75
+ getUrl();
76
+ }
77
+ }, [displayed._rev]);
78
+ if (!displayUrl || typeof displayUrl !== "string") {
79
+ return /* @__PURE__ */jsx(ThemeProvider, {
80
+ children: /* @__PURE__ */jsx(Flex, {
81
+ padding: 5,
82
+ align: "center",
83
+ justify: "center",
84
+ children: /* @__PURE__ */jsx(Spinner, {})
85
+ })
86
+ });
87
+ }
88
+ return /* @__PURE__ */jsxs(ThemeProvider, {
89
+ children: [/* @__PURE__ */jsx("textarea", {
90
+ style: {
91
+ position: "absolute",
92
+ pointerEvents: "none",
93
+ opacity: 0
94
+ },
95
+ ref: input,
96
+ value: displayUrl,
97
+ readOnly: true,
98
+ tabIndex: -1
99
+ }), /* @__PURE__ */jsxs(Flex, {
100
+ direction: "column",
101
+ style: {
102
+ height: "100%"
103
+ },
104
+ children: [/* @__PURE__ */jsx(Card, {
105
+ padding: 2,
106
+ borderBottom: true,
107
+ children: /* @__PURE__ */jsxs(Flex, {
108
+ align: "center",
109
+ gap: 2,
110
+ children: [/* @__PURE__ */jsx(Flex, {
111
+ align: "center",
112
+ gap: 1,
113
+ children: /* @__PURE__ */jsx(Button, {
114
+ fontSize: [1],
115
+ padding: 2,
116
+ tone: "primary",
117
+ mode: iframeSize === "mobile" ? "default" : "ghost",
118
+ icon: MobileDeviceIcon,
119
+ onClick: () => setIframeSize(iframeSize === "mobile" ? "desktop" : "mobile")
120
+ })
121
+ }), /* @__PURE__ */jsx(Box, {
122
+ flex: 1,
123
+ children: showDisplayUrl && /* @__PURE__ */jsx(Text, {
124
+ size: 0,
125
+ textOverflow: "ellipsis",
126
+ children: displayUrl
127
+ })
128
+ }), /* @__PURE__ */jsxs(Flex, {
129
+ align: "center",
130
+ gap: 1,
131
+ children: [(reload == null ? void 0 : reload.button) ? /* @__PURE__ */jsx(Button, {
132
+ fontSize: [1],
133
+ padding: 2,
134
+ icon: UndoIcon,
135
+ title: "Reload",
136
+ "aria-label": "Reload",
137
+ onClick: () => handleReload()
138
+ }) : null, /* @__PURE__ */jsx(Button, {
139
+ fontSize: [1],
140
+ icon: CopyIcon,
141
+ padding: [2],
142
+ title: "Copy",
143
+ "aria-label": "Copy",
144
+ onClick: () => handleCopy()
145
+ }), /* @__PURE__ */jsx(Button, {
146
+ fontSize: [1],
147
+ icon: LeaveIcon,
148
+ padding: [2],
149
+ text: "Open",
150
+ tone: "primary",
151
+ onClick: () => window.open(displayUrl)
152
+ })]
153
+ })]
154
+ })
155
+ }), /* @__PURE__ */jsx(Card, {
156
+ tone: "transparent",
157
+ padding: iframeSize === "mobile" ? 2 : 0,
158
+ style: {
159
+ height: "100%"
160
+ },
161
+ children: /* @__PURE__ */jsxs(Flex, {
162
+ align: "center",
163
+ justify: "center",
164
+ style: {
165
+ height: "100%",
166
+ position: "relative"
167
+ },
168
+ children: [loader && loading && /* @__PURE__ */jsx(Flex, {
169
+ justify: "center",
170
+ align: "center",
171
+ style: {
172
+ inset: "0",
173
+ position: "absolute"
174
+ },
175
+ children: /* @__PURE__ */jsx(Flex, {
176
+ style: {
177
+ ...sizes[iframeSize],
178
+ backgroundColor: "rgba(0,0,0,0.2)"
179
+ },
180
+ justify: "center",
181
+ align: "center",
182
+ children: /* @__PURE__ */jsx(Card, {
183
+ padding: 4,
184
+ radius: 2,
185
+ shadow: 1,
186
+ children: /* @__PURE__ */jsxs(Flex, {
187
+ align: "center",
188
+ direction: "column",
189
+ gap: 3,
190
+ height: "fill",
191
+ justify: "center",
192
+ children: [/* @__PURE__ */jsx(Spinner, {}), loader && typeof loader === "string" && /* @__PURE__ */jsx(Text, {
193
+ size: 1,
194
+ children: loader
195
+ })]
196
+ })
197
+ })
198
+ })
199
+ }), /* @__PURE__ */jsx("iframe", {
200
+ ref: iframe,
201
+ title: "preview",
202
+ style: sizes[iframeSize],
203
+ frameBorder: "0",
204
+ src: displayUrl,
205
+ ...attributes,
206
+ onLoad: handleIframeLoad
207
+ })]
208
+ })
209
+ })]
210
+ })]
211
+ });
212
+ }
213
+ export { Iframe as default };
2
214
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/Iframe.tsx"],"sourcesContent":["/* eslint-disable react/jsx-no-bind */\nimport React, {useEffect, useState, useRef} from 'react'\nimport {SanityDocumentLike} from 'sanity'\nimport {Box, Flex, Text, Button, ThemeProvider, Card, Spinner} from '@sanity/ui'\nimport {UndoIcon, CopyIcon, LeaveIcon, MobileDeviceIcon} from '@sanity/icons'\nimport {HTMLAttributeReferrerPolicy} from 'react'\n\nimport {useCopyToClipboard} from 'usehooks-ts'\n\ntype Size = 'desktop' | 'mobile'\n\ntype SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n maxHeight: string | number\n }\n}\n\nconst sizes: SizeProps = {\n desktop: {\n width: `100%`,\n height: `100%`,\n maxHeight: `100%`,\n },\n mobile: {\n width: 414,\n height: `100%`,\n maxHeight: 736,\n },\n}\n\nexport type IframeOptions = {\n url: string | ((document: SanityDocumentLike) => unknown)\n defaultSize?: 'desktop' | 'mobile'\n loader?: boolean | string\n reload: {\n revision: boolean | number\n button: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nexport type IframeProps = {\n document: {\n displayed: SanityDocumentLike\n }\n options: IframeOptions\n}\n\nconst DEFAULT_SIZE = `desktop`\n\nfunction Iframe(props: IframeProps) {\n const {document: sanityDocument, options} = props\n const {url, defaultSize = DEFAULT_SIZE, reload, loader, attributes = {}} = options\n const [displayUrl, setDisplayUrl] = useState(url && typeof url === 'string' ? url : ``)\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n const [loading, setLoading] = useState(false)\n const input = useRef<HTMLTextAreaElement>(null)\n const iframe = useRef<HTMLIFrameElement>(null)\n const {displayed} = sanityDocument\n const [, copy] = useCopyToClipboard()\n\n function handleCopy() {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n }\n\n function handleReload() {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issuies\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setLoading(true)\n }\n\n function handleIframeLoad() {\n setLoading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n // Reload on new revisions\n useEffect(() => {\n if (reload?.revision || reload?.revision == 0) {\n setTimeout(() => {\n handleReload()\n }, Number(reload?.revision))\n }\n }, [displayed._rev, reload?.revision])\n\n // Set initial URL and refresh on new revisions\n useEffect(() => {\n const getUrl = async () => {\n setLoading(true)\n const resolveUrl = typeof url === 'function' ? await url(displayed) : ``\n\n // Only update state if URL has changed\n if (resolveUrl !== displayUrl && resolveUrl && typeof resolveUrl === 'string') {\n setDisplayUrl(resolveUrl)\n }\n }\n\n if (typeof url === 'function') {\n getUrl()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [displayed._rev])\n\n if (!displayUrl || typeof displayUrl !== 'string') {\n return (\n <ThemeProvider>\n <Flex padding={5} align=\"center\" justify=\"center\">\n <Spinner />\n </Flex>\n </ThemeProvider>\n )\n }\n\n return (\n <ThemeProvider>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={displayUrl}\n readOnly\n tabIndex={-1}\n />\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Button\n fontSize={[1]}\n padding={2}\n tone=\"primary\"\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Flex>\n <Box flex={1}>\n <Text size={0} textOverflow=\"ellipsis\">\n {displayUrl}\n </Text>\n </Box>\n <Flex align=\"center\" gap={1}>\n {reload?.button ? (\n <Button\n fontSize={[1]}\n padding={2}\n icon={UndoIcon}\n title=\"Reload\"\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n ) : null}\n <Button\n fontSize={[1]}\n icon={CopyIcon}\n padding={[2]}\n title=\"Copy\"\n aria-label=\"Copy\"\n onClick={() => handleCopy()}\n />\n <Button\n fontSize={[1]}\n icon={LeaveIcon}\n padding={[2]}\n text=\"Open\"\n tone=\"primary\"\n onClick={() => window.open(displayUrl)}\n />\n </Flex>\n </Flex>\n </Card>\n <Card tone=\"transparent\" padding={iframeSize === 'mobile' ? 2 : 0} style={{height: `100%`}}>\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n {loader && loading && (\n <Flex justify=\"center\" align=\"center\" style={{inset: `0`, position: `absolute`}}>\n <Flex\n style={{...sizes[iframeSize], backgroundColor: `rgba(0,0,0,0.2)`}}\n justify=\"center\"\n align=\"center\"\n >\n <Card padding={4} radius={2} shadow={1}>\n <Flex align=\"center\" direction=\"column\" gap={3} height=\"fill\" justify=\"center\">\n <Spinner />\n {loader && typeof loader === 'string' && <Text size={1}>{loader}</Text>}\n </Flex>\n </Card>\n </Flex>\n </Flex>\n )}\n <iframe\n ref={iframe}\n title=\"preview\"\n style={sizes[iframeSize]}\n frameBorder=\"0\"\n src={displayUrl}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n </Flex>\n </Card>\n </Flex>\n </ThemeProvider>\n )\n}\n\nexport default Iframe\n"],"names":["sizes","desktop","width","height","maxHeight","mobile","DEFAULT_SIZE","Iframe","props","document","sanityDocument","options","url","defaultSize","reload","loader","attributes","displayUrl","setDisplayUrl","useState","iframeSize","setIframeSize","loading","setLoading","input","useRef","iframe","displayed","copy","useCopyToClipboard","handleReload","current","src","useEffect","revision","setTimeout","Number","_rev","async","resolveUrl","getUrl","jsxs","ThemeProvider","children","jsx","style","position","pointerEvents","opacity","ref","value","readOnly","tabIndex","Flex","direction","Card","padding","borderBottom","align","gap","Button","fontSize","tone","mode","icon","MobileDeviceIcon","onClick","Box","flex","Text","size","textOverflow","button","UndoIcon","title","CopyIcon","_a","LeaveIcon","text","window","open","justify","inset","backgroundColor","radius","shadow","Spinner","_objectSpread","frameBorder","onLoad"],"mappings":"6hCAoBA,MAAMA,EAAmB,CACvBC,QAAS,CACPC,MAAO,OACPC,OAAQ,OACRC,UAAW,QAEbC,OAAQ,CACNH,MAAO,IACPC,OAAQ,OACRC,UAAW,MA2BTE,EAAe,UAErB,SAASC,EAAOC,GACd,MAAOC,SAAUC,EAAgBC,QAAAA,GAAWH,GACtCI,IAACA,cAAKC,EAAcP,EAAAQ,OAAcA,SAAQC,EAAQC,WAAAA,EAAa,IAAML,GACpEM,EAAYC,GAAiBC,EAASP,GAAsB,iBAARA,EAAmBA,OACvEQ,EAAYC,GAAiBF,GAAiB,MAARnB,OAAQ,EAAAA,EAAAa,IAAeA,EAAcP,IAC3EgB,EAASC,GAAcJ,GAAS,GACjCK,EAAQC,EAA4B,MACpCC,EAASD,EAA0B,OACnCE,UAACA,GAAajB,GACXkB,CAAAA,GAAQC,IAQjB,SAASC,WACFJ,WAAQK,WAMNL,EAAAK,QAAQC,IAAMN,EAAOK,QAAQC,IAEpCT,GAAW,GACb,CAqCA,OA1BAU,GAAU,OACI,MAARnB,OAAQ,EAAAA,EAAAoB,WAAgC,IAAZ,MAARpB,OAAQ,EAAAA,EAAAoB,YAC9BC,YAAW,KACIL,GAAA,GACZM,OAAe,MAARtB,OAAQ,EAAAA,EAAAoB,UACpB,GACC,CAACP,EAAUU,KAAM,MAAAvB,OAAA,EAAAA,EAAQoB,WAG5BD,GAAU,KAWW,mBAARrB,GAVI0B,WACbf,GAAW,GACX,MAAMgB,EAA4B,mBAAR3B,QAA2BA,EAAIe,GAAa,GAGlEY,IAAetB,GAAcsB,GAAoC,iBAAfA,GACpDrB,EAAcqB,EAChB,EAIOC,EACT,GAEC,CAACb,EAAUU,OAETpB,GAAoC,iBAAfA,EAWvBwB,EAAAC,EAAA,CACCC,SAAA,CAACC,EAAA,WAAA,CACCC,MAAO,CAACC,oBAAsBC,cAAe,OAAQC,QAAS,GAC9DC,IAAKzB,EACL0B,MAAOjC,EACPkC,UAAQ,EACRC,UAAU,IAEXX,EAAAY,EAAA,CAAKC,UAAU,SAAST,MAAO,CAAC1C,OAAA,QAC/BwC,SAAA,CAACC,EAAAW,EAAA,CAAKC,QAAS,EAAGC,cAAY,EAC5Bd,SAACF,EAAAY,EAAA,CAAKK,MAAM,SAASC,IAAK,EACxBhB,SAAA,CAACC,EAAAS,EAAA,CAAKK,MAAM,SAASC,IAAK,EACxBhB,SAACC,EAAAgB,EAAA,CACCC,SAAU,CAAC,GACXL,QAAS,EACTM,KAAK,UACLC,KAAqB,WAAf3C,EAA0B,UAAY,QAC5C4C,KAAMC,EACNC,QAAS,IAAM7C,EAA6B,WAAfD,EAA0B,UAAY,cAGtEwB,EAAAuB,EAAA,CAAIC,KAAM,EACTzB,SAACC,EAAAyB,EAAA,CAAKC,KAAM,EAAGC,aAAa,WACzB5B,SAAA1B,MAGJwB,EAAAY,EAAA,CAAKK,MAAM,SAASC,IAAK,EACvBhB,SAAA,EAAA,MAAA7B,OAAA,EAAAA,EAAQ0D,QACN5B,EAAAgB,EAAA,CACCC,SAAU,CAAC,GACXL,QAAS,EACTQ,KAAMS,EACNC,MAAM,SACN,aAAW,SACXR,QAAS,IAAMpC,MAEf,KACHc,EAAAgB,EAAA,CACCC,SAAU,CAAC,GACXG,KAAMW,EACNnB,QAAS,CAAC,GACVkB,MAAM,OACN,aAAW,OACXR,QAAS,KA3GvB,IArEFU,GAsES,OAAAA,EAAO,MAAApD,OAAA,EAAAA,EAAAO,cAAS,EAAA6C,EAAA1B,QAEhBtB,EAAAJ,EAAMO,QAAQmB,MAwGmB,IAE3BN,EAAAgB,EAAA,CACCC,SAAU,CAAC,GACXG,KAAMa,EACNrB,QAAS,CAAC,GACVsB,KAAK,OACLhB,KAAK,UACLI,QAAS,IAAMa,OAAOC,KAAK/D,aAKlC2B,EAAAW,EAAA,CAAKO,KAAK,cAAcN,QAAwB,WAAfpC,EAA0B,EAAI,EAAGyB,MAAO,CAAC1C,OAAA,QACzEwC,SAACF,EAAAY,EAAA,CAAKK,MAAM,SAASuB,QAAQ,SAASpC,MAAO,CAAC1C,OAAQ,OAAQ2C,qBAC3DH,SAAA,CAAA5B,GAAUO,GACRsB,EAAAS,EAAA,CAAK4B,QAAQ,SAASvB,MAAM,SAASb,MAAO,CAACqC,MAAO,IAAKpC,qBACxDH,SAACC,EAAAS,EAAA,CACCR,MAAW7C,EAAAA,EAAAA,CAAAA,EAAAA,EAAMoB,IAAA,CAAA,EAAA,CAAa+D,oCAC9BF,QAAQ,SACRvB,MAAM,SAENf,SAACC,EAAAW,EAAA,CAAKC,QAAS,EAAG4B,OAAQ,EAAGC,OAAQ,EACnC1C,SAACF,EAAAY,EAAA,CAAKK,MAAM,SAASJ,UAAU,SAASK,IAAK,EAAGxD,OAAO,OAAO8E,QAAQ,SACpEtC,SAAA,CAAAC,EAAC0C,EAAQ,IACRvE,GAA4B,iBAAXA,GAAwB6B,EAAAyB,EAAA,CAAKC,KAAM,EAAI3B,SAAA5B,aAMlE6B,EAAA,SAAA2C,EAAAA,EAAA,CACCtC,IAAKvB,EACLgD,MAAM,UACN7B,MAAO7C,EAAMoB,GACboE,YAAY,IACZxD,IAAKf,GACDD,GAAA,CAAA,EAAA,CACJyE,OA/HZ,WACElE,GAAW,GAEPP,EAAWyE,QAAuC,mBAAtBzE,EAAWyE,QACzCzE,EAAWyE,QAEf,gBA+BK7C,EAAAF,EAAA,CACCC,SAACC,EAAAS,EAAA,CAAKG,QAAS,EAAGE,MAAM,SAASuB,QAAQ,SACvCtC,WAAC2C,EAAQ,OA+FnB"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/Iframe.tsx"],"sourcesContent":["/* eslint-disable react/jsx-no-bind */\nimport React, {useEffect, useState, useRef} from 'react'\nimport {SanityDocumentLike} from 'sanity'\nimport {Box, Flex, Text, Button, ThemeProvider, Card, Spinner} from '@sanity/ui'\nimport {UndoIcon, CopyIcon, LeaveIcon, MobileDeviceIcon} from '@sanity/icons'\nimport {HTMLAttributeReferrerPolicy} from 'react'\n\nimport {useCopyToClipboard} from 'usehooks-ts'\n\ntype Size = 'desktop' | 'mobile'\n\ntype SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n maxHeight: string | number\n }\n}\n\nconst sizes: SizeProps = {\n desktop: {\n width: `100%`,\n height: `100%`,\n maxHeight: `100%`,\n },\n mobile: {\n width: 414,\n height: `100%`,\n maxHeight: 736,\n },\n}\n\nexport type IframeOptions = {\n url: string | ((document: SanityDocumentLike) => unknown)\n defaultSize?: 'desktop' | 'mobile'\n loader?: boolean | string\n showDisplayUrl?: boolean\n reload: {\n revision: boolean | number\n button: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nexport type IframeProps = {\n document: {\n displayed: SanityDocumentLike\n }\n options: IframeOptions\n}\n\nconst DEFAULT_SIZE = `desktop`\n\nfunction Iframe(props: IframeProps) {\n const {document: sanityDocument, options} = props\n const {\n url,\n defaultSize = DEFAULT_SIZE,\n reload,\n loader,\n attributes = {},\n showDisplayUrl = true,\n } = options\n const [displayUrl, setDisplayUrl] = useState(url && typeof url === 'string' ? url : ``)\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n const [loading, setLoading] = useState(false)\n const input = useRef<HTMLTextAreaElement>(null)\n const iframe = useRef<HTMLIFrameElement>(null)\n const {displayed} = sanityDocument\n const [, copy] = useCopyToClipboard()\n\n function handleCopy() {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n }\n\n function handleReload() {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issuies\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setLoading(true)\n }\n\n function handleIframeLoad() {\n setLoading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n // Reload on new revisions\n useEffect(() => {\n if (reload?.revision || reload?.revision == 0) {\n setTimeout(() => {\n handleReload()\n }, Number(reload?.revision))\n }\n }, [displayed._rev, reload?.revision])\n\n // Set initial URL and refresh on new revisions\n useEffect(() => {\n const getUrl = async () => {\n setLoading(true)\n const resolveUrl = typeof url === 'function' ? await url(displayed) : ``\n\n // Only update state if URL has changed\n if (resolveUrl !== displayUrl && resolveUrl && typeof resolveUrl === 'string') {\n setDisplayUrl(resolveUrl)\n }\n }\n\n if (typeof url === 'function') {\n getUrl()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [displayed._rev])\n\n if (!displayUrl || typeof displayUrl !== 'string') {\n return (\n <ThemeProvider>\n <Flex padding={5} align=\"center\" justify=\"center\">\n <Spinner />\n </Flex>\n </ThemeProvider>\n )\n }\n\n return (\n <ThemeProvider>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={displayUrl}\n readOnly\n tabIndex={-1}\n />\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Button\n fontSize={[1]}\n padding={2}\n tone=\"primary\"\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Flex>\n <Box flex={1}>\n {showDisplayUrl && (\n <Text size={0} textOverflow=\"ellipsis\">\n {displayUrl}\n </Text>\n )}\n </Box>\n <Flex align=\"center\" gap={1}>\n {reload?.button ? (\n <Button\n fontSize={[1]}\n padding={2}\n icon={UndoIcon}\n title=\"Reload\"\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n ) : null}\n <Button\n fontSize={[1]}\n icon={CopyIcon}\n padding={[2]}\n title=\"Copy\"\n aria-label=\"Copy\"\n onClick={() => handleCopy()}\n />\n <Button\n fontSize={[1]}\n icon={LeaveIcon}\n padding={[2]}\n text=\"Open\"\n tone=\"primary\"\n onClick={() => window.open(displayUrl)}\n />\n </Flex>\n </Flex>\n </Card>\n <Card tone=\"transparent\" padding={iframeSize === 'mobile' ? 2 : 0} style={{height: `100%`}}>\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n {loader && loading && (\n <Flex justify=\"center\" align=\"center\" style={{inset: `0`, position: `absolute`}}>\n <Flex\n style={{...sizes[iframeSize], backgroundColor: `rgba(0,0,0,0.2)`}}\n justify=\"center\"\n align=\"center\"\n >\n <Card padding={4} radius={2} shadow={1}>\n <Flex align=\"center\" direction=\"column\" gap={3} height=\"fill\" justify=\"center\">\n <Spinner />\n {loader && typeof loader === 'string' && <Text size={1}>{loader}</Text>}\n </Flex>\n </Card>\n </Flex>\n </Flex>\n )}\n <iframe\n ref={iframe}\n title=\"preview\"\n style={sizes[iframeSize]}\n frameBorder=\"0\"\n src={displayUrl}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n </Flex>\n </Card>\n </Flex>\n </ThemeProvider>\n )\n}\n\nexport default Iframe\n"],"names":["sizes","desktop","width","height","maxHeight","mobile","DEFAULT_SIZE","Iframe","props","document","sanityDocument","options","url","defaultSize","reload","loader","attributes","showDisplayUrl","displayUrl","setDisplayUrl","useState","iframeSize","setIframeSize","loading","setLoading","input","useRef","iframe","displayed","copy","useCopyToClipboard","handleCopy","_a","current","value","handleReload","src","handleIframeLoad","onLoad","useEffect","revision","setTimeout","Number","_rev","getUrl","resolveUrl","jsx","ThemeProvider","children","Flex","padding","align","justify","Spinner","style","position","pointerEvents","opacity","ref","readOnly","tabIndex","jsxs","direction","Card","borderBottom","gap","Button","fontSize","tone","mode","icon","MobileDeviceIcon","onClick","Box","flex","Text","size","textOverflow","button","UndoIcon","title","CopyIcon","LeaveIcon","text","window","open","inset","backgroundColor","radius","shadow","frameBorder"],"mappings":";;;;;AAoBA,MAAMA,KAAmB,GAAA;EACvBC,OAAS,EAAA;IACPC,KAAO,QAAA;IACPC,MAAQ,QAAA;IACRC,SAAW;EACb,CAAA;EACAC,MAAQ,EAAA;IACNH,KAAO,EAAA,GAAA;IACPC,MAAQ,QAAA;IACRC,SAAW,EAAA;EACb;AACF,CAAA;AA0BA,MAAME,YAAe,YAAA;AAErB,SAASC,OAAOC,KAAoB,EAAA;EAClC,MAAM;IAACC,QAAA,EAAUC,cAAgB;IAAAC;EAAA,CAAW,GAAAH,KAAA;EACtC,MAAA;IACJI,GAAA;IACAC,WAAc,GAAAP,YAAA;IACdQ,MAAA;IACAC,MAAA;IACAC,aAAa,CAAC,CAAA;IACdC,cAAiB,GAAA;EACf,CAAA,GAAAN,OAAA;EACE,MAAA,CAACO,UAAY,EAAAC,aAAa,CAAI,GAAAC,QAAA,CAASR,OAAO,OAAOA,GAAA,KAAQ,QAAW,GAAAA,GAAA,KAAQ,CAAA;EAChF,MAAA,CAACS,YAAYC,aAAa,CAAA,GAAIF,UAASpB,KAAQ,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,KAAA,CAAAa,WAAA,CAAA,IAAeA,cAAcP,YAAY,CAAA;EAC9F,MAAM,CAACiB,OAAA,EAASC,UAAU,CAAA,GAAIJ,SAAS,KAAK,CAAA;EACtC,MAAAK,KAAA,GAAQC,OAA4B,IAAI,CAAA;EACxC,MAAAC,MAAA,GAASD,OAA0B,IAAI,CAAA;EACvC,MAAA;IAACE;EAAa,CAAA,GAAAlB,cAAA;EACpB,MAAM,GAAGmB,IAAI,CAAA,GAAIC,kBAAmB,EAAA;EAEpC,SAASC,UAAaA,CAAA,EAAA;IA7ExB,IAAAC,EAAA;IA8EQ,IAAA,EAAA,CAACA,EAAO,GAAAP,KAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,KAAA,CAAAQ,OAAA,KAAP,IAAgB,GAAA,KAAA,CAAA,GAAAD,EAAA,CAAAE,KAAA,CAAA,EAAO;IAEvBL,IAAA,CAAAJ,KAAA,CAAMQ,QAAQC,KAAK,CAAA;EAC1B;EAEA,SAASC,YAAeA,CAAA,EAAA;IAClB,IAAA,EAACR,iCAAQM,OAAS,CAAA,EAAA;MACpB;IACF;IAION,MAAA,CAAAM,OAAA,CAAQG,GAAM,GAAAT,MAAA,CAAOM,OAAQ,CAAAG,GAAA;IAEpCZ,UAAA,CAAW,IAAI,CAAA;EACjB;EAEA,SAASa,gBAAmBA,CAAA,EAAA;IAC1Bb,UAAA,CAAW,KAAK,CAAA;IAEhB,IAAIR,UAAW,CAAAsB,MAAA,IAAU,OAAOtB,UAAA,CAAWsB,WAAW,UAAY,EAAA;MAChEtB,UAAA,CAAWsB,MAAO,CAAA,CAAA;IACpB;EACF;EAGAC,SAAA,CAAU,MAAM;IACd,IAAA,CAAIzB,MAAQ,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,MAAA,CAAA0B,QAAA,KAAA,CAAY1B,MAAQ,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,MAAA,CAAA0B,QAAA,KAAY,CAAG,EAAA;MAC7CC,UAAA,CAAW,MAAM;QACFN,YAAA,EAAA;MAAA,CACZ,EAAAO,MAAA,CAAO5B,MAAQ,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,MAAA,CAAA0B,QAAQ,CAAC,CAAA;IAC7B;EAAA,GACC,CAACZ,SAAA,CAAUe,IAAM,EAAA7B,MAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,MAAA,CAAQ0B,QAAQ,CAAC,CAAA;EAGrCD,SAAA,CAAU,MAAM;IACd,MAAMK,SAAS,MAAAA,CAAA,KAAY;MACzBpB,UAAA,CAAW,IAAI,CAAA;MACf,MAAMqB,aAAa,OAAOjC,GAAA,KAAQ,aAAa,MAAMA,GAAA,CAAIgB,SAAS,CAAI,KAAA;MAGtE,IAAIiB,UAAe,KAAA3B,UAAA,IAAc2B,UAAc,IAAA,OAAOA,eAAe,QAAU,EAAA;QAC7E1B,aAAA,CAAc0B,UAAU,CAAA;MAC1B;IAAA,CACF;IAEI,IAAA,OAAOjC,QAAQ,UAAY,EAAA;MACtBgC,MAAA,EAAA;IACT;EAAA,CAEC,EAAA,CAAChB,SAAU,CAAAe,IAAI,CAAC,CAAA;EAEnB,IAAI,CAACzB,UAAA,IAAc,OAAOA,UAAA,KAAe,QAAU,EAAA;IACjD,sBACG4B,GAAA,CAAAC,aAAA,EAAA;MACCC,QAAC,EAAA,eAAAF,GAAA,CAAAG,IAAA,EAAA;QAAKC,OAAS,EAAA,CAAA;QAAGC,KAAM,EAAA,QAAA;QAASC,OAAQ,EAAA,QAAA;QACvCJ,QAAC,EAAA,eAAAF,GAAA,CAAAO,OAAA,EAAA,CAAQ,CAAA;OACX;IACF,CAAA,CAAA;EAEJ;EAEA,2BACGN,aACC,EAAA;IAAAC,QAAA,EAAA,CAAA,eAAAF,GAAA,CAAC,UAAA,EAAA;MACCQ,OAAO;QAACC,QAAA;QAAsBC,aAAe,QAAA;QAAQC,SAAS;MAAC,CAAA;MAC/DC,GAAK,EAAAjC,KAAA;MACLS,KAAO,EAAAhB,UAAA;MACPyC,QAAQ,EAAA,IAAA;MACRC,QAAU,EAAA,CAAA;IAAA,CACZ,CAAA,EACA,eAAAC,IAAA,CAACZ;MAAKa,SAAU,EAAA,QAAA;MAASR,OAAO;QAACnD,MAAA;MAC/B,CAAA;MAAA6C,QAAA,EAAA,CAAA,eAACF,GAAA,CAAAiB,IAAA,EAAA;QAAKb,OAAS,EAAA,CAAA;QAAGc,YAAY,EAAA,IAAA;QAC5BhB,8BAACC,IAAK,EAAA;UAAAE,KAAA,EAAM,QAAS;UAAAc,GAAA,EAAK,CACxB;UAAAjB,QAAA,EAAA,CAAA,eAAAF,GAAA,CAACG,IAAK,EAAA;YAAAE,KAAA,EAAM,QAAS;YAAAc,GAAA,EAAK,CACxB;YAAAjB,QAAA,iBAAAF,GAAA,CAACoB,MAAA,EAAA;cACCC,QAAA,EAAU,CAAC,CAAC,CAAA;cACZjB,OAAS,EAAA,CAAA;cACTkB,IAAK,EAAA,SAAA;cACLC,IAAA,EAAMhD,UAAe,KAAA,QAAA,GAAW,SAAY,GAAA,OAAA;cAC5CiD,IAAM,EAAAC,gBAAA;cACNC,SAASA,CAAA,KAAMlD,aAAA,CAAcD,UAAe,KAAA,QAAA,GAAW,YAAY,QAAQ;YAAA,CAAA;WAE/E,CAAA,EAAA,eACCyB,GAAA,CAAA2B,GAAA,EAAA;YAAIC,IAAM,EAAA,CAAA;YACR1B,QACC,EAAA/B,cAAA,IAAA,eAAA6B,GAAA,CAAC6B,IAAK,EAAA;cAAAC,IAAA,EAAM,CAAG;cAAAC,YAAA,EAAa,UACzB;cAAA7B,QAAA,EAAA9B;YACH,CAAA;WAEJ,CAAA,EAAA,eACC2C,IAAA,CAAAZ,IAAA,EAAA;YAAKE,KAAM,EAAA,QAAA;YAASc,KAAK,CACvB;YAAAjB,QAAA,EAAA,CAAA,CAAAlC,MAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,MAAA,CAAQgE,MACP,IAAA,eAAAhC,GAAA,CAACoB,MAAA,EAAA;cACCC,QAAA,EAAU,CAAC,CAAC,CAAA;cACZjB,OAAS,EAAA,CAAA;cACToB,IAAM,EAAAS,QAAA;cACNC,KAAM,EAAA,QAAA;cACN,YAAW,EAAA,QAAA;cACXR,OAAA,EAASA,CAAA,KAAMrC,YAAa,CAAA;YAAA,CAAA,CAE5B,GAAA,IAAA,EAAA,eACJW,GAAA,CAACoB,MAAA,EAAA;cACCC,QAAA,EAAU,CAAC,CAAC,CAAA;cACZG,IAAM,EAAAW,QAAA;cACN/B,OAAA,EAAS,CAAC,CAAC,CAAA;cACX8B,KAAM,EAAA,MAAA;cACN,YAAW,EAAA,MAAA;cACXR,OAAA,EAASA,CAAA,KAAMzC,UAAW,CAAA;YAAA,CAC5B,CAAA,EAAA,eACAe,GAAA,CAACoB,MAAA,EAAA;cACCC,QAAA,EAAU,CAAC,CAAC,CAAA;cACZG,IAAM,EAAAY,SAAA;cACNhC,OAAA,EAAS,CAAC,CAAC,CAAA;cACXiC,IAAK,EAAA,MAAA;cACLf,IAAK,EAAA,SAAA;cACLI,OAAS,EAAAA,CAAA,KAAMY,MAAO,CAAAC,IAAA,CAAKnE,UAAU;YAAA,CACvC,CAAA;WACF,CAAA;QAAA,CACF;MACF,CAAA,CAAA,EAAA,eACA4B,GAAA,CAACiB,IAAK,EAAA;QAAAK,IAAA,EAAK,aAAc;QAAAlB,OAAA,EAAS7B,UAAe,KAAA,QAAA,GAAW,CAAI,GAAA,CAAA;QAAGiC,KAAO,EAAA;UAACnD,MAAQ;QAAA;QACjF6C,QAAC,EAAA,eAAAa,IAAA,CAAAZ,IAAA,EAAA;UAAKE,KAAM,EAAA,QAAA;UAASC,OAAQ,EAAA,QAAA;UAASE,KAAO,EAAA;YAACnD,MAAQ,QAAA;YAAQoD,QAAU;UACrE,CAAA;UAAAP,QAAA,EAAA,CAAAjC,MAAA,IAAUQ,OACT,IAAA,eAAAuB,GAAA,CAACG,IAAK,EAAA;YAAAG,OAAA,EAAQ,QAAS;YAAAD,KAAA,EAAM,QAAS;YAAAG,KAAA,EAAO;cAACgC,KAAA,KAAY;cAAA/B,QAAA;aACxD;YAAAP,QAAA,iBAAAF,GAAA,CAACG,IAAA,EAAA;cACCK,OAAO;gBAAC,GAAGtD,MAAMqB,UAAU,CAAA;gBAAGkE;cAAkC,CAAA;cAChEnC,OAAQ,EAAA,QAAA;cACRD,KAAM,EAAA,QAAA;cAENH,6BAACe,IAAK,EAAA;gBAAAb,OAAA,EAAS;gBAAGsC,MAAQ,EAAA,CAAA;gBAAGC,QAAQ,CACnC;gBAAAzC,QAAA,EAAA,eAAAa,IAAA,CAACZ;kBAAKE,KAAM,EAAA,QAAA;kBAASW,WAAU,QAAS;kBAAAG,GAAA,EAAK;kBAAG9D,MAAO,EAAA,MAAA;kBAAOiD,SAAQ,QACpE;kBAAAJ,QAAA,EAAA,CAAA,eAAAF,GAAA,CAACO,OAAQ,EAAA,EAAA,CAAA,EACRtC,MAAA,IAAU,OAAOA,MAAW,KAAA,QAAA,IAAA,mBAAa4D,IAAK,EAAA;oBAAAC,IAAA,EAAM;oBAAI5B,QAAO,EAAAjC;mBAAA,CAAA;gBAAA,CAClE;cACF,CAAA;YAAA,CAAA;WAEJ,CAAA,EAAA,eAEF+B,GAAA,CAAC,QAAA,EAAA;YACCY,GAAK,EAAA/B,MAAA;YACLqD,KAAM,EAAA,SAAA;YACN1B,KAAA,EAAOtD,MAAMqB,UAAU,CAAA;YACvBqE,WAAY,EAAA,GAAA;YACZtD,GAAK,EAAAlB,UAAA;YACJ,GAAGF,UAAA;YACJsB,MAAQ,EAAAD;UAAA,CACV,CAAA;QAAA,CACF;MACF,CAAA,CAAA;KACF,CAAA;EACF,CAAA,CAAA;AAEJ;"}
package/lib/index.js CHANGED
@@ -1,2 +1,216 @@
1
- "use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function t(t){for(var i=1;i<arguments.length;i++){var r=null!=arguments[i]?arguments[i]:{};i%2?e(Object(r),!0).forEach((function(e){n(t,e,r[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):e(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var i=require("react/jsx-runtime"),r=require("react"),o=require("@sanity/ui"),l=require("@sanity/icons"),s=require("usehooks-ts");const c={desktop:{width:"100%",height:"100%",maxHeight:"100%"},mobile:{width:414,height:"100%",maxHeight:736}},a="desktop";module.exports=function(e){const{document:n,options:u}=e,{url:d,defaultSize:p=a,reload:f,loader:x,attributes:g={}}=u,[j,y]=r.useState(d&&"string"==typeof d?d:""),[h,b]=r.useState((null==c?void 0:c[p])?p:a),[v,m]=r.useState(!1),O=r.useRef(null),w=r.useRef(null),{displayed:C}=n,[,S]=s.useCopyToClipboard();function P(){(null==w?void 0:w.current)&&(w.current.src=w.current.src,m(!0))}return r.useEffect((()=>{((null==f?void 0:f.revision)||0==(null==f?void 0:f.revision))&&setTimeout((()=>{P()}),Number(null==f?void 0:f.revision))}),[C._rev,null==f?void 0:f.revision]),r.useEffect((()=>{"function"==typeof d&&(async()=>{m(!0);const e="function"==typeof d?await d(C):"";e!==j&&e&&"string"==typeof e&&y(e)})()}),[C._rev]),j&&"string"==typeof j?i.jsxs(o.ThemeProvider,{children:[i.jsx("textarea",{style:{position:"absolute",pointerEvents:"none",opacity:0},ref:O,value:j,readOnly:!0,tabIndex:-1}),i.jsxs(o.Flex,{direction:"column",style:{height:"100%"},children:[i.jsx(o.Card,{padding:2,borderBottom:!0,children:i.jsxs(o.Flex,{align:"center",gap:2,children:[i.jsx(o.Flex,{align:"center",gap:1,children:i.jsx(o.Button,{fontSize:[1],padding:2,tone:"primary",mode:"mobile"===h?"default":"ghost",icon:l.MobileDeviceIcon,onClick:()=>b("mobile"===h?"desktop":"mobile")})}),i.jsx(o.Box,{flex:1,children:i.jsx(o.Text,{size:0,textOverflow:"ellipsis",children:j})}),i.jsxs(o.Flex,{align:"center",gap:1,children:[(null==f?void 0:f.button)?i.jsx(o.Button,{fontSize:[1],padding:2,icon:l.UndoIcon,title:"Reload","aria-label":"Reload",onClick:()=>P()}):null,i.jsx(o.Button,{fontSize:[1],icon:l.CopyIcon,padding:[2],title:"Copy","aria-label":"Copy",onClick:()=>{var e;(null==(e=null==O?void 0:O.current)?void 0:e.value)&&S(O.current.value)}}),i.jsx(o.Button,{fontSize:[1],icon:l.LeaveIcon,padding:[2],text:"Open",tone:"primary",onClick:()=>window.open(j)})]})]})}),i.jsx(o.Card,{tone:"transparent",padding:"mobile"===h?2:0,style:{height:"100%"},children:i.jsxs(o.Flex,{align:"center",justify:"center",style:{height:"100%",position:"relative"},children:[x&&v&&i.jsx(o.Flex,{justify:"center",align:"center",style:{inset:"0",position:"absolute"},children:i.jsx(o.Flex,{style:t(t({},c[h]),{},{backgroundColor:"rgba(0,0,0,0.2)"}),justify:"center",align:"center",children:i.jsx(o.Card,{padding:4,radius:2,shadow:1,children:i.jsxs(o.Flex,{align:"center",direction:"column",gap:3,height:"fill",justify:"center",children:[i.jsx(o.Spinner,{}),x&&"string"==typeof x&&i.jsx(o.Text,{size:1,children:x})]})})})}),i.jsx("iframe",t(t({ref:w,title:"preview",style:c[h],frameBorder:"0",src:j},g),{},{onLoad:function(){m(!1),g.onLoad&&"function"==typeof g.onLoad&&g.onLoad()}}))]})})]})]}):i.jsx(o.ThemeProvider,{children:i.jsx(o.Flex,{padding:5,align:"center",justify:"center",children:i.jsx(o.Spinner,{})})})};
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var ui = require('@sanity/ui');
6
+ var icons = require('@sanity/icons');
7
+ var usehooksTs = require('usehooks-ts');
8
+ const sizes = {
9
+ desktop: {
10
+ width: "100%",
11
+ height: "100%",
12
+ maxHeight: "100%"
13
+ },
14
+ mobile: {
15
+ width: 414,
16
+ height: "100%",
17
+ maxHeight: 736
18
+ }
19
+ };
20
+ const DEFAULT_SIZE = "desktop";
21
+ function Iframe(props) {
22
+ const {
23
+ document: sanityDocument,
24
+ options
25
+ } = props;
26
+ const {
27
+ url,
28
+ defaultSize = DEFAULT_SIZE,
29
+ reload,
30
+ loader,
31
+ attributes = {},
32
+ showDisplayUrl = true
33
+ } = options;
34
+ const [displayUrl, setDisplayUrl] = react.useState(url && typeof url === "string" ? url : "");
35
+ const [iframeSize, setIframeSize] = react.useState((sizes == null ? void 0 : sizes[defaultSize]) ? defaultSize : DEFAULT_SIZE);
36
+ const [loading, setLoading] = react.useState(false);
37
+ const input = react.useRef(null);
38
+ const iframe = react.useRef(null);
39
+ const {
40
+ displayed
41
+ } = sanityDocument;
42
+ const [, copy] = usehooksTs.useCopyToClipboard();
43
+ function handleCopy() {
44
+ var _a;
45
+ if (!((_a = input == null ? void 0 : input.current) == null ? void 0 : _a.value)) return;
46
+ copy(input.current.value);
47
+ }
48
+ function handleReload() {
49
+ if (!(iframe == null ? void 0 : iframe.current)) {
50
+ return;
51
+ }
52
+ iframe.current.src = iframe.current.src;
53
+ setLoading(true);
54
+ }
55
+ function handleIframeLoad() {
56
+ setLoading(false);
57
+ if (attributes.onLoad && typeof attributes.onLoad === "function") {
58
+ attributes.onLoad();
59
+ }
60
+ }
61
+ react.useEffect(() => {
62
+ if ((reload == null ? void 0 : reload.revision) || (reload == null ? void 0 : reload.revision) == 0) {
63
+ setTimeout(() => {
64
+ handleReload();
65
+ }, Number(reload == null ? void 0 : reload.revision));
66
+ }
67
+ }, [displayed._rev, reload == null ? void 0 : reload.revision]);
68
+ react.useEffect(() => {
69
+ const getUrl = async () => {
70
+ setLoading(true);
71
+ const resolveUrl = typeof url === "function" ? await url(displayed) : "";
72
+ if (resolveUrl !== displayUrl && resolveUrl && typeof resolveUrl === "string") {
73
+ setDisplayUrl(resolveUrl);
74
+ }
75
+ };
76
+ if (typeof url === "function") {
77
+ getUrl();
78
+ }
79
+ }, [displayed._rev]);
80
+ if (!displayUrl || typeof displayUrl !== "string") {
81
+ return /* @__PURE__ */jsxRuntime.jsx(ui.ThemeProvider, {
82
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
83
+ padding: 5,
84
+ align: "center",
85
+ justify: "center",
86
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
87
+ })
88
+ });
89
+ }
90
+ return /* @__PURE__ */jsxRuntime.jsxs(ui.ThemeProvider, {
91
+ children: [/* @__PURE__ */jsxRuntime.jsx("textarea", {
92
+ style: {
93
+ position: "absolute",
94
+ pointerEvents: "none",
95
+ opacity: 0
96
+ },
97
+ ref: input,
98
+ value: displayUrl,
99
+ readOnly: true,
100
+ tabIndex: -1
101
+ }), /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
102
+ direction: "column",
103
+ style: {
104
+ height: "100%"
105
+ },
106
+ children: [/* @__PURE__ */jsxRuntime.jsx(ui.Card, {
107
+ padding: 2,
108
+ borderBottom: true,
109
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
110
+ align: "center",
111
+ gap: 2,
112
+ children: [/* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
113
+ align: "center",
114
+ gap: 1,
115
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
116
+ fontSize: [1],
117
+ padding: 2,
118
+ tone: "primary",
119
+ mode: iframeSize === "mobile" ? "default" : "ghost",
120
+ icon: icons.MobileDeviceIcon,
121
+ onClick: () => setIframeSize(iframeSize === "mobile" ? "desktop" : "mobile")
122
+ })
123
+ }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
124
+ flex: 1,
125
+ children: showDisplayUrl && /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
126
+ size: 0,
127
+ textOverflow: "ellipsis",
128
+ children: displayUrl
129
+ })
130
+ }), /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
131
+ align: "center",
132
+ gap: 1,
133
+ children: [(reload == null ? void 0 : reload.button) ? /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
134
+ fontSize: [1],
135
+ padding: 2,
136
+ icon: icons.UndoIcon,
137
+ title: "Reload",
138
+ "aria-label": "Reload",
139
+ onClick: () => handleReload()
140
+ }) : null, /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
141
+ fontSize: [1],
142
+ icon: icons.CopyIcon,
143
+ padding: [2],
144
+ title: "Copy",
145
+ "aria-label": "Copy",
146
+ onClick: () => handleCopy()
147
+ }), /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
148
+ fontSize: [1],
149
+ icon: icons.LeaveIcon,
150
+ padding: [2],
151
+ text: "Open",
152
+ tone: "primary",
153
+ onClick: () => window.open(displayUrl)
154
+ })]
155
+ })]
156
+ })
157
+ }), /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
158
+ tone: "transparent",
159
+ padding: iframeSize === "mobile" ? 2 : 0,
160
+ style: {
161
+ height: "100%"
162
+ },
163
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
164
+ align: "center",
165
+ justify: "center",
166
+ style: {
167
+ height: "100%",
168
+ position: "relative"
169
+ },
170
+ children: [loader && loading && /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
171
+ justify: "center",
172
+ align: "center",
173
+ style: {
174
+ inset: "0",
175
+ position: "absolute"
176
+ },
177
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
178
+ style: {
179
+ ...sizes[iframeSize],
180
+ backgroundColor: "rgba(0,0,0,0.2)"
181
+ },
182
+ justify: "center",
183
+ align: "center",
184
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
185
+ padding: 4,
186
+ radius: 2,
187
+ shadow: 1,
188
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
189
+ align: "center",
190
+ direction: "column",
191
+ gap: 3,
192
+ height: "fill",
193
+ justify: "center",
194
+ children: [/* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {}), loader && typeof loader === "string" && /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
195
+ size: 1,
196
+ children: loader
197
+ })]
198
+ })
199
+ })
200
+ })
201
+ }), /* @__PURE__ */jsxRuntime.jsx("iframe", {
202
+ ref: iframe,
203
+ title: "preview",
204
+ style: sizes[iframeSize],
205
+ frameBorder: "0",
206
+ src: displayUrl,
207
+ ...attributes,
208
+ onLoad: handleIframeLoad
209
+ })]
210
+ })
211
+ })]
212
+ })]
213
+ });
214
+ }
215
+ module.exports = Iframe;
2
216
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/Iframe.tsx"],"sourcesContent":["/* eslint-disable react/jsx-no-bind */\nimport React, {useEffect, useState, useRef} from 'react'\nimport {SanityDocumentLike} from 'sanity'\nimport {Box, Flex, Text, Button, ThemeProvider, Card, Spinner} from '@sanity/ui'\nimport {UndoIcon, CopyIcon, LeaveIcon, MobileDeviceIcon} from '@sanity/icons'\nimport {HTMLAttributeReferrerPolicy} from 'react'\n\nimport {useCopyToClipboard} from 'usehooks-ts'\n\ntype Size = 'desktop' | 'mobile'\n\ntype SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n maxHeight: string | number\n }\n}\n\nconst sizes: SizeProps = {\n desktop: {\n width: `100%`,\n height: `100%`,\n maxHeight: `100%`,\n },\n mobile: {\n width: 414,\n height: `100%`,\n maxHeight: 736,\n },\n}\n\nexport type IframeOptions = {\n url: string | ((document: SanityDocumentLike) => unknown)\n defaultSize?: 'desktop' | 'mobile'\n loader?: boolean | string\n reload: {\n revision: boolean | number\n button: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nexport type IframeProps = {\n document: {\n displayed: SanityDocumentLike\n }\n options: IframeOptions\n}\n\nconst DEFAULT_SIZE = `desktop`\n\nfunction Iframe(props: IframeProps) {\n const {document: sanityDocument, options} = props\n const {url, defaultSize = DEFAULT_SIZE, reload, loader, attributes = {}} = options\n const [displayUrl, setDisplayUrl] = useState(url && typeof url === 'string' ? url : ``)\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n const [loading, setLoading] = useState(false)\n const input = useRef<HTMLTextAreaElement>(null)\n const iframe = useRef<HTMLIFrameElement>(null)\n const {displayed} = sanityDocument\n const [, copy] = useCopyToClipboard()\n\n function handleCopy() {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n }\n\n function handleReload() {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issuies\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setLoading(true)\n }\n\n function handleIframeLoad() {\n setLoading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n // Reload on new revisions\n useEffect(() => {\n if (reload?.revision || reload?.revision == 0) {\n setTimeout(() => {\n handleReload()\n }, Number(reload?.revision))\n }\n }, [displayed._rev, reload?.revision])\n\n // Set initial URL and refresh on new revisions\n useEffect(() => {\n const getUrl = async () => {\n setLoading(true)\n const resolveUrl = typeof url === 'function' ? await url(displayed) : ``\n\n // Only update state if URL has changed\n if (resolveUrl !== displayUrl && resolveUrl && typeof resolveUrl === 'string') {\n setDisplayUrl(resolveUrl)\n }\n }\n\n if (typeof url === 'function') {\n getUrl()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [displayed._rev])\n\n if (!displayUrl || typeof displayUrl !== 'string') {\n return (\n <ThemeProvider>\n <Flex padding={5} align=\"center\" justify=\"center\">\n <Spinner />\n </Flex>\n </ThemeProvider>\n )\n }\n\n return (\n <ThemeProvider>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={displayUrl}\n readOnly\n tabIndex={-1}\n />\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Button\n fontSize={[1]}\n padding={2}\n tone=\"primary\"\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Flex>\n <Box flex={1}>\n <Text size={0} textOverflow=\"ellipsis\">\n {displayUrl}\n </Text>\n </Box>\n <Flex align=\"center\" gap={1}>\n {reload?.button ? (\n <Button\n fontSize={[1]}\n padding={2}\n icon={UndoIcon}\n title=\"Reload\"\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n ) : null}\n <Button\n fontSize={[1]}\n icon={CopyIcon}\n padding={[2]}\n title=\"Copy\"\n aria-label=\"Copy\"\n onClick={() => handleCopy()}\n />\n <Button\n fontSize={[1]}\n icon={LeaveIcon}\n padding={[2]}\n text=\"Open\"\n tone=\"primary\"\n onClick={() => window.open(displayUrl)}\n />\n </Flex>\n </Flex>\n </Card>\n <Card tone=\"transparent\" padding={iframeSize === 'mobile' ? 2 : 0} style={{height: `100%`}}>\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n {loader && loading && (\n <Flex justify=\"center\" align=\"center\" style={{inset: `0`, position: `absolute`}}>\n <Flex\n style={{...sizes[iframeSize], backgroundColor: `rgba(0,0,0,0.2)`}}\n justify=\"center\"\n align=\"center\"\n >\n <Card padding={4} radius={2} shadow={1}>\n <Flex align=\"center\" direction=\"column\" gap={3} height=\"fill\" justify=\"center\">\n <Spinner />\n {loader && typeof loader === 'string' && <Text size={1}>{loader}</Text>}\n </Flex>\n </Card>\n </Flex>\n </Flex>\n )}\n <iframe\n ref={iframe}\n title=\"preview\"\n style={sizes[iframeSize]}\n frameBorder=\"0\"\n src={displayUrl}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n </Flex>\n </Card>\n </Flex>\n </ThemeProvider>\n )\n}\n\nexport default Iframe\n"],"names":["sizes","desktop","width","height","maxHeight","mobile","DEFAULT_SIZE","props","document","sanityDocument","options","url","defaultSize","reload","loader","attributes","displayUrl","setDisplayUrl","useState","iframeSize","setIframeSize","loading","setLoading","input","useRef","iframe","displayed","copy","useCopyToClipboard","handleReload","current","src","useEffect","revision","setTimeout","Number","_rev","async","resolveUrl","getUrl","jsxs","ThemeProvider","children","jsx","style","position","pointerEvents","opacity","ref","value","readOnly","tabIndex","Flex","direction","Card","padding","borderBottom","align","gap","Button","fontSize","tone","mode","icon","MobileDeviceIcon","onClick","Box","flex","Text","size","textOverflow","button","UndoIcon","title","CopyIcon","_a","LeaveIcon","text","window","open","justify","inset","backgroundColor","radius","shadow","Spinner","_objectSpread","frameBorder","onLoad"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/Iframe.tsx"],"sourcesContent":["/* eslint-disable react/jsx-no-bind */\nimport React, {useEffect, useState, useRef} from 'react'\nimport {SanityDocumentLike} from 'sanity'\nimport {Box, Flex, Text, Button, ThemeProvider, Card, Spinner} from '@sanity/ui'\nimport {UndoIcon, CopyIcon, LeaveIcon, MobileDeviceIcon} from '@sanity/icons'\nimport {HTMLAttributeReferrerPolicy} from 'react'\n\nimport {useCopyToClipboard} from 'usehooks-ts'\n\ntype Size = 'desktop' | 'mobile'\n\ntype SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n maxHeight: string | number\n }\n}\n\nconst sizes: SizeProps = {\n desktop: {\n width: `100%`,\n height: `100%`,\n maxHeight: `100%`,\n },\n mobile: {\n width: 414,\n height: `100%`,\n maxHeight: 736,\n },\n}\n\nexport type IframeOptions = {\n url: string | ((document: SanityDocumentLike) => unknown)\n defaultSize?: 'desktop' | 'mobile'\n loader?: boolean | string\n showDisplayUrl?: boolean\n reload: {\n revision: boolean | number\n button: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nexport type IframeProps = {\n document: {\n displayed: SanityDocumentLike\n }\n options: IframeOptions\n}\n\nconst DEFAULT_SIZE = `desktop`\n\nfunction Iframe(props: IframeProps) {\n const {document: sanityDocument, options} = props\n const {\n url,\n defaultSize = DEFAULT_SIZE,\n reload,\n loader,\n attributes = {},\n showDisplayUrl = true,\n } = options\n const [displayUrl, setDisplayUrl] = useState(url && typeof url === 'string' ? url : ``)\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n const [loading, setLoading] = useState(false)\n const input = useRef<HTMLTextAreaElement>(null)\n const iframe = useRef<HTMLIFrameElement>(null)\n const {displayed} = sanityDocument\n const [, copy] = useCopyToClipboard()\n\n function handleCopy() {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n }\n\n function handleReload() {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issuies\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setLoading(true)\n }\n\n function handleIframeLoad() {\n setLoading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n // Reload on new revisions\n useEffect(() => {\n if (reload?.revision || reload?.revision == 0) {\n setTimeout(() => {\n handleReload()\n }, Number(reload?.revision))\n }\n }, [displayed._rev, reload?.revision])\n\n // Set initial URL and refresh on new revisions\n useEffect(() => {\n const getUrl = async () => {\n setLoading(true)\n const resolveUrl = typeof url === 'function' ? await url(displayed) : ``\n\n // Only update state if URL has changed\n if (resolveUrl !== displayUrl && resolveUrl && typeof resolveUrl === 'string') {\n setDisplayUrl(resolveUrl)\n }\n }\n\n if (typeof url === 'function') {\n getUrl()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [displayed._rev])\n\n if (!displayUrl || typeof displayUrl !== 'string') {\n return (\n <ThemeProvider>\n <Flex padding={5} align=\"center\" justify=\"center\">\n <Spinner />\n </Flex>\n </ThemeProvider>\n )\n }\n\n return (\n <ThemeProvider>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={displayUrl}\n readOnly\n tabIndex={-1}\n />\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Button\n fontSize={[1]}\n padding={2}\n tone=\"primary\"\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Flex>\n <Box flex={1}>\n {showDisplayUrl && (\n <Text size={0} textOverflow=\"ellipsis\">\n {displayUrl}\n </Text>\n )}\n </Box>\n <Flex align=\"center\" gap={1}>\n {reload?.button ? (\n <Button\n fontSize={[1]}\n padding={2}\n icon={UndoIcon}\n title=\"Reload\"\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n ) : null}\n <Button\n fontSize={[1]}\n icon={CopyIcon}\n padding={[2]}\n title=\"Copy\"\n aria-label=\"Copy\"\n onClick={() => handleCopy()}\n />\n <Button\n fontSize={[1]}\n icon={LeaveIcon}\n padding={[2]}\n text=\"Open\"\n tone=\"primary\"\n onClick={() => window.open(displayUrl)}\n />\n </Flex>\n </Flex>\n </Card>\n <Card tone=\"transparent\" padding={iframeSize === 'mobile' ? 2 : 0} style={{height: `100%`}}>\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n {loader && loading && (\n <Flex justify=\"center\" align=\"center\" style={{inset: `0`, position: `absolute`}}>\n <Flex\n style={{...sizes[iframeSize], backgroundColor: `rgba(0,0,0,0.2)`}}\n justify=\"center\"\n align=\"center\"\n >\n <Card padding={4} radius={2} shadow={1}>\n <Flex align=\"center\" direction=\"column\" gap={3} height=\"fill\" justify=\"center\">\n <Spinner />\n {loader && typeof loader === 'string' && <Text size={1}>{loader}</Text>}\n </Flex>\n </Card>\n </Flex>\n </Flex>\n )}\n <iframe\n ref={iframe}\n title=\"preview\"\n style={sizes[iframeSize]}\n frameBorder=\"0\"\n src={displayUrl}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n </Flex>\n </Card>\n </Flex>\n </ThemeProvider>\n )\n}\n\nexport default Iframe\n"],"names":["sizes","desktop","width","height","maxHeight","mobile","DEFAULT_SIZE","Iframe","props","document","sanityDocument","options","url","defaultSize","reload","loader","attributes","showDisplayUrl","displayUrl","setDisplayUrl","useState","iframeSize","setIframeSize","loading","setLoading","input","useRef","iframe","displayed","copy","useCopyToClipboard","handleCopy","_a","current","value","handleReload","src","handleIframeLoad","onLoad","useEffect","revision","setTimeout","Number","_rev","getUrl","resolveUrl","jsx","ThemeProvider","children","Flex","padding","align","justify","Spinner","style","position","pointerEvents","opacity","ref","readOnly","tabIndex","jsxs","direction","Card","borderBottom","gap","Button","fontSize","tone","mode","icon","MobileDeviceIcon","onClick","Box","flex","Text","size","textOverflow","button","UndoIcon","title","CopyIcon","LeaveIcon","text","window","open","inset","backgroundColor","radius","shadow","frameBorder"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import {HTMLAttributeReferrerPolicy} from 'react'
2
+ import {JSX as JSX_2} from 'react/jsx-runtime'
2
3
  import {SanityDocumentLike} from 'sanity'
3
4
 
4
- declare function Iframe(props: IframeProps): JSX.Element
5
+ declare function Iframe(props: IframeProps): JSX_2.Element
5
6
  export default Iframe
6
7
 
7
8
  export declare type IframeOptions = IframeOptions_2
@@ -10,6 +11,7 @@ declare type IframeOptions_2 = {
10
11
  url: string | ((document: SanityDocumentLike) => unknown)
11
12
  defaultSize?: 'desktop' | 'mobile'
12
13
  loader?: boolean | string
14
+ showDisplayUrl?: boolean
13
15
  reload: {
14
16
  revision: boolean | number
15
17
  button: boolean
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-iframe-pane",
3
- "version": "2.2.0",
3
+ "version": "2.3.1-beta.0",
4
4
  "description": "Display any URL in a View Pane, along with helpful buttons to Copy the URL or open in a new tab",
5
5
  "homepage": "https://github.com/sanity-io/sanity-plugin-iframe-pane#readme",
6
6
  "bugs": {
@@ -11,13 +11,14 @@
11
11
  "url": "git@github.com:sanity-io/sanity-plugin-iframe-pane.git"
12
12
  },
13
13
  "license": "MIT",
14
- "author": "Simeon Griggs <simeon@sanity.io>",
14
+ "author": "Sanity.io <hello@sanity.io>",
15
+ "sideEffects": false,
15
16
  "exports": {
16
17
  ".": {
17
18
  "types": "./lib/src/index.d.ts",
18
19
  "source": "./src/index.ts",
19
- "import": "./lib/index.esm.js",
20
20
  "require": "./lib/index.js",
21
+ "import": "./lib/index.esm.js",
21
22
  "default": "./lib/index.esm.js"
22
23
  },
23
24
  "./package.json": "./package.json"
@@ -29,51 +30,58 @@
29
30
  "files": [
30
31
  "src",
31
32
  "lib",
32
- "v2-incompatible.js",
33
- "sanity.json"
33
+ "sanity.json",
34
+ "v2-incompatible.js"
34
35
  ],
35
36
  "scripts": {
36
37
  "prebuild": "npm run clean && plugin-kit verify-package --silent && pkg-utils",
37
- "build": "pkg-utils build --strict",
38
+ "build": "run-s clean && plugin-kit verify-package --silent && pkg-utils build --strict && pkg-utils --strict",
38
39
  "clean": "rimraf lib",
40
+ "format": "prettier --write --cache --ignore-unknown .",
39
41
  "link-watch": "plugin-kit link-watch",
40
42
  "lint": "eslint .",
41
43
  "prepare": "husky install",
42
- "prepublishOnly": "npm run build",
43
- "watch": "pkg-utils watch"
44
+ "prepublishOnly": "run-s build",
45
+ "watch": "pkg-utils watch --strict"
44
46
  },
45
47
  "dependencies": {
46
- "@sanity/icons": "^2.0.0",
47
- "@sanity/incompatible-plugin": "^1.0.4",
48
+ "@sanity/icons": "^2.2.2",
49
+ "@sanity/incompatible-plugin": "^1.0.0",
48
50
  "@sanity/ui": "^1.0.0",
49
- "usehooks-ts": "^2.6.0"
51
+ "usehooks-ts": "2.9.1"
50
52
  },
51
53
  "devDependencies": {
52
- "@commitlint/cli": "^17.2.0",
53
- "@commitlint/config-conventional": "^17.2.0",
54
- "@sanity/pkg-utils": "^1.17.2",
55
- "@sanity/plugin-kit": "^2.1.5",
56
- "@sanity/semantic-release-preset": "^2.0.2",
57
- "@typescript-eslint/eslint-plugin": "^5.42.0",
58
- "@typescript-eslint/parser": "^5.42.0",
59
- "eslint": "^8.26.0",
60
- "eslint-config-prettier": "^8.5.0",
54
+ "@commitlint/cli": "^17.6.3",
55
+ "@commitlint/config-conventional": "^17.6.3",
56
+ "@sanity/pkg-utils": "^2.2.16",
57
+ "@sanity/plugin-kit": "^3.1.7",
58
+ "@sanity/semantic-release-preset": "^4.1.1",
59
+ "@typescript-eslint/eslint-plugin": "^5.59.7",
60
+ "@typescript-eslint/parser": "^5.59.7",
61
+ "eslint": "^8.41.0",
62
+ "eslint-config-prettier": "^8.8.0",
61
63
  "eslint-config-sanity": "^6.0.0",
62
64
  "eslint-plugin-prettier": "^4.2.1",
63
- "eslint-plugin-react": "^7.31.10",
65
+ "eslint-plugin-react": "^7.32.2",
64
66
  "eslint-plugin-react-hooks": "^4.6.0",
65
- "husky": "^8.0.1",
66
- "lint-staged": "^13.0.3",
67
- "prettier": "^2.7.1",
68
- "prettier-plugin-packagejson": "^2.3.0",
69
- "react": "^18",
70
- "rimraf": "^3.0.2",
71
- "sanity": "^3.0.0",
72
- "typescript": "^4.8.4"
67
+ "husky": "^8.0.3",
68
+ "lint-staged": "^13.2.2",
69
+ "npm-run-all": "^4.1.5",
70
+ "prettier": "^2.8.8",
71
+ "prettier-plugin-packagejson": "^2.4.3",
72
+ "react": "^18.2.0",
73
+ "react-dom": "^18.2.0",
74
+ "react-is": "^18.2.0",
75
+ "rimraf": "^5.0.1",
76
+ "sanity": "^3.11.1",
77
+ "styled-components": "^5.3.6",
78
+ "typescript": "^5.0.4"
73
79
  },
74
80
  "peerDependencies": {
75
81
  "react": "^18",
76
- "sanity": "^3.0.0"
82
+ "react-dom": "^18",
83
+ "sanity": "^3",
84
+ "styled-components": "^5.2"
77
85
  },
78
86
  "engines": {
79
87
  "node": ">=14"
package/src/Iframe.tsx CHANGED
@@ -35,6 +35,7 @@ export type IframeOptions = {
35
35
  url: string | ((document: SanityDocumentLike) => unknown)
36
36
  defaultSize?: 'desktop' | 'mobile'
37
37
  loader?: boolean | string
38
+ showDisplayUrl?: boolean
38
39
  reload: {
39
40
  revision: boolean | number
40
41
  button: boolean
@@ -58,7 +59,14 @@ const DEFAULT_SIZE = `desktop`
58
59
 
59
60
  function Iframe(props: IframeProps) {
60
61
  const {document: sanityDocument, options} = props
61
- const {url, defaultSize = DEFAULT_SIZE, reload, loader, attributes = {}} = options
62
+ const {
63
+ url,
64
+ defaultSize = DEFAULT_SIZE,
65
+ reload,
66
+ loader,
67
+ attributes = {},
68
+ showDisplayUrl = true,
69
+ } = options
62
70
  const [displayUrl, setDisplayUrl] = useState(url && typeof url === 'string' ? url : ``)
63
71
  const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)
64
72
  const [loading, setLoading] = useState(false)
@@ -153,9 +161,11 @@ function Iframe(props: IframeProps) {
153
161
  />
154
162
  </Flex>
155
163
  <Box flex={1}>
156
- <Text size={0} textOverflow="ellipsis">
157
- {displayUrl}
158
- </Text>
164
+ {showDisplayUrl && (
165
+ <Text size={0} textOverflow="ellipsis">
166
+ {displayUrl}
167
+ </Text>
168
+ )}
159
169
  </Box>
160
170
  <Flex align="center" gap={1}>
161
171
  {reload?.button ? (