sanity-plugin-iframe-pane 2.3.1-beta.1 → 2.3.2-canary.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.
Files changed (39) hide show
  1. package/lib/_chunks/is-valid-secret-3aaae7ae.js +35 -0
  2. package/lib/_chunks/is-valid-secret-3aaae7ae.js.map +1 -0
  3. package/lib/_chunks/is-valid-secret-71f6ff4a.cjs +41 -0
  4. package/lib/_chunks/is-valid-secret-71f6ff4a.cjs.map +1 -0
  5. package/lib/_chunks/types-43de0b73.cjs +38 -0
  6. package/lib/_chunks/types-43de0b73.cjs.map +1 -0
  7. package/lib/_chunks/types-4860e7b4.js +34 -0
  8. package/lib/_chunks/types-4860e7b4.js.map +1 -0
  9. package/lib/index.cjs +461 -154
  10. package/lib/index.cjs.js +2 -1
  11. package/lib/index.cjs.map +1 -1
  12. package/lib/index.d.ts +38 -13
  13. package/lib/index.js +462 -158
  14. package/lib/index.js.map +1 -1
  15. package/lib/is-valid-secret.cjs +8 -0
  16. package/lib/is-valid-secret.cjs.js +4 -0
  17. package/lib/is-valid-secret.cjs.map +1 -0
  18. package/lib/is-valid-secret.d.ts +41 -0
  19. package/lib/is-valid-secret.js +2 -0
  20. package/lib/is-valid-secret.js.map +1 -0
  21. package/lib/preview-url.cjs +77 -0
  22. package/lib/preview-url.cjs.js +4 -0
  23. package/lib/preview-url.cjs.map +1 -0
  24. package/lib/preview-url.d.ts +17 -0
  25. package/lib/preview-url.js +72 -0
  26. package/lib/preview-url.js.map +1 -0
  27. package/package.json +34 -10
  28. package/src/DisplayUrl.tsx +21 -0
  29. package/src/GetUrlSecret.tsx +80 -0
  30. package/src/Iframe.tsx +272 -158
  31. package/src/Toolbar.tsx +153 -0
  32. package/src/defineUrlResolver.tsx +31 -0
  33. package/src/index.ts +3 -5
  34. package/src/is-valid-secret.ts +2 -0
  35. package/src/isValidSecret.tsx +68 -0
  36. package/src/preview-url.ts +2 -0
  37. package/src/previewUrl.ts +62 -0
  38. package/src/types.ts +17 -0
  39. package/src/utils.ts +45 -0
package/lib/index.js CHANGED
@@ -1,91 +1,113 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { MobileDeviceIcon, UndoIcon, CopyIcon, LeaveIcon } from '@sanity/icons';
3
- import { ThemeProvider, Flex, Spinner, Card, Button, Box, Text } from '@sanity/ui';
4
- import { useState, useRef, useEffect } from 'react';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { MobileDeviceIcon, UndoIcon, ClipboardIcon, LaunchIcon, WarningOutlineIcon } from '@sanity/icons';
3
+ import { Text, useToast, Card, Flex, Tooltip, Button, Box, Spinner, usePrefersReducedMotion, Container, Stack } from '@sanity/ui';
4
+ import { motion, AnimatePresence, MotionConfig } from 'framer-motion';
5
+ import { useState, useEffect, useMemo, useRef, forwardRef, useCallback, useDeferredValue } from 'react';
6
+ import { useClient } from 'sanity';
7
+ import { apiVersion, fetchSecretQuery, tag } from './_chunks/is-valid-secret-3aaae7ae.js';
8
+ import { patchUrlSecret, getExpiresAt, MissingSlug } from './_chunks/types-4860e7b4.js';
5
9
  import { useCopyToClipboard } from 'usehooks-ts';
10
+ function GetUrlSecret(props) {
11
+ const {
12
+ urlSecretId,
13
+ setUrlSecret,
14
+ urlSecret,
15
+ setError
16
+ } = props;
17
+ const client = useClient({
18
+ apiVersion
19
+ });
20
+ const [secretExpiresAt, setSecretExpiresAt] = useState(null);
21
+ if (!urlSecretId.includes(".")) {
22
+ throw new TypeError("`urlSecretId` must have a dot prefix, `".concat(urlSecretId, "` is not secure, add a prefix, for example `preview.").concat(urlSecretId, "` "));
23
+ }
24
+ useEffect(() => {
25
+ if (urlSecret) return;
26
+ async function getSecret(signal) {
27
+ const data = await client.fetch(fetchSecretQuery, {
28
+ id: urlSecretId
29
+ }, {
30
+ signal,
31
+ tag
32
+ });
33
+ if (signal.aborted) return;
34
+ if (!(data == null ? void 0 : data.secret) || !(data == null ? void 0 : data._updatedAt)) {
35
+ try {
36
+ const newUpdatedAt = /* @__PURE__ */new Date();
37
+ const newSecret = await patchUrlSecret(client, urlSecretId, signal);
38
+ if (signal.aborted) return;
39
+ setUrlSecret(newSecret);
40
+ setSecretExpiresAt(getExpiresAt(newUpdatedAt));
41
+ } catch (err) {
42
+ console.error("Failed to create a new preview secret. Ensure the `client` has a `token` specified that has `write` permissions.", err);
43
+ }
44
+ return;
45
+ }
46
+ if ((data == null ? void 0 : data.secret) !== urlSecret) {
47
+ setUrlSecret(data == null ? void 0 : data.secret);
48
+ setSecretExpiresAt(getExpiresAt(new Date(data == null ? void 0 : data._updatedAt)));
49
+ }
50
+ }
51
+ const abort = new AbortController();
52
+ getSecret(abort.signal).catch(error => error.name !== "AbortError" && setError(error));
53
+ return () => abort.abort();
54
+ }, [client, setError, setUrlSecret, urlSecret, urlSecretId]);
55
+ useEffect(() => {
56
+ if (!secretExpiresAt) return;
57
+ const timeout = setTimeout(() => {
58
+ setUrlSecret(null);
59
+ setSecretExpiresAt(null);
60
+ }, Math.max(0, secretExpiresAt.getTime() - /* @__PURE__ */new Date().getTime()));
61
+ return () => clearTimeout(timeout);
62
+ }, [secretExpiresAt, setUrlSecret]);
63
+ return null;
64
+ }
65
+ function DisplayUrl(_ref) {
66
+ let {
67
+ displayUrl
68
+ } = _ref;
69
+ const truncatedUrl = useMemo(() => {
70
+ const url = new URL(displayUrl);
71
+ if (url.searchParams.has("secret")) {
72
+ url.searchParams.delete("secret");
73
+ url.searchParams.append("secret", "***");
74
+ }
75
+ return "".concat(url.origin === location.origin ? "" : url.origin).concat(url.pathname).concat(url.search);
76
+ }, [displayUrl]);
77
+ return /* @__PURE__ */jsx(Text, {
78
+ size: 0,
79
+ textOverflow: "ellipsis",
80
+ title: displayUrl,
81
+ children: truncatedUrl
82
+ });
83
+ }
6
84
  const sizes = {
7
85
  desktop: {
8
86
  width: "100%",
9
- height: "100%",
10
- maxHeight: "100%"
87
+ height: "100%"
11
88
  },
12
89
  mobile: {
13
90
  width: 414,
14
- height: "100%",
15
- maxHeight: 736
91
+ height: 746
16
92
  }
17
93
  };
18
94
  const DEFAULT_SIZE = "desktop";
19
- function Iframe(props) {
95
+ function Toolbar(props) {
20
96
  const {
21
- document: sanityDocument,
22
- options
97
+ displayUrl,
98
+ iframeSize,
99
+ setIframeSize,
100
+ reloading,
101
+ showDisplayUrl,
102
+ reloadButton,
103
+ handleReload
23
104
  } = 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
105
  const input = useRef(null);
36
- const iframe = useRef(null);
37
106
  const {
38
- displayed
39
- } = sanityDocument;
107
+ push: pushToast
108
+ } = useToast();
40
109
  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, {
110
+ return /* @__PURE__ */jsxs(Fragment, {
89
111
  children: [/* @__PURE__ */jsx("textarea", {
90
112
  style: {
91
113
  position: "absolute",
@@ -96,119 +118,401 @@ function Iframe(props) {
96
118
  value: displayUrl,
97
119
  readOnly: true,
98
120
  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, {
121
+ }), /* @__PURE__ */jsx(Card, {
122
+ padding: 2,
123
+ borderBottom: true,
124
+ children: /* @__PURE__ */jsxs(Flex, {
125
+ align: "center",
126
+ gap: 2,
127
+ children: [/* @__PURE__ */jsx(Flex, {
108
128
  align: "center",
109
- gap: 2,
110
- children: [/* @__PURE__ */jsx(Flex, {
111
- align: "center",
112
- gap: 1,
129
+ gap: 1,
130
+ children: /* @__PURE__ */jsx(Tooltip, {
131
+ content: /* @__PURE__ */jsx(Text, {
132
+ size: 1,
133
+ style: {
134
+ whiteSpace: "nowrap"
135
+ },
136
+ children: iframeSize === "mobile" ? "Exit mobile preview" : "Preview mobile viewport"
137
+ }),
138
+ padding: 2,
113
139
  children: /* @__PURE__ */jsx(Button, {
140
+ disabled: !displayUrl,
114
141
  fontSize: [1],
115
142
  padding: 2,
116
- tone: "primary",
117
143
  mode: iframeSize === "mobile" ? "default" : "ghost",
118
144
  icon: MobileDeviceIcon,
119
145
  onClick: () => setIframeSize(iframeSize === "mobile" ? "desktop" : "mobile")
120
146
  })
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, {
147
+ })
148
+ }), /* @__PURE__ */jsx(Box, {
149
+ flex: 1,
150
+ children: showDisplayUrl && displayUrl && /* @__PURE__ */jsx(DisplayUrl, {
151
+ displayUrl
152
+ })
153
+ }), /* @__PURE__ */jsxs(Flex, {
154
+ align: "center",
155
+ gap: 1,
156
+ children: [reloadButton ? /* @__PURE__ */jsx(Tooltip, {
157
+ content: /* @__PURE__ */jsx(Text, {
158
+ size: 1,
159
+ style: {
160
+ whiteSpace: "nowrap"
161
+ },
162
+ children: reloading ? "Reloading\u2026" : "Reload"
163
+ }),
164
+ padding: 2,
165
+ children: /* @__PURE__ */jsx(Button, {
166
+ disabled: !displayUrl,
167
+ mode: "bleed",
132
168
  fontSize: [1],
133
169
  padding: 2,
134
- icon: UndoIcon,
135
- title: "Reload",
170
+ icon: /* @__PURE__ */jsx(UndoIcon, {
171
+ style: {
172
+ transform: "rotate(90deg) scaleY(-1)"
173
+ }
174
+ }),
175
+ loading: reloading,
136
176
  "aria-label": "Reload",
137
177
  onClick: () => handleReload()
138
- }) : null, /* @__PURE__ */jsx(Button, {
178
+ })
179
+ }) : null, /* @__PURE__ */jsx(Tooltip, {
180
+ content: /* @__PURE__ */jsx(Text, {
181
+ size: 1,
182
+ style: {
183
+ whiteSpace: "nowrap"
184
+ },
185
+ children: "Copy URL"
186
+ }),
187
+ padding: 2,
188
+ children: /* @__PURE__ */jsx(Button, {
189
+ mode: "bleed",
190
+ disabled: !displayUrl,
139
191
  fontSize: [1],
140
- icon: CopyIcon,
192
+ icon: ClipboardIcon,
141
193
  padding: [2],
142
- title: "Copy",
143
- "aria-label": "Copy",
144
- onClick: () => handleCopy()
145
- }), /* @__PURE__ */jsx(Button, {
194
+ "aria-label": "Copy URL",
195
+ onClick: () => {
196
+ var _a;
197
+ if (!((_a = input == null ? void 0 : input.current) == null ? void 0 : _a.value)) return;
198
+ copy(input.current.value);
199
+ pushToast({
200
+ closable: true,
201
+ status: "success",
202
+ title: "The URL is copied to the clipboard"
203
+ });
204
+ }
205
+ })
206
+ }), /* @__PURE__ */jsx(Tooltip, {
207
+ content: /* @__PURE__ */jsx(Text, {
208
+ size: 1,
209
+ style: {
210
+ whiteSpace: "nowrap"
211
+ },
212
+ children: "Open URL in a new tab"
213
+ }),
214
+ padding: 2,
215
+ children: /* @__PURE__ */jsx(Button, {
216
+ disabled: !displayUrl,
146
217
  fontSize: [1],
147
- icon: LeaveIcon,
148
- padding: [2],
218
+ icon: LaunchIcon,
219
+ mode: "ghost",
220
+ paddingY: [2],
149
221
  text: "Open",
150
- tone: "primary",
222
+ "aria-label": "Open URL in a new tab",
151
223
  onClick: () => window.open(displayUrl)
152
- })]
224
+ })
153
225
  })]
154
- })
155
- }), /* @__PURE__ */jsx(Card, {
226
+ })]
227
+ })
228
+ })]
229
+ });
230
+ }
231
+ const MotionFlex = motion(Flex);
232
+ function Iframe(props) {
233
+ var _a;
234
+ const [error, setError] = useState(null);
235
+ if (error) {
236
+ throw error;
237
+ }
238
+ const {
239
+ document: sanityDocument,
240
+ options
241
+ } = props;
242
+ const {
243
+ url,
244
+ urlSecretId,
245
+ defaultSize = DEFAULT_SIZE,
246
+ reload,
247
+ loader = "Loading\u2026",
248
+ attributes = {},
249
+ showDisplayUrl = true
250
+ } = options;
251
+ const [iframeSize, setIframeSize] = useState(((_a = sizes) == null ? void 0 : _a[defaultSize]) ? defaultSize : DEFAULT_SIZE);
252
+ const [workaroundEmptyDocument, setWorkaroundEmptyDocument] = useState(true);
253
+ useEffect(() => {
254
+ const timeout = setTimeout(() => setWorkaroundEmptyDocument(false), 1e3);
255
+ return () => clearTimeout(timeout);
256
+ }, []);
257
+ const prefersReducedMotion = usePrefersReducedMotion();
258
+ const [urlState, setUrlState] = useState(() => typeof url === "function" ? "" : url);
259
+ const [loading, setLoading] = useState(true);
260
+ const [reloading, setReloading] = useState(false);
261
+ const iframe = useRef(null);
262
+ const {
263
+ displayed
264
+ } = sanityDocument;
265
+ const handleReload = useCallback(() => {
266
+ if (!(iframe == null ? void 0 : iframe.current)) {
267
+ return;
268
+ }
269
+ iframe.current.src = iframe.current.src;
270
+ setReloading(true);
271
+ }, []);
272
+ const deferredRevision = useDeferredValue(displayed._rev);
273
+ const displayUrl = typeof urlState === "string" ? urlState : "";
274
+ return /* @__PURE__ */jsx(MotionConfig, {
275
+ transition: prefersReducedMotion ? {
276
+ duration: 0
277
+ } : void 0,
278
+ children: /* @__PURE__ */jsxs(Flex, {
279
+ direction: "column",
280
+ style: {
281
+ height: "100%"
282
+ },
283
+ children: [/* @__PURE__ */jsx(Toolbar, {
284
+ displayUrl,
285
+ iframeSize,
286
+ reloading,
287
+ setIframeSize,
288
+ showDisplayUrl,
289
+ reloadButton: !!(reload == null ? void 0 : reload.button),
290
+ handleReload
291
+ }), urlState === MissingSlug && !workaroundEmptyDocument ? /* @__PURE__ */jsx(MissingSlugScreen, {}) : /* @__PURE__ */jsx(Card, {
156
292
  tone: "transparent",
157
- padding: iframeSize === "mobile" ? 2 : 0,
158
293
  style: {
159
294
  height: "100%"
160
295
  },
296
+ children: /* @__PURE__ */jsx(Frame, {
297
+ ref: iframe,
298
+ loader,
299
+ loading,
300
+ reloading,
301
+ iframeSize,
302
+ setReloading,
303
+ setLoading,
304
+ displayUrl,
305
+ attributes
306
+ })
307
+ }), typeof url === "function" && /* @__PURE__ */jsx(AsyncUrl, {
308
+ url,
309
+ displayed,
310
+ urlSecretId,
311
+ setDisplayUrl: setUrlState,
312
+ setError
313
+ }, deferredRevision), displayUrl && ((reload == null ? void 0 : reload.revision) || (reload == null ? void 0 : reload.revision) === 0) && /* @__PURE__ */jsx(ReloadOnRevision, {
314
+ revision: reload.revision,
315
+ _rev: deferredRevision,
316
+ handleReload
317
+ })]
318
+ })
319
+ });
320
+ }
321
+ const Frame = forwardRef(function Frame2(props, iframe) {
322
+ const {
323
+ loader,
324
+ loading,
325
+ setLoading,
326
+ iframeSize,
327
+ attributes,
328
+ reloading,
329
+ displayUrl,
330
+ setReloading
331
+ } = props;
332
+ function handleIframeLoad() {
333
+ setLoading(false);
334
+ setReloading(false);
335
+ if (attributes.onLoad && typeof attributes.onLoad === "function") {
336
+ attributes.onLoad();
337
+ }
338
+ }
339
+ return /* @__PURE__ */jsxs(Flex, {
340
+ align: "center",
341
+ justify: "center",
342
+ style: {
343
+ height: "100%",
344
+ position: "relative"
345
+ },
346
+ children: [/* @__PURE__ */jsx(AnimatePresence, {
347
+ children: loader && loading && /* @__PURE__ */jsx(MotionFlex, {
348
+ initial: "initial",
349
+ animate: "animate",
350
+ exit: "exit",
351
+ variants: spinnerVariants,
352
+ justify: "center",
353
+ align: "center",
354
+ style: {
355
+ inset: "0",
356
+ position: "absolute"
357
+ },
161
358
  children: /* @__PURE__ */jsxs(Flex, {
162
- align: "center",
163
- justify: "center",
164
359
  style: {
165
- height: "100%",
166
- position: "relative"
360
+ ...sizes[iframeSize]
167
361
  },
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
362
+ justify: "center",
363
+ align: "center",
364
+ direction: "column",
365
+ gap: 4,
366
+ children: [/* @__PURE__ */jsx(Spinner, {
367
+ muted: true
368
+ }), loader && typeof loader === "string" && /* @__PURE__ */jsx(Text, {
369
+ muted: true,
370
+ size: 1,
371
+ children: loader
207
372
  })]
208
373
  })
209
- })]
374
+ })
375
+ }), /* @__PURE__ */jsx(motion.iframe, {
376
+ ref: iframe,
377
+ title: "preview",
378
+ frameBorder: "0",
379
+ style: {
380
+ maxHeight: "100%"
381
+ },
382
+ src: displayUrl,
383
+ initial: ["background", iframeSize],
384
+ variants: iframeVariants,
385
+ animate: [loader && loading ? "background" : "active", reloading ? "reloading" : "idle", iframeSize],
386
+ ...attributes,
387
+ onLoad: handleIframeLoad
210
388
  })]
211
389
  });
390
+ });
391
+ const spinnerVariants = {
392
+ initial: {
393
+ opacity: 1
394
+ },
395
+ animate: {
396
+ opacity: [0, 0, 1]
397
+ },
398
+ exit: {
399
+ opacity: [1, 0, 0]
400
+ }
401
+ };
402
+ const iframeVariants = {
403
+ ...sizes,
404
+ desktop: {
405
+ ...sizes.desktop,
406
+ boxShadow: "0 0 0 0px var(--card-shadow-outline-color)"
407
+ },
408
+ mobile: {
409
+ ...sizes.mobile,
410
+ boxShadow: "0 0 0 1px var(--card-shadow-outline-color)"
411
+ },
412
+ background: {
413
+ opacity: 0,
414
+ scale: 1
415
+ },
416
+ idle: {
417
+ scale: 1
418
+ },
419
+ reloading: {
420
+ scale: [1, 1, 1, 0.98]
421
+ },
422
+ active: {
423
+ opacity: [0, 0, 1],
424
+ scale: 1
425
+ }
426
+ };
427
+ function ReloadOnRevision(props) {
428
+ const {
429
+ revision,
430
+ handleReload,
431
+ _rev
432
+ } = props;
433
+ const [initialRev] = useState(_rev);
434
+ useEffect(() => {
435
+ if (_rev !== initialRev) {
436
+ const timeout = setTimeout(handleReload, Number(revision === true ? 300 : revision));
437
+ return () => clearTimeout(timeout);
438
+ }
439
+ }, [_rev, revision, handleReload, initialRev]);
440
+ return null;
441
+ }
442
+ function AsyncUrl(props) {
443
+ const {
444
+ urlSecretId,
445
+ setDisplayUrl,
446
+ setError
447
+ } = props;
448
+ const [displayed] = useState(props.displayed);
449
+ const [url] = useState(() => props.url);
450
+ const [urlSecret, setUrlSecret] = useState(null);
451
+ useEffect(() => {
452
+ if (urlSecretId && !urlSecret) return;
453
+ const getUrl = async signal => {
454
+ const resolveUrl = await url(displayed, urlSecret, abort.signal);
455
+ if (!signal.aborted && resolveUrl) {
456
+ setDisplayUrl(resolveUrl);
457
+ }
458
+ };
459
+ const abort = new AbortController();
460
+ getUrl(abort.signal).catch(error => error.name !== "AbortError" && setError(error));
461
+ return () => abort.abort();
462
+ }, [displayed, setDisplayUrl, setError, url, urlSecret, urlSecretId]);
463
+ if (urlSecretId) {
464
+ return /* @__PURE__ */jsx(GetUrlSecret, {
465
+ urlSecretId,
466
+ urlSecret,
467
+ setUrlSecret,
468
+ setError
469
+ });
470
+ }
471
+ return null;
472
+ }
473
+ function MissingSlugScreen() {
474
+ return /* @__PURE__ */jsx(Card, {
475
+ height: "fill",
476
+ children: /* @__PURE__ */jsx(Flex, {
477
+ align: "center",
478
+ height: "fill",
479
+ justify: "center",
480
+ padding: 4,
481
+ sizing: "border",
482
+ children: /* @__PURE__ */jsx(Container, {
483
+ width: 0,
484
+ children: /* @__PURE__ */jsx(Card, {
485
+ padding: 4,
486
+ radius: 2,
487
+ shadow: 1,
488
+ tone: "caution",
489
+ children: /* @__PURE__ */jsxs(Flex, {
490
+ children: [/* @__PURE__ */jsx(Box, {
491
+ children: /* @__PURE__ */jsx(Text, {
492
+ size: 1,
493
+ children: /* @__PURE__ */jsx(WarningOutlineIcon, {})
494
+ })
495
+ }), /* @__PURE__ */jsxs(Stack, {
496
+ flex: 1,
497
+ marginLeft: 3,
498
+ space: 3,
499
+ children: [/* @__PURE__ */jsx(Text, {
500
+ as: "h1",
501
+ size: 1,
502
+ weight: "bold",
503
+ children: "Missing slug"
504
+ }), /* @__PURE__ */jsx(Text, {
505
+ as: "p",
506
+ muted: true,
507
+ size: 1,
508
+ children: "Add a slug to see the preview."
509
+ })]
510
+ })]
511
+ })
512
+ })
513
+ })
514
+ })
515
+ });
212
516
  }
213
- export { Iframe as default };
517
+ export { Iframe };
214
518
  //# sourceMappingURL=index.js.map