sanity-plugin-iframe-pane 3.1.4 → 3.1.6
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/lib/index.cjs +15 -5
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +15 -5
- package/lib/index.js.map +1 -1
- package/package.json +22 -24
- package/src/DisplayUrl.tsx +1 -1
- package/src/Iframe.tsx +8 -8
- package/src/Toolbar.tsx +22 -9
- package/lib/index.cjs.js +0 -4
package/lib/index.cjs
CHANGED
|
@@ -35,6 +35,7 @@ function Toolbar(props) {
|
|
|
35
35
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { align: "center", gap: 1, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
36
36
|
ui.Tooltip,
|
|
37
37
|
{
|
|
38
|
+
animate: !0,
|
|
38
39
|
content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: { whiteSpace: "nowrap" }, children: iframeSize === "mobile" ? "Exit mobile preview" : "Preview mobile viewport" }),
|
|
39
40
|
padding: 2,
|
|
40
41
|
placement: "bottom-start",
|
|
@@ -56,6 +57,7 @@ function Toolbar(props) {
|
|
|
56
57
|
reloadButton ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
57
58
|
ui.Tooltip,
|
|
58
59
|
{
|
|
60
|
+
animate: !0,
|
|
59
61
|
content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: { whiteSpace: "nowrap" }, children: reloading ? "Reloading\u2026" : "Reload" }),
|
|
60
62
|
padding: 2,
|
|
61
63
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -76,6 +78,7 @@ function Toolbar(props) {
|
|
|
76
78
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
77
79
|
ui.Tooltip,
|
|
78
80
|
{
|
|
81
|
+
animate: !0,
|
|
79
82
|
content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: { whiteSpace: "nowrap" }, children: "Copy URL" }),
|
|
80
83
|
padding: 2,
|
|
81
84
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -89,11 +92,17 @@ function Toolbar(props) {
|
|
|
89
92
|
"aria-label": "Copy URL",
|
|
90
93
|
onClick: () => {
|
|
91
94
|
var _a;
|
|
92
|
-
(_a = input == null ? void 0 : input.current) != null && _a.value &&
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
(_a = input == null ? void 0 : input.current) != null && _a.value && copy(input.current.value).then((copied) => {
|
|
96
|
+
pushToast(copied ? {
|
|
97
|
+
closable: !0,
|
|
98
|
+
status: "success",
|
|
99
|
+
title: "The URL is copied to the clipboard"
|
|
100
|
+
} : {
|
|
101
|
+
closable: !0,
|
|
102
|
+
status: "error",
|
|
103
|
+
title: "Failed to copy the URL to the clipboard"
|
|
104
|
+
});
|
|
105
|
+
});
|
|
97
106
|
}
|
|
98
107
|
}
|
|
99
108
|
)
|
|
@@ -102,6 +111,7 @@ function Toolbar(props) {
|
|
|
102
111
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
103
112
|
ui.Tooltip,
|
|
104
113
|
{
|
|
114
|
+
animate: !0,
|
|
105
115
|
content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: { whiteSpace: "nowrap" }, children: "Open URL in a new tab" }),
|
|
106
116
|
padding: 2,
|
|
107
117
|
placement: "bottom-end",
|
package/lib/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/DisplayUrl.tsx","../src/Toolbar.tsx","../src/Iframe.tsx"],"sourcesContent":["import {getRedirectTo} from '@sanity/preview-url-secret/get-redirect-to'\nimport {Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\n\nexport function DisplayUrl(props: {url: URL}) {\n const truncatedUrl = useMemo(() => {\n const url = getRedirectTo(props.url)\n return `${url.origin === location.origin ? '' : url.origin}${url.pathname}${url.search}`\n }, [props.url])\n\n return (\n <Text size={0} textOverflow=\"ellipsis\">\n {truncatedUrl}\n </Text>\n )\n}\n","import {CopyIcon, LaunchIcon, MobileDeviceIcon, RefreshIcon} from '@sanity/icons'\nimport {Box, Button, Card, Flex, Text, Tooltip, useToast} from '@sanity/ui'\nimport React, {useRef} from 'react'\nimport {useCopyToClipboard} from 'usehooks-ts'\n\nimport {DisplayUrl} from './DisplayUrl'\nimport {IframeSizeKey, type SizeProps} from './types'\n\nexport const sizes: SizeProps = {\n desktop: {\n width: '100%',\n height: '100%',\n },\n mobile: {\n width: 414,\n height: 746,\n },\n}\n\nexport const DEFAULT_SIZE = `desktop`\n\nexport interface ToolbarProps {\n url: URL | Error | undefined\n iframeSize: IframeSizeKey\n setIframeSize: (size: IframeSizeKey) => void\n showUrl: boolean\n reloading: boolean\n reloadButton: boolean\n handleReload: () => void\n}\nexport function Toolbar(props: ToolbarProps) {\n const {url, iframeSize, setIframeSize, reloading, showUrl, reloadButton, handleReload} = props\n const validUrl = url instanceof URL\n\n const input = useRef<HTMLTextAreaElement>(null)\n const {push: pushToast} = useToast()\n const [, copy] = useCopyToClipboard()\n\n return (\n <>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={validUrl ? url.toString() : ''}\n readOnly\n tabIndex={-1}\n />\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {iframeSize === 'mobile' ? 'Exit mobile preview' : 'Preview mobile viewport'}\n </Text>\n }\n padding={2}\n placement=\"bottom-start\"\n >\n <Button\n disabled={!validUrl}\n fontSize={[1]}\n padding={2}\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Tooltip>\n </Flex>\n <Box flex={1}>{showUrl && validUrl && <DisplayUrl url={url} />}</Box>\n <Flex align=\"center\" gap={1}>\n {reloadButton ? (\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {reloading ? 'Reloading…' : 'Reload'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!validUrl}\n mode=\"bleed\"\n fontSize={[1]}\n padding={2}\n icon={RefreshIcon}\n loading={reloading}\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n </Tooltip>\n ) : null}\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Copy URL\n </Text>\n }\n padding={2}\n >\n <Button\n mode=\"bleed\"\n disabled={!validUrl}\n fontSize={[1]}\n icon={CopyIcon}\n padding={[2]}\n aria-label=\"Copy URL\"\n onClick={() => {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n pushToast({\n closable: true,\n status: 'success',\n title: 'The URL is copied to the clipboard',\n })\n }}\n />\n </Tooltip>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Open URL in a new tab\n </Text>\n }\n padding={2}\n placement=\"bottom-end\"\n >\n <Button\n disabled={!validUrl}\n fontSize={[1]}\n icon={LaunchIcon}\n mode=\"ghost\"\n paddingY={[2]}\n text=\"Open\"\n aria-label=\"Open URL in a new tab\"\n onClick={validUrl ? () => window.open(url.toString()) : undefined}\n />\n </Tooltip>\n </Flex>\n </Flex>\n </Card>\n </>\n )\n}\n","import {WarningOutlineIcon} from '@sanity/icons'\nimport {createPreviewSecret} from '@sanity/preview-url-secret/create-secret'\nimport {definePreviewUrl} from '@sanity/preview-url-secret/define-preview-url'\nimport {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {AnimatePresence, motion, MotionConfig} from 'framer-motion'\nimport React, {\n forwardRef,\n memo,\n Suspense,\n useCallback,\n useEffect,\n useRef,\n useState,\n useTransition,\n} from 'react'\nimport {HTMLAttributeReferrerPolicy} from 'react'\nimport {SanityDocument, useClient, useCurrentUser} from 'sanity'\nimport {suspend} from 'suspend-react'\n\nimport {DEFAULT_SIZE, sizes, Toolbar} from './Toolbar'\nimport {IframeSizeKey} from './types'\n\nexport type UrlResolver = (\n document: SanityDocument | null,\n) => string | Error | undefined | Promise<string | Error | undefined>\n\nexport type {IframeSizeKey}\n\nexport interface IframeOptions {\n /**\n * If you have multiple iframe instances side-by-side you need to give each a unique key.\n */\n key?: string\n url:\n | string\n | UrlResolver\n | {\n /**\n * The URL origin of where the preview is hosted, for example `https://example.com`.\n * If it's an embedded Studio then set it to `'same-origin'`.\n */\n origin: 'same-origin' | string\n /**\n * The route to redirect to after enabling Draft Mode.\n * If you don't have enough data to build the URL, return an `Error` instance to show an error message.\n * @example `return new Error('Missing slug')`\n * To prolong the loading state, return `undefined`\n */\n preview: string | UrlResolver\n /**\n * The route that enables Draft Mode\n * @example '/api/draft'\n */\n draftMode: string\n }\n defaultSize?: IframeSizeKey\n showDisplayUrl?: boolean\n reload?: {\n button?: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nconst MotionFlex = motion(Flex)\n\nexport interface IframeProps {\n document: {\n displayed: SanityDocument\n draft: SanityDocument | null\n published: SanityDocument | null\n }\n options: IframeOptions\n}\n\nexport function Iframe(props: IframeProps) {\n const {document, options} = props\n const draft = document.draft || document.published || document.displayed\n\n const {defaultSize = DEFAULT_SIZE, reload, attributes, showDisplayUrl = true, key} = options\n\n const urlRef = useRef(options.url)\n const [draftSnapshot, setDraftSnapshot] = useState(() => ({key, draft}))\n useEffect(() => {\n urlRef.current = options.url\n }, [options.url])\n useEffect(() => {\n if (JSON.stringify({key, draft}) !== JSON.stringify(draftSnapshot)) {\n startTransition(() => setDraftSnapshot({key, draft}))\n }\n }, [draft, draftSnapshot, key])\n const currentUser = useCurrentUser()\n const client = useClient({apiVersion: '2023-10-16'})\n const [expiresAt, setExpiresAt] = useState<number | undefined>()\n const previewSecretRef = useRef<string | undefined>()\n const [isResolvingUrl, startTransition] = useTransition()\n const url = useCallback(\n // eslint-disable-next-line @typescript-eslint/no-shadow\n async (draft: SanityDocument | null) => {\n if (typeof location === 'undefined') {\n return undefined\n }\n const urlProp = urlRef.current\n if (typeof urlProp === 'string') {\n return new URL(urlProp, location.origin)\n }\n if (typeof urlProp === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const url = await urlProp(draft)\n return typeof url === 'string' ? new URL(url, location.origin) : url\n }\n if (typeof urlProp === 'object') {\n const preview =\n typeof urlProp.preview === 'function' ? await urlProp.preview(draft) : urlProp.preview\n if (typeof preview !== 'string') {\n return preview\n }\n if (!previewSecretRef.current) {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const {secret, expiresAt} = await createPreviewSecret(\n client,\n 'sanity-plugin-iframe-pane',\n location.href,\n currentUser?.id,\n )\n previewSecretRef.current = secret\n startTransition(() => setExpiresAt(expiresAt.getTime()))\n }\n\n const resolvePreviewUrl = definePreviewUrl({\n origin: urlProp.origin === 'same-origin' ? location.origin : urlProp.origin,\n preview,\n draftMode: {\n enable: urlProp.draftMode,\n },\n })\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const url = await resolvePreviewUrl({\n client,\n previewUrlSecret: previewSecretRef.current,\n previewSearchParam: null,\n })\n return new URL(url, location.origin)\n }\n return undefined\n },\n [client, currentUser?.id],\n )\n useEffect(() => {\n if (expiresAt) {\n const timeout = setTimeout(\n () => {\n startTransition(() => setExpiresAt(undefined))\n previewSecretRef.current = undefined\n },\n Math.max(0, expiresAt - Date.now()),\n )\n return () => clearTimeout(timeout)\n }\n return undefined\n }, [expiresAt])\n\n return (\n <Suspense fallback={<Loading iframeSize=\"desktop\" />}>\n <IframeInner\n key={draftSnapshot.key}\n _key={draftSnapshot.key}\n draftSnapshot={draftSnapshot.draft}\n url={url}\n isResolvingUrl={isResolvingUrl}\n attributes={attributes}\n defaultSize={defaultSize}\n reload={reload}\n showDisplayUrl={showDisplayUrl}\n userId={currentUser?.id}\n />\n </Suspense>\n )\n}\n\nexport interface IframeInnerProps extends Omit<IframeOptions, 'url'> {\n url: (draftSnapshot: SanityDocument | null) => Promise<URL | Error | undefined>\n isResolvingUrl: boolean\n draftSnapshot: SanityDocument | null\n userId?: string\n expiresAt?: number\n _key?: string\n}\nconst IframeInner = memo(function IframeInner(props: IframeInnerProps) {\n const {\n isResolvingUrl,\n defaultSize = DEFAULT_SIZE,\n reload,\n attributes = {},\n showDisplayUrl = true,\n draftSnapshot,\n userId,\n expiresAt,\n _key,\n } = props\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n\n const prefersReducedMotion = usePrefersReducedMotion()\n\n const url = suspend(\n () => props.url(draftSnapshot),\n [\n // Cache based on a few specific conditions\n 'sanity-plugin-iframe-pane',\n draftSnapshot,\n userId,\n expiresAt,\n _key,\n resolveUUID,\n ],\n )\n\n const [loading, setLoading] = useState(true)\n const [_reloading, setReloading] = useState(false)\n const reloading = _reloading || isResolvingUrl\n\n const iframe = useRef<HTMLIFrameElement>(null)\n\n const handleReload = useCallback(() => {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issues\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setReloading(true)\n }, [])\n\n return (\n <MotionConfig transition={prefersReducedMotion ? {duration: 0} : undefined}>\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Toolbar\n url={url}\n iframeSize={iframeSize}\n reloading={reloading}\n setIframeSize={setIframeSize}\n showUrl={showDisplayUrl}\n reloadButton={!!reload?.button}\n handleReload={handleReload}\n />\n {url instanceof Error ? (\n <ErrorCard error={url} />\n ) : (\n <Card tone=\"transparent\" style={{height: `100%`}}>\n <Frame\n ref={iframe}\n loading={loading}\n reloading={reloading}\n iframeSize={iframeSize}\n setReloading={setReloading}\n setLoading={setLoading}\n url={url}\n attributes={attributes}\n />\n </Card>\n )}\n </Flex>\n </MotionConfig>\n )\n})\n\ninterface FrameProps extends Required<Pick<IframeOptions, 'attributes'>> {\n loading: boolean\n reloading: boolean\n setLoading: (loading: boolean) => void\n setReloading: (reloading: boolean) => void\n iframeSize: IframeSizeKey\n url: URL | undefined\n}\nconst Frame = forwardRef(function Frame(\n props: FrameProps,\n iframe: React.ForwardedRef<HTMLIFrameElement>,\n) {\n const {loading, setLoading, iframeSize, attributes, reloading, url, setReloading} = props\n\n function handleIframeLoad() {\n setLoading(false)\n setReloading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n <AnimatePresence>\n {!url ||\n (loading && (\n <MotionFlex\n initial=\"initial\"\n animate=\"animate\"\n exit=\"exit\"\n variants={spinnerVariants}\n justify=\"center\"\n align=\"center\"\n style={{inset: `0`, position: `absolute`}}\n >\n <Loading iframeSize={iframeSize} />\n </MotionFlex>\n ))}\n </AnimatePresence>\n {url && (\n <motion.iframe\n ref={iframe}\n title=\"preview\"\n frameBorder=\"0\"\n style={{maxHeight: '100%'}}\n src={url.toString()}\n initial={['background', iframeSize]}\n variants={iframeVariants}\n animate={[\n loading ? 'background' : 'active',\n reloading ? 'reloading' : 'idle',\n iframeSize,\n ]}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n )}\n </Flex>\n )\n})\n\nconst spinnerVariants = {\n initial: {opacity: 1},\n animate: {opacity: [0, 0, 1]},\n exit: {opacity: [1, 0, 0]},\n}\n\nconst iframeVariants = {\n ...sizes,\n desktop: {\n ...sizes.desktop,\n boxShadow: '0 0 0 0px var(--card-shadow-outline-color)',\n },\n mobile: {\n ...sizes.mobile,\n boxShadow: '0 0 0 1px var(--card-shadow-outline-color)',\n },\n background: {\n opacity: 0,\n scale: 1,\n },\n idle: {\n scale: 1,\n },\n reloading: {\n scale: [1, 1, 1, 0.98],\n },\n active: {\n opacity: [0, 0, 1],\n scale: 1,\n },\n}\n\nfunction Loading({iframeSize}: {iframeSize: IframeSizeKey}) {\n return (\n <Flex style={{...sizes[iframeSize]}} justify=\"center\" align=\"center\" direction=\"column\" gap={4}>\n <Spinner muted />\n <Text muted size={1}>\n Loading…\n </Text>\n </Flex>\n )\n}\n\nexport function ErrorCard({error}: {error: Error}) {\n return (\n <Card height=\"fill\">\n <Flex align=\"center\" height=\"fill\" justify=\"center\" padding={4} sizing=\"border\">\n <Container width={0}>\n <Card padding={4} radius={2} shadow={1} tone=\"caution\">\n <Flex>\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack flex={1} marginLeft={3} space={3}>\n <Text as=\"h1\" size={1} weight=\"bold\">\n {error.name}\n </Text>\n <Text as=\"p\" muted size={1}>\n {error.message}\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Container>\n </Flex>\n </Card>\n )\n}\n\n// https://github.com/pmndrs/suspend-react?tab=readme-ov-file#making-cache-keys-unique\nconst resolveUUID = Symbol()\n"],"names":["useMemo","getRedirectTo","Text","useRef","useToast","useCopyToClipboard","jsxs","Fragment","jsx","Card","Flex","Tooltip","Button","MobileDeviceIcon","Box","RefreshIcon","CopyIcon","LaunchIcon","motion","useState","useEffect","useCurrentUser","useClient","useTransition","useCallback","draft","url","expiresAt","createPreviewSecret","definePreviewUrl","Suspense","memo","usePrefersReducedMotion","suspend","MotionConfig","forwardRef","AnimatePresence","Spinner","Container","WarningOutlineIcon","Stack"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/DisplayUrl.tsx","../src/Toolbar.tsx","../src/Iframe.tsx"],"sourcesContent":["import {getRedirectTo} from '@sanity/preview-url-secret/get-redirect-to'\nimport {Text} from '@sanity/ui'\nimport {useMemo} from 'react'\n\nexport function DisplayUrl(props: {url: URL}) {\n const truncatedUrl = useMemo(() => {\n const url = getRedirectTo(props.url)\n return `${url.origin === location.origin ? '' : url.origin}${url.pathname}${url.search}`\n }, [props.url])\n\n return (\n <Text size={0} textOverflow=\"ellipsis\">\n {truncatedUrl}\n </Text>\n )\n}\n","import {CopyIcon, LaunchIcon, MobileDeviceIcon, RefreshIcon} from '@sanity/icons'\nimport {Box, Button, Card, Flex, Text, Tooltip, useToast} from '@sanity/ui'\nimport {useRef} from 'react'\nimport {useCopyToClipboard} from 'usehooks-ts'\n\nimport {DisplayUrl} from './DisplayUrl'\nimport type {IframeSizeKey, SizeProps} from './types'\n\nexport const sizes: SizeProps = {\n desktop: {\n width: '100%',\n height: '100%',\n },\n mobile: {\n width: 414,\n height: 746,\n },\n}\n\nexport const DEFAULT_SIZE = 'desktop'\n\nexport interface ToolbarProps {\n url: URL | Error | undefined\n iframeSize: IframeSizeKey\n setIframeSize: (size: IframeSizeKey) => void\n showUrl: boolean\n reloading: boolean\n reloadButton: boolean\n handleReload: () => void\n}\nexport function Toolbar(props: ToolbarProps) {\n const {url, iframeSize, setIframeSize, reloading, showUrl, reloadButton, handleReload} = props\n const validUrl = url instanceof URL\n\n const input = useRef<HTMLTextAreaElement>(null)\n const {push: pushToast} = useToast()\n const [, copy] = useCopyToClipboard()\n\n return (\n <>\n <textarea\n style={{position: 'absolute', pointerEvents: 'none', opacity: 0}}\n ref={input}\n value={validUrl ? url.toString() : ''}\n readOnly\n tabIndex={-1}\n />\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Tooltip\n animate\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {iframeSize === 'mobile' ? 'Exit mobile preview' : 'Preview mobile viewport'}\n </Text>\n }\n padding={2}\n placement=\"bottom-start\"\n >\n <Button\n disabled={!validUrl}\n fontSize={[1]}\n padding={2}\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Tooltip>\n </Flex>\n <Box flex={1}>{showUrl && validUrl && <DisplayUrl url={url} />}</Box>\n <Flex align=\"center\" gap={1}>\n {reloadButton ? (\n <Tooltip\n animate\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {reloading ? 'Reloading…' : 'Reload'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!validUrl}\n mode=\"bleed\"\n fontSize={[1]}\n padding={2}\n icon={RefreshIcon}\n loading={reloading}\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n </Tooltip>\n ) : null}\n <Tooltip\n animate\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Copy URL\n </Text>\n }\n padding={2}\n >\n <Button\n mode=\"bleed\"\n disabled={!validUrl}\n fontSize={[1]}\n icon={CopyIcon}\n padding={[2]}\n aria-label=\"Copy URL\"\n onClick={() => {\n if (!input?.current?.value) return\n\n copy(input.current.value).then((copied) => {\n if (copied) {\n pushToast({\n closable: true,\n status: 'success',\n title: 'The URL is copied to the clipboard',\n })\n } else {\n pushToast({\n closable: true,\n status: 'error',\n title: 'Failed to copy the URL to the clipboard',\n })\n }\n })\n }}\n />\n </Tooltip>\n <Tooltip\n animate\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Open URL in a new tab\n </Text>\n }\n padding={2}\n placement=\"bottom-end\"\n >\n <Button\n disabled={!validUrl}\n fontSize={[1]}\n icon={LaunchIcon}\n mode=\"ghost\"\n paddingY={[2]}\n text=\"Open\"\n aria-label=\"Open URL in a new tab\"\n onClick={validUrl ? () => window.open(url.toString()) : undefined}\n />\n </Tooltip>\n </Flex>\n </Flex>\n </Card>\n </>\n )\n}\n","import {WarningOutlineIcon} from '@sanity/icons'\nimport {createPreviewSecret} from '@sanity/preview-url-secret/create-secret'\nimport {definePreviewUrl} from '@sanity/preview-url-secret/define-preview-url'\nimport {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {AnimatePresence, motion, MotionConfig} from 'framer-motion'\nimport type {HTMLAttributeReferrerPolicy} from 'react'\nimport {\n forwardRef,\n memo,\n Suspense,\n useCallback,\n useEffect,\n useRef,\n useState,\n useTransition,\n} from 'react'\nimport {type SanityDocument, useClient, useCurrentUser} from 'sanity'\nimport {suspend} from 'suspend-react'\n\nimport {DEFAULT_SIZE, sizes, Toolbar} from './Toolbar'\nimport type {IframeSizeKey} from './types'\n\nexport type UrlResolver = (\n document: SanityDocument | null,\n) => string | Error | undefined | Promise<string | Error | undefined>\n\nexport type {IframeSizeKey}\n\nexport interface IframeOptions {\n /**\n * If you have multiple iframe instances side-by-side you need to give each a unique key.\n */\n key?: string\n url:\n | string\n | UrlResolver\n | {\n /**\n * The URL origin of where the preview is hosted, for example `https://example.com`.\n * If it's an embedded Studio then set it to `'same-origin'`.\n */\n origin: 'same-origin' | string\n /**\n * The route to redirect to after enabling Draft Mode.\n * If you don't have enough data to build the URL, return an `Error` instance to show an error message.\n * @example `return new Error('Missing slug')`\n * To prolong the loading state, return `undefined`\n */\n preview: string | UrlResolver\n /**\n * The route that enables Draft Mode\n * @example '/api/draft'\n */\n draftMode: string\n }\n defaultSize?: IframeSizeKey\n showDisplayUrl?: boolean\n reload?: {\n button?: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nconst MotionFlex = motion(Flex)\n\nexport interface IframeProps {\n document: {\n displayed: SanityDocument\n draft: SanityDocument | null\n published: SanityDocument | null\n }\n options: IframeOptions\n}\n\nexport function Iframe(props: IframeProps) {\n const {document, options} = props\n const draft = document.draft || document.published || document.displayed\n\n const {defaultSize = DEFAULT_SIZE, reload, attributes, showDisplayUrl = true, key} = options\n\n const urlRef = useRef(options.url)\n const [draftSnapshot, setDraftSnapshot] = useState(() => ({key, draft}))\n useEffect(() => {\n urlRef.current = options.url\n }, [options.url])\n useEffect(() => {\n if (JSON.stringify({key, draft}) !== JSON.stringify(draftSnapshot)) {\n startTransition(() => setDraftSnapshot({key, draft}))\n }\n }, [draft, draftSnapshot, key])\n const currentUser = useCurrentUser()\n const client = useClient({apiVersion: '2023-10-16'})\n const [expiresAt, setExpiresAt] = useState<number | undefined>()\n const previewSecretRef = useRef<string | undefined>()\n const [isResolvingUrl, startTransition] = useTransition()\n const url = useCallback(\n // eslint-disable-next-line @typescript-eslint/no-shadow\n async (draft: SanityDocument | null) => {\n if (typeof location === 'undefined') {\n return undefined\n }\n const urlProp = urlRef.current\n if (typeof urlProp === 'string') {\n return new URL(urlProp, location.origin)\n }\n if (typeof urlProp === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const url = await urlProp(draft)\n return typeof url === 'string' ? new URL(url, location.origin) : url\n }\n if (typeof urlProp === 'object') {\n const preview =\n typeof urlProp.preview === 'function' ? await urlProp.preview(draft) : urlProp.preview\n if (typeof preview !== 'string') {\n return preview\n }\n if (!previewSecretRef.current) {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const {secret, expiresAt} = await createPreviewSecret(\n client,\n 'sanity-plugin-iframe-pane',\n location.href,\n currentUser?.id,\n )\n previewSecretRef.current = secret\n startTransition(() => setExpiresAt(expiresAt.getTime()))\n }\n\n const resolvePreviewUrl = definePreviewUrl({\n origin: urlProp.origin === 'same-origin' ? location.origin : urlProp.origin,\n preview,\n draftMode: {\n enable: urlProp.draftMode,\n },\n })\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const url = await resolvePreviewUrl({\n client,\n previewUrlSecret: previewSecretRef.current,\n previewSearchParam: null,\n })\n return new URL(url, location.origin)\n }\n return undefined\n },\n [client, currentUser?.id],\n )\n useEffect(() => {\n if (expiresAt) {\n const timeout = setTimeout(\n () => {\n startTransition(() => setExpiresAt(undefined))\n previewSecretRef.current = undefined\n },\n Math.max(0, expiresAt - Date.now()),\n )\n return () => clearTimeout(timeout)\n }\n return undefined\n }, [expiresAt])\n\n return (\n <Suspense fallback={<Loading iframeSize=\"desktop\" />}>\n <IframeInner\n key={draftSnapshot.key}\n _key={draftSnapshot.key}\n draftSnapshot={draftSnapshot.draft}\n url={url}\n isResolvingUrl={isResolvingUrl}\n attributes={attributes}\n defaultSize={defaultSize}\n reload={reload}\n showDisplayUrl={showDisplayUrl}\n userId={currentUser?.id}\n />\n </Suspense>\n )\n}\n\nexport interface IframeInnerProps extends Omit<IframeOptions, 'url'> {\n url: (draftSnapshot: SanityDocument | null) => Promise<URL | Error | undefined>\n isResolvingUrl: boolean\n draftSnapshot: SanityDocument | null\n userId?: string\n expiresAt?: number\n _key?: string\n}\nconst IframeInner = memo(function IframeInner(props: IframeInnerProps) {\n const {\n isResolvingUrl,\n defaultSize = DEFAULT_SIZE,\n reload,\n attributes = {},\n showDisplayUrl = true,\n draftSnapshot,\n userId,\n expiresAt,\n _key,\n } = props\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n\n const prefersReducedMotion = usePrefersReducedMotion()\n\n const url = suspend(\n () => props.url(draftSnapshot),\n [\n // Cache based on a few specific conditions\n 'sanity-plugin-iframe-pane',\n draftSnapshot,\n userId,\n expiresAt,\n _key,\n resolveUUID,\n ],\n )\n\n const [loading, setLoading] = useState(true)\n const [_reloading, setReloading] = useState(false)\n const reloading = _reloading || isResolvingUrl\n\n const iframe = useRef<HTMLIFrameElement>(null)\n\n const handleReload = useCallback(() => {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issues\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setReloading(true)\n }, [])\n\n return (\n <MotionConfig transition={prefersReducedMotion ? {duration: 0} : undefined}>\n <Flex direction=\"column\" style={{height: '100%'}}>\n <Toolbar\n url={url}\n iframeSize={iframeSize}\n reloading={reloading}\n setIframeSize={setIframeSize}\n showUrl={showDisplayUrl}\n reloadButton={!!reload?.button}\n handleReload={handleReload}\n />\n {url instanceof Error ? (\n <ErrorCard error={url} />\n ) : (\n <Card tone=\"transparent\" style={{height: '100%'}}>\n <Frame\n ref={iframe}\n loading={loading}\n reloading={reloading}\n iframeSize={iframeSize}\n setReloading={setReloading}\n setLoading={setLoading}\n url={url}\n attributes={attributes}\n />\n </Card>\n )}\n </Flex>\n </MotionConfig>\n )\n})\n\ninterface FrameProps extends Required<Pick<IframeOptions, 'attributes'>> {\n loading: boolean\n reloading: boolean\n setLoading: (loading: boolean) => void\n setReloading: (reloading: boolean) => void\n iframeSize: IframeSizeKey\n url: URL | undefined\n}\nconst Frame = forwardRef(function Frame(\n props: FrameProps,\n iframe: React.ForwardedRef<HTMLIFrameElement>,\n) {\n const {loading, setLoading, iframeSize, attributes, reloading, url, setReloading} = props\n\n function handleIframeLoad() {\n setLoading(false)\n setReloading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" style={{height: '100%', position: 'relative'}}>\n <AnimatePresence>\n {!url ||\n (loading && (\n <MotionFlex\n initial=\"initial\"\n animate=\"animate\"\n exit=\"exit\"\n variants={spinnerVariants}\n justify=\"center\"\n align=\"center\"\n style={{inset: '0', position: 'absolute'}}\n >\n <Loading iframeSize={iframeSize} />\n </MotionFlex>\n ))}\n </AnimatePresence>\n {url && (\n <motion.iframe\n ref={iframe}\n title=\"preview\"\n frameBorder=\"0\"\n style={{maxHeight: '100%'}}\n src={url.toString()}\n initial={['background', iframeSize]}\n variants={iframeVariants}\n animate={[\n loading ? 'background' : 'active',\n reloading ? 'reloading' : 'idle',\n iframeSize,\n ]}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n )}\n </Flex>\n )\n})\n\nconst spinnerVariants = {\n initial: {opacity: 1},\n animate: {opacity: [0, 0, 1]},\n exit: {opacity: [1, 0, 0]},\n}\n\nconst iframeVariants = {\n ...sizes,\n desktop: {\n ...sizes.desktop,\n boxShadow: '0 0 0 0px var(--card-shadow-outline-color)',\n },\n mobile: {\n ...sizes.mobile,\n boxShadow: '0 0 0 1px var(--card-shadow-outline-color)',\n },\n background: {\n opacity: 0,\n scale: 1,\n },\n idle: {\n scale: 1,\n },\n reloading: {\n scale: [1, 1, 1, 0.98],\n },\n active: {\n opacity: [0, 0, 1],\n scale: 1,\n },\n}\n\nfunction Loading({iframeSize}: {iframeSize: IframeSizeKey}) {\n return (\n <Flex style={{...sizes[iframeSize]}} justify=\"center\" align=\"center\" direction=\"column\" gap={4}>\n <Spinner muted />\n <Text muted size={1}>\n Loading…\n </Text>\n </Flex>\n )\n}\n\nexport function ErrorCard({error}: {error: Error}) {\n return (\n <Card height=\"fill\">\n <Flex align=\"center\" height=\"fill\" justify=\"center\" padding={4} sizing=\"border\">\n <Container width={0}>\n <Card padding={4} radius={2} shadow={1} tone=\"caution\">\n <Flex>\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack flex={1} marginLeft={3} space={3}>\n <Text as=\"h1\" size={1} weight=\"bold\">\n {error.name}\n </Text>\n <Text as=\"p\" muted size={1}>\n {error.message}\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Container>\n </Flex>\n </Card>\n )\n}\n\n// https://github.com/pmndrs/suspend-react?tab=readme-ov-file#making-cache-keys-unique\nconst resolveUUID = Symbol()\n"],"names":["useMemo","getRedirectTo","Text","useRef","useToast","useCopyToClipboard","jsxs","Fragment","jsx","Card","Flex","Tooltip","Button","MobileDeviceIcon","Box","RefreshIcon","CopyIcon","LaunchIcon","motion","useState","useEffect","useCurrentUser","useClient","useTransition","useCallback","draft","url","expiresAt","createPreviewSecret","definePreviewUrl","Suspense","memo","usePrefersReducedMotion","suspend","MotionConfig","forwardRef","AnimatePresence","Spinner","Container","WarningOutlineIcon","Stack"],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -43,6 +43,7 @@ function Toolbar(props) {
|
|
|
43
43
|
/* @__PURE__ */ jsx(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ jsx(
|
|
44
44
|
Tooltip,
|
|
45
45
|
{
|
|
46
|
+
animate: !0,
|
|
46
47
|
content: /* @__PURE__ */ jsx(Text, { size: 1, style: { whiteSpace: "nowrap" }, children: iframeSize === "mobile" ? "Exit mobile preview" : "Preview mobile viewport" }),
|
|
47
48
|
padding: 2,
|
|
48
49
|
placement: "bottom-start",
|
|
@@ -64,6 +65,7 @@ function Toolbar(props) {
|
|
|
64
65
|
reloadButton ? /* @__PURE__ */ jsx(
|
|
65
66
|
Tooltip,
|
|
66
67
|
{
|
|
68
|
+
animate: !0,
|
|
67
69
|
content: /* @__PURE__ */ jsx(Text, { size: 1, style: { whiteSpace: "nowrap" }, children: reloading ? "Reloading\u2026" : "Reload" }),
|
|
68
70
|
padding: 2,
|
|
69
71
|
children: /* @__PURE__ */ jsx(
|
|
@@ -84,6 +86,7 @@ function Toolbar(props) {
|
|
|
84
86
|
/* @__PURE__ */ jsx(
|
|
85
87
|
Tooltip,
|
|
86
88
|
{
|
|
89
|
+
animate: !0,
|
|
87
90
|
content: /* @__PURE__ */ jsx(Text, { size: 1, style: { whiteSpace: "nowrap" }, children: "Copy URL" }),
|
|
88
91
|
padding: 2,
|
|
89
92
|
children: /* @__PURE__ */ jsx(
|
|
@@ -97,11 +100,17 @@ function Toolbar(props) {
|
|
|
97
100
|
"aria-label": "Copy URL",
|
|
98
101
|
onClick: () => {
|
|
99
102
|
var _a;
|
|
100
|
-
(_a = input == null ? void 0 : input.current) != null && _a.value &&
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
(_a = input == null ? void 0 : input.current) != null && _a.value && copy(input.current.value).then((copied) => {
|
|
104
|
+
pushToast(copied ? {
|
|
105
|
+
closable: !0,
|
|
106
|
+
status: "success",
|
|
107
|
+
title: "The URL is copied to the clipboard"
|
|
108
|
+
} : {
|
|
109
|
+
closable: !0,
|
|
110
|
+
status: "error",
|
|
111
|
+
title: "Failed to copy the URL to the clipboard"
|
|
112
|
+
});
|
|
113
|
+
});
|
|
105
114
|
}
|
|
106
115
|
}
|
|
107
116
|
)
|
|
@@ -110,6 +119,7 @@ function Toolbar(props) {
|
|
|
110
119
|
/* @__PURE__ */ jsx(
|
|
111
120
|
Tooltip,
|
|
112
121
|
{
|
|
122
|
+
animate: !0,
|
|
113
123
|
content: /* @__PURE__ */ jsx(Text, { size: 1, style: { whiteSpace: "nowrap" }, children: "Open URL in a new tab" }),
|
|
114
124
|
padding: 2,
|
|
115
125
|
placement: "bottom-end",
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/DisplayUrl.tsx","../src/Toolbar.tsx","../src/Iframe.tsx"],"sourcesContent":["import {getRedirectTo} from '@sanity/preview-url-secret/get-redirect-to'\nimport {Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\n\nexport function DisplayUrl(props: {url: URL}) {\n const truncatedUrl = useMemo(() => {\n const url = getRedirectTo(props.url)\n return `${url.origin === location.origin ? '' : url.origin}${url.pathname}${url.search}`\n }, [props.url])\n\n return (\n <Text size={0} textOverflow=\"ellipsis\">\n {truncatedUrl}\n </Text>\n )\n}\n","import {CopyIcon, LaunchIcon, MobileDeviceIcon, RefreshIcon} from '@sanity/icons'\nimport {Box, Button, Card, Flex, Text, Tooltip, useToast} from '@sanity/ui'\nimport React, {useRef} from 'react'\nimport {useCopyToClipboard} from 'usehooks-ts'\n\nimport {DisplayUrl} from './DisplayUrl'\nimport {IframeSizeKey, type SizeProps} from './types'\n\nexport const sizes: SizeProps = {\n desktop: {\n width: '100%',\n height: '100%',\n },\n mobile: {\n width: 414,\n height: 746,\n },\n}\n\nexport const DEFAULT_SIZE = `desktop`\n\nexport interface ToolbarProps {\n url: URL | Error | undefined\n iframeSize: IframeSizeKey\n setIframeSize: (size: IframeSizeKey) => void\n showUrl: boolean\n reloading: boolean\n reloadButton: boolean\n handleReload: () => void\n}\nexport function Toolbar(props: ToolbarProps) {\n const {url, iframeSize, setIframeSize, reloading, showUrl, reloadButton, handleReload} = props\n const validUrl = url instanceof URL\n\n const input = useRef<HTMLTextAreaElement>(null)\n const {push: pushToast} = useToast()\n const [, copy] = useCopyToClipboard()\n\n return (\n <>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={validUrl ? url.toString() : ''}\n readOnly\n tabIndex={-1}\n />\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {iframeSize === 'mobile' ? 'Exit mobile preview' : 'Preview mobile viewport'}\n </Text>\n }\n padding={2}\n placement=\"bottom-start\"\n >\n <Button\n disabled={!validUrl}\n fontSize={[1]}\n padding={2}\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Tooltip>\n </Flex>\n <Box flex={1}>{showUrl && validUrl && <DisplayUrl url={url} />}</Box>\n <Flex align=\"center\" gap={1}>\n {reloadButton ? (\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {reloading ? 'Reloading…' : 'Reload'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!validUrl}\n mode=\"bleed\"\n fontSize={[1]}\n padding={2}\n icon={RefreshIcon}\n loading={reloading}\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n </Tooltip>\n ) : null}\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Copy URL\n </Text>\n }\n padding={2}\n >\n <Button\n mode=\"bleed\"\n disabled={!validUrl}\n fontSize={[1]}\n icon={CopyIcon}\n padding={[2]}\n aria-label=\"Copy URL\"\n onClick={() => {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n pushToast({\n closable: true,\n status: 'success',\n title: 'The URL is copied to the clipboard',\n })\n }}\n />\n </Tooltip>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Open URL in a new tab\n </Text>\n }\n padding={2}\n placement=\"bottom-end\"\n >\n <Button\n disabled={!validUrl}\n fontSize={[1]}\n icon={LaunchIcon}\n mode=\"ghost\"\n paddingY={[2]}\n text=\"Open\"\n aria-label=\"Open URL in a new tab\"\n onClick={validUrl ? () => window.open(url.toString()) : undefined}\n />\n </Tooltip>\n </Flex>\n </Flex>\n </Card>\n </>\n )\n}\n","import {WarningOutlineIcon} from '@sanity/icons'\nimport {createPreviewSecret} from '@sanity/preview-url-secret/create-secret'\nimport {definePreviewUrl} from '@sanity/preview-url-secret/define-preview-url'\nimport {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {AnimatePresence, motion, MotionConfig} from 'framer-motion'\nimport React, {\n forwardRef,\n memo,\n Suspense,\n useCallback,\n useEffect,\n useRef,\n useState,\n useTransition,\n} from 'react'\nimport {HTMLAttributeReferrerPolicy} from 'react'\nimport {SanityDocument, useClient, useCurrentUser} from 'sanity'\nimport {suspend} from 'suspend-react'\n\nimport {DEFAULT_SIZE, sizes, Toolbar} from './Toolbar'\nimport {IframeSizeKey} from './types'\n\nexport type UrlResolver = (\n document: SanityDocument | null,\n) => string | Error | undefined | Promise<string | Error | undefined>\n\nexport type {IframeSizeKey}\n\nexport interface IframeOptions {\n /**\n * If you have multiple iframe instances side-by-side you need to give each a unique key.\n */\n key?: string\n url:\n | string\n | UrlResolver\n | {\n /**\n * The URL origin of where the preview is hosted, for example `https://example.com`.\n * If it's an embedded Studio then set it to `'same-origin'`.\n */\n origin: 'same-origin' | string\n /**\n * The route to redirect to after enabling Draft Mode.\n * If you don't have enough data to build the URL, return an `Error` instance to show an error message.\n * @example `return new Error('Missing slug')`\n * To prolong the loading state, return `undefined`\n */\n preview: string | UrlResolver\n /**\n * The route that enables Draft Mode\n * @example '/api/draft'\n */\n draftMode: string\n }\n defaultSize?: IframeSizeKey\n showDisplayUrl?: boolean\n reload?: {\n button?: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nconst MotionFlex = motion(Flex)\n\nexport interface IframeProps {\n document: {\n displayed: SanityDocument\n draft: SanityDocument | null\n published: SanityDocument | null\n }\n options: IframeOptions\n}\n\nexport function Iframe(props: IframeProps) {\n const {document, options} = props\n const draft = document.draft || document.published || document.displayed\n\n const {defaultSize = DEFAULT_SIZE, reload, attributes, showDisplayUrl = true, key} = options\n\n const urlRef = useRef(options.url)\n const [draftSnapshot, setDraftSnapshot] = useState(() => ({key, draft}))\n useEffect(() => {\n urlRef.current = options.url\n }, [options.url])\n useEffect(() => {\n if (JSON.stringify({key, draft}) !== JSON.stringify(draftSnapshot)) {\n startTransition(() => setDraftSnapshot({key, draft}))\n }\n }, [draft, draftSnapshot, key])\n const currentUser = useCurrentUser()\n const client = useClient({apiVersion: '2023-10-16'})\n const [expiresAt, setExpiresAt] = useState<number | undefined>()\n const previewSecretRef = useRef<string | undefined>()\n const [isResolvingUrl, startTransition] = useTransition()\n const url = useCallback(\n // eslint-disable-next-line @typescript-eslint/no-shadow\n async (draft: SanityDocument | null) => {\n if (typeof location === 'undefined') {\n return undefined\n }\n const urlProp = urlRef.current\n if (typeof urlProp === 'string') {\n return new URL(urlProp, location.origin)\n }\n if (typeof urlProp === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const url = await urlProp(draft)\n return typeof url === 'string' ? new URL(url, location.origin) : url\n }\n if (typeof urlProp === 'object') {\n const preview =\n typeof urlProp.preview === 'function' ? await urlProp.preview(draft) : urlProp.preview\n if (typeof preview !== 'string') {\n return preview\n }\n if (!previewSecretRef.current) {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const {secret, expiresAt} = await createPreviewSecret(\n client,\n 'sanity-plugin-iframe-pane',\n location.href,\n currentUser?.id,\n )\n previewSecretRef.current = secret\n startTransition(() => setExpiresAt(expiresAt.getTime()))\n }\n\n const resolvePreviewUrl = definePreviewUrl({\n origin: urlProp.origin === 'same-origin' ? location.origin : urlProp.origin,\n preview,\n draftMode: {\n enable: urlProp.draftMode,\n },\n })\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const url = await resolvePreviewUrl({\n client,\n previewUrlSecret: previewSecretRef.current,\n previewSearchParam: null,\n })\n return new URL(url, location.origin)\n }\n return undefined\n },\n [client, currentUser?.id],\n )\n useEffect(() => {\n if (expiresAt) {\n const timeout = setTimeout(\n () => {\n startTransition(() => setExpiresAt(undefined))\n previewSecretRef.current = undefined\n },\n Math.max(0, expiresAt - Date.now()),\n )\n return () => clearTimeout(timeout)\n }\n return undefined\n }, [expiresAt])\n\n return (\n <Suspense fallback={<Loading iframeSize=\"desktop\" />}>\n <IframeInner\n key={draftSnapshot.key}\n _key={draftSnapshot.key}\n draftSnapshot={draftSnapshot.draft}\n url={url}\n isResolvingUrl={isResolvingUrl}\n attributes={attributes}\n defaultSize={defaultSize}\n reload={reload}\n showDisplayUrl={showDisplayUrl}\n userId={currentUser?.id}\n />\n </Suspense>\n )\n}\n\nexport interface IframeInnerProps extends Omit<IframeOptions, 'url'> {\n url: (draftSnapshot: SanityDocument | null) => Promise<URL | Error | undefined>\n isResolvingUrl: boolean\n draftSnapshot: SanityDocument | null\n userId?: string\n expiresAt?: number\n _key?: string\n}\nconst IframeInner = memo(function IframeInner(props: IframeInnerProps) {\n const {\n isResolvingUrl,\n defaultSize = DEFAULT_SIZE,\n reload,\n attributes = {},\n showDisplayUrl = true,\n draftSnapshot,\n userId,\n expiresAt,\n _key,\n } = props\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n\n const prefersReducedMotion = usePrefersReducedMotion()\n\n const url = suspend(\n () => props.url(draftSnapshot),\n [\n // Cache based on a few specific conditions\n 'sanity-plugin-iframe-pane',\n draftSnapshot,\n userId,\n expiresAt,\n _key,\n resolveUUID,\n ],\n )\n\n const [loading, setLoading] = useState(true)\n const [_reloading, setReloading] = useState(false)\n const reloading = _reloading || isResolvingUrl\n\n const iframe = useRef<HTMLIFrameElement>(null)\n\n const handleReload = useCallback(() => {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issues\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setReloading(true)\n }, [])\n\n return (\n <MotionConfig transition={prefersReducedMotion ? {duration: 0} : undefined}>\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Toolbar\n url={url}\n iframeSize={iframeSize}\n reloading={reloading}\n setIframeSize={setIframeSize}\n showUrl={showDisplayUrl}\n reloadButton={!!reload?.button}\n handleReload={handleReload}\n />\n {url instanceof Error ? (\n <ErrorCard error={url} />\n ) : (\n <Card tone=\"transparent\" style={{height: `100%`}}>\n <Frame\n ref={iframe}\n loading={loading}\n reloading={reloading}\n iframeSize={iframeSize}\n setReloading={setReloading}\n setLoading={setLoading}\n url={url}\n attributes={attributes}\n />\n </Card>\n )}\n </Flex>\n </MotionConfig>\n )\n})\n\ninterface FrameProps extends Required<Pick<IframeOptions, 'attributes'>> {\n loading: boolean\n reloading: boolean\n setLoading: (loading: boolean) => void\n setReloading: (reloading: boolean) => void\n iframeSize: IframeSizeKey\n url: URL | undefined\n}\nconst Frame = forwardRef(function Frame(\n props: FrameProps,\n iframe: React.ForwardedRef<HTMLIFrameElement>,\n) {\n const {loading, setLoading, iframeSize, attributes, reloading, url, setReloading} = props\n\n function handleIframeLoad() {\n setLoading(false)\n setReloading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n <AnimatePresence>\n {!url ||\n (loading && (\n <MotionFlex\n initial=\"initial\"\n animate=\"animate\"\n exit=\"exit\"\n variants={spinnerVariants}\n justify=\"center\"\n align=\"center\"\n style={{inset: `0`, position: `absolute`}}\n >\n <Loading iframeSize={iframeSize} />\n </MotionFlex>\n ))}\n </AnimatePresence>\n {url && (\n <motion.iframe\n ref={iframe}\n title=\"preview\"\n frameBorder=\"0\"\n style={{maxHeight: '100%'}}\n src={url.toString()}\n initial={['background', iframeSize]}\n variants={iframeVariants}\n animate={[\n loading ? 'background' : 'active',\n reloading ? 'reloading' : 'idle',\n iframeSize,\n ]}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n )}\n </Flex>\n )\n})\n\nconst spinnerVariants = {\n initial: {opacity: 1},\n animate: {opacity: [0, 0, 1]},\n exit: {opacity: [1, 0, 0]},\n}\n\nconst iframeVariants = {\n ...sizes,\n desktop: {\n ...sizes.desktop,\n boxShadow: '0 0 0 0px var(--card-shadow-outline-color)',\n },\n mobile: {\n ...sizes.mobile,\n boxShadow: '0 0 0 1px var(--card-shadow-outline-color)',\n },\n background: {\n opacity: 0,\n scale: 1,\n },\n idle: {\n scale: 1,\n },\n reloading: {\n scale: [1, 1, 1, 0.98],\n },\n active: {\n opacity: [0, 0, 1],\n scale: 1,\n },\n}\n\nfunction Loading({iframeSize}: {iframeSize: IframeSizeKey}) {\n return (\n <Flex style={{...sizes[iframeSize]}} justify=\"center\" align=\"center\" direction=\"column\" gap={4}>\n <Spinner muted />\n <Text muted size={1}>\n Loading…\n </Text>\n </Flex>\n )\n}\n\nexport function ErrorCard({error}: {error: Error}) {\n return (\n <Card height=\"fill\">\n <Flex align=\"center\" height=\"fill\" justify=\"center\" padding={4} sizing=\"border\">\n <Container width={0}>\n <Card padding={4} radius={2} shadow={1} tone=\"caution\">\n <Flex>\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack flex={1} marginLeft={3} space={3}>\n <Text as=\"h1\" size={1} weight=\"bold\">\n {error.name}\n </Text>\n <Text as=\"p\" muted size={1}>\n {error.message}\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Container>\n </Flex>\n </Card>\n )\n}\n\n// https://github.com/pmndrs/suspend-react?tab=readme-ov-file#making-cache-keys-unique\nconst resolveUUID = Symbol()\n"],"names":["draft","url","expiresAt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/DisplayUrl.tsx","../src/Toolbar.tsx","../src/Iframe.tsx"],"sourcesContent":["import {getRedirectTo} from '@sanity/preview-url-secret/get-redirect-to'\nimport {Text} from '@sanity/ui'\nimport {useMemo} from 'react'\n\nexport function DisplayUrl(props: {url: URL}) {\n const truncatedUrl = useMemo(() => {\n const url = getRedirectTo(props.url)\n return `${url.origin === location.origin ? '' : url.origin}${url.pathname}${url.search}`\n }, [props.url])\n\n return (\n <Text size={0} textOverflow=\"ellipsis\">\n {truncatedUrl}\n </Text>\n )\n}\n","import {CopyIcon, LaunchIcon, MobileDeviceIcon, RefreshIcon} from '@sanity/icons'\nimport {Box, Button, Card, Flex, Text, Tooltip, useToast} from '@sanity/ui'\nimport {useRef} from 'react'\nimport {useCopyToClipboard} from 'usehooks-ts'\n\nimport {DisplayUrl} from './DisplayUrl'\nimport type {IframeSizeKey, SizeProps} from './types'\n\nexport const sizes: SizeProps = {\n desktop: {\n width: '100%',\n height: '100%',\n },\n mobile: {\n width: 414,\n height: 746,\n },\n}\n\nexport const DEFAULT_SIZE = 'desktop'\n\nexport interface ToolbarProps {\n url: URL | Error | undefined\n iframeSize: IframeSizeKey\n setIframeSize: (size: IframeSizeKey) => void\n showUrl: boolean\n reloading: boolean\n reloadButton: boolean\n handleReload: () => void\n}\nexport function Toolbar(props: ToolbarProps) {\n const {url, iframeSize, setIframeSize, reloading, showUrl, reloadButton, handleReload} = props\n const validUrl = url instanceof URL\n\n const input = useRef<HTMLTextAreaElement>(null)\n const {push: pushToast} = useToast()\n const [, copy] = useCopyToClipboard()\n\n return (\n <>\n <textarea\n style={{position: 'absolute', pointerEvents: 'none', opacity: 0}}\n ref={input}\n value={validUrl ? url.toString() : ''}\n readOnly\n tabIndex={-1}\n />\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Tooltip\n animate\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {iframeSize === 'mobile' ? 'Exit mobile preview' : 'Preview mobile viewport'}\n </Text>\n }\n padding={2}\n placement=\"bottom-start\"\n >\n <Button\n disabled={!validUrl}\n fontSize={[1]}\n padding={2}\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Tooltip>\n </Flex>\n <Box flex={1}>{showUrl && validUrl && <DisplayUrl url={url} />}</Box>\n <Flex align=\"center\" gap={1}>\n {reloadButton ? (\n <Tooltip\n animate\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {reloading ? 'Reloading…' : 'Reload'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!validUrl}\n mode=\"bleed\"\n fontSize={[1]}\n padding={2}\n icon={RefreshIcon}\n loading={reloading}\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n </Tooltip>\n ) : null}\n <Tooltip\n animate\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Copy URL\n </Text>\n }\n padding={2}\n >\n <Button\n mode=\"bleed\"\n disabled={!validUrl}\n fontSize={[1]}\n icon={CopyIcon}\n padding={[2]}\n aria-label=\"Copy URL\"\n onClick={() => {\n if (!input?.current?.value) return\n\n copy(input.current.value).then((copied) => {\n if (copied) {\n pushToast({\n closable: true,\n status: 'success',\n title: 'The URL is copied to the clipboard',\n })\n } else {\n pushToast({\n closable: true,\n status: 'error',\n title: 'Failed to copy the URL to the clipboard',\n })\n }\n })\n }}\n />\n </Tooltip>\n <Tooltip\n animate\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Open URL in a new tab\n </Text>\n }\n padding={2}\n placement=\"bottom-end\"\n >\n <Button\n disabled={!validUrl}\n fontSize={[1]}\n icon={LaunchIcon}\n mode=\"ghost\"\n paddingY={[2]}\n text=\"Open\"\n aria-label=\"Open URL in a new tab\"\n onClick={validUrl ? () => window.open(url.toString()) : undefined}\n />\n </Tooltip>\n </Flex>\n </Flex>\n </Card>\n </>\n )\n}\n","import {WarningOutlineIcon} from '@sanity/icons'\nimport {createPreviewSecret} from '@sanity/preview-url-secret/create-secret'\nimport {definePreviewUrl} from '@sanity/preview-url-secret/define-preview-url'\nimport {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {AnimatePresence, motion, MotionConfig} from 'framer-motion'\nimport type {HTMLAttributeReferrerPolicy} from 'react'\nimport {\n forwardRef,\n memo,\n Suspense,\n useCallback,\n useEffect,\n useRef,\n useState,\n useTransition,\n} from 'react'\nimport {type SanityDocument, useClient, useCurrentUser} from 'sanity'\nimport {suspend} from 'suspend-react'\n\nimport {DEFAULT_SIZE, sizes, Toolbar} from './Toolbar'\nimport type {IframeSizeKey} from './types'\n\nexport type UrlResolver = (\n document: SanityDocument | null,\n) => string | Error | undefined | Promise<string | Error | undefined>\n\nexport type {IframeSizeKey}\n\nexport interface IframeOptions {\n /**\n * If you have multiple iframe instances side-by-side you need to give each a unique key.\n */\n key?: string\n url:\n | string\n | UrlResolver\n | {\n /**\n * The URL origin of where the preview is hosted, for example `https://example.com`.\n * If it's an embedded Studio then set it to `'same-origin'`.\n */\n origin: 'same-origin' | string\n /**\n * The route to redirect to after enabling Draft Mode.\n * If you don't have enough data to build the URL, return an `Error` instance to show an error message.\n * @example `return new Error('Missing slug')`\n * To prolong the loading state, return `undefined`\n */\n preview: string | UrlResolver\n /**\n * The route that enables Draft Mode\n * @example '/api/draft'\n */\n draftMode: string\n }\n defaultSize?: IframeSizeKey\n showDisplayUrl?: boolean\n reload?: {\n button?: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nconst MotionFlex = motion(Flex)\n\nexport interface IframeProps {\n document: {\n displayed: SanityDocument\n draft: SanityDocument | null\n published: SanityDocument | null\n }\n options: IframeOptions\n}\n\nexport function Iframe(props: IframeProps) {\n const {document, options} = props\n const draft = document.draft || document.published || document.displayed\n\n const {defaultSize = DEFAULT_SIZE, reload, attributes, showDisplayUrl = true, key} = options\n\n const urlRef = useRef(options.url)\n const [draftSnapshot, setDraftSnapshot] = useState(() => ({key, draft}))\n useEffect(() => {\n urlRef.current = options.url\n }, [options.url])\n useEffect(() => {\n if (JSON.stringify({key, draft}) !== JSON.stringify(draftSnapshot)) {\n startTransition(() => setDraftSnapshot({key, draft}))\n }\n }, [draft, draftSnapshot, key])\n const currentUser = useCurrentUser()\n const client = useClient({apiVersion: '2023-10-16'})\n const [expiresAt, setExpiresAt] = useState<number | undefined>()\n const previewSecretRef = useRef<string | undefined>()\n const [isResolvingUrl, startTransition] = useTransition()\n const url = useCallback(\n // eslint-disable-next-line @typescript-eslint/no-shadow\n async (draft: SanityDocument | null) => {\n if (typeof location === 'undefined') {\n return undefined\n }\n const urlProp = urlRef.current\n if (typeof urlProp === 'string') {\n return new URL(urlProp, location.origin)\n }\n if (typeof urlProp === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const url = await urlProp(draft)\n return typeof url === 'string' ? new URL(url, location.origin) : url\n }\n if (typeof urlProp === 'object') {\n const preview =\n typeof urlProp.preview === 'function' ? await urlProp.preview(draft) : urlProp.preview\n if (typeof preview !== 'string') {\n return preview\n }\n if (!previewSecretRef.current) {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const {secret, expiresAt} = await createPreviewSecret(\n client,\n 'sanity-plugin-iframe-pane',\n location.href,\n currentUser?.id,\n )\n previewSecretRef.current = secret\n startTransition(() => setExpiresAt(expiresAt.getTime()))\n }\n\n const resolvePreviewUrl = definePreviewUrl({\n origin: urlProp.origin === 'same-origin' ? location.origin : urlProp.origin,\n preview,\n draftMode: {\n enable: urlProp.draftMode,\n },\n })\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const url = await resolvePreviewUrl({\n client,\n previewUrlSecret: previewSecretRef.current,\n previewSearchParam: null,\n })\n return new URL(url, location.origin)\n }\n return undefined\n },\n [client, currentUser?.id],\n )\n useEffect(() => {\n if (expiresAt) {\n const timeout = setTimeout(\n () => {\n startTransition(() => setExpiresAt(undefined))\n previewSecretRef.current = undefined\n },\n Math.max(0, expiresAt - Date.now()),\n )\n return () => clearTimeout(timeout)\n }\n return undefined\n }, [expiresAt])\n\n return (\n <Suspense fallback={<Loading iframeSize=\"desktop\" />}>\n <IframeInner\n key={draftSnapshot.key}\n _key={draftSnapshot.key}\n draftSnapshot={draftSnapshot.draft}\n url={url}\n isResolvingUrl={isResolvingUrl}\n attributes={attributes}\n defaultSize={defaultSize}\n reload={reload}\n showDisplayUrl={showDisplayUrl}\n userId={currentUser?.id}\n />\n </Suspense>\n )\n}\n\nexport interface IframeInnerProps extends Omit<IframeOptions, 'url'> {\n url: (draftSnapshot: SanityDocument | null) => Promise<URL | Error | undefined>\n isResolvingUrl: boolean\n draftSnapshot: SanityDocument | null\n userId?: string\n expiresAt?: number\n _key?: string\n}\nconst IframeInner = memo(function IframeInner(props: IframeInnerProps) {\n const {\n isResolvingUrl,\n defaultSize = DEFAULT_SIZE,\n reload,\n attributes = {},\n showDisplayUrl = true,\n draftSnapshot,\n userId,\n expiresAt,\n _key,\n } = props\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n\n const prefersReducedMotion = usePrefersReducedMotion()\n\n const url = suspend(\n () => props.url(draftSnapshot),\n [\n // Cache based on a few specific conditions\n 'sanity-plugin-iframe-pane',\n draftSnapshot,\n userId,\n expiresAt,\n _key,\n resolveUUID,\n ],\n )\n\n const [loading, setLoading] = useState(true)\n const [_reloading, setReloading] = useState(false)\n const reloading = _reloading || isResolvingUrl\n\n const iframe = useRef<HTMLIFrameElement>(null)\n\n const handleReload = useCallback(() => {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issues\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setReloading(true)\n }, [])\n\n return (\n <MotionConfig transition={prefersReducedMotion ? {duration: 0} : undefined}>\n <Flex direction=\"column\" style={{height: '100%'}}>\n <Toolbar\n url={url}\n iframeSize={iframeSize}\n reloading={reloading}\n setIframeSize={setIframeSize}\n showUrl={showDisplayUrl}\n reloadButton={!!reload?.button}\n handleReload={handleReload}\n />\n {url instanceof Error ? (\n <ErrorCard error={url} />\n ) : (\n <Card tone=\"transparent\" style={{height: '100%'}}>\n <Frame\n ref={iframe}\n loading={loading}\n reloading={reloading}\n iframeSize={iframeSize}\n setReloading={setReloading}\n setLoading={setLoading}\n url={url}\n attributes={attributes}\n />\n </Card>\n )}\n </Flex>\n </MotionConfig>\n )\n})\n\ninterface FrameProps extends Required<Pick<IframeOptions, 'attributes'>> {\n loading: boolean\n reloading: boolean\n setLoading: (loading: boolean) => void\n setReloading: (reloading: boolean) => void\n iframeSize: IframeSizeKey\n url: URL | undefined\n}\nconst Frame = forwardRef(function Frame(\n props: FrameProps,\n iframe: React.ForwardedRef<HTMLIFrameElement>,\n) {\n const {loading, setLoading, iframeSize, attributes, reloading, url, setReloading} = props\n\n function handleIframeLoad() {\n setLoading(false)\n setReloading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" style={{height: '100%', position: 'relative'}}>\n <AnimatePresence>\n {!url ||\n (loading && (\n <MotionFlex\n initial=\"initial\"\n animate=\"animate\"\n exit=\"exit\"\n variants={spinnerVariants}\n justify=\"center\"\n align=\"center\"\n style={{inset: '0', position: 'absolute'}}\n >\n <Loading iframeSize={iframeSize} />\n </MotionFlex>\n ))}\n </AnimatePresence>\n {url && (\n <motion.iframe\n ref={iframe}\n title=\"preview\"\n frameBorder=\"0\"\n style={{maxHeight: '100%'}}\n src={url.toString()}\n initial={['background', iframeSize]}\n variants={iframeVariants}\n animate={[\n loading ? 'background' : 'active',\n reloading ? 'reloading' : 'idle',\n iframeSize,\n ]}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n )}\n </Flex>\n )\n})\n\nconst spinnerVariants = {\n initial: {opacity: 1},\n animate: {opacity: [0, 0, 1]},\n exit: {opacity: [1, 0, 0]},\n}\n\nconst iframeVariants = {\n ...sizes,\n desktop: {\n ...sizes.desktop,\n boxShadow: '0 0 0 0px var(--card-shadow-outline-color)',\n },\n mobile: {\n ...sizes.mobile,\n boxShadow: '0 0 0 1px var(--card-shadow-outline-color)',\n },\n background: {\n opacity: 0,\n scale: 1,\n },\n idle: {\n scale: 1,\n },\n reloading: {\n scale: [1, 1, 1, 0.98],\n },\n active: {\n opacity: [0, 0, 1],\n scale: 1,\n },\n}\n\nfunction Loading({iframeSize}: {iframeSize: IframeSizeKey}) {\n return (\n <Flex style={{...sizes[iframeSize]}} justify=\"center\" align=\"center\" direction=\"column\" gap={4}>\n <Spinner muted />\n <Text muted size={1}>\n Loading…\n </Text>\n </Flex>\n )\n}\n\nexport function ErrorCard({error}: {error: Error}) {\n return (\n <Card height=\"fill\">\n <Flex align=\"center\" height=\"fill\" justify=\"center\" padding={4} sizing=\"border\">\n <Container width={0}>\n <Card padding={4} radius={2} shadow={1} tone=\"caution\">\n <Flex>\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack flex={1} marginLeft={3} space={3}>\n <Text as=\"h1\" size={1} weight=\"bold\">\n {error.name}\n </Text>\n <Text as=\"p\" muted size={1}>\n {error.message}\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Container>\n </Flex>\n </Card>\n )\n}\n\n// https://github.com/pmndrs/suspend-react?tab=readme-ov-file#making-cache-keys-unique\nconst resolveUUID = Symbol()\n"],"names":["draft","url","expiresAt"],"mappings":";;;;;;;;;;;AAIO,SAAS,WAAW,OAAmB;AACtC,QAAA,eAAe,QAAQ,MAAM;AAC3B,UAAA,MAAM,cAAc,MAAM,GAAG;AACnC,WAAO,GAAG,IAAI,WAAW,SAAS,SAAS,KAAK,IAAI,MAAM,GAAG,IAAI,QAAQ,GAAG,IAAI,MAAM;AAAA,EAAA,GACrF,CAAC,MAAM,GAAG,CAAC;AAEd,6BACG,MAAK,EAAA,MAAM,GAAG,cAAa,YACzB,UACH,aAAA,CAAA;AAEJ;ACPO,MAAM,QAAmB;AAAA,EAC9B,SAAS;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AAAA,EACA,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AACF,GAEa,eAAe;AAWrB,SAAS,QAAQ,OAAqB;AACrC,QAAA,EAAC,KAAK,YAAY,eAAe,WAAW,SAAS,cAAc,aAAY,IAAI,OACnF,WAAW,eAAe,KAE1B,QAAQ,OAA4B,IAAI,GACxC,EAAC,MAAM,cAAa,YACpB,CAAA,EAAG,IAAI,IAAI,mBAAmB;AAEpC,SAEI,qBAAA,UAAA,EAAA,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO,EAAC,UAAU,YAAY,eAAe,QAAQ,SAAS,EAAC;AAAA,QAC/D,KAAK;AAAA,QACL,OAAO,WAAW,IAAI,SAAa,IAAA;AAAA,QACnC,UAAQ;AAAA,QACR,UAAU;AAAA,MAAA;AAAA,IACZ;AAAA,IACA,oBAAC,MAAK,EAAA,SAAS,GAAG,cAAY,IAC5B,UAAA,qBAAC,MAAK,EAAA,OAAM,UAAS,KAAK,GACxB,UAAA;AAAA,MAAA,oBAAC,MAAK,EAAA,OAAM,UAAS,KAAK,GACxB,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAO;AAAA,UACP,SACE,oBAAC,MAAK,EAAA,MAAM,GAAG,OAAO,EAAC,YAAY,SAAQ,GACxC,UAAe,eAAA,WAAW,wBAAwB,2BACrD;AAAA,UAEF,SAAS;AAAA,UACT,WAAU;AAAA,UAEV,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,UAAU,CAAC;AAAA,cACX,UAAU,CAAC,CAAC;AAAA,cACZ,SAAS;AAAA,cACT,MAAM,eAAe,WAAW,YAAY;AAAA,cAC5C,MAAM;AAAA,cACN,SAAS,MAAM,cAAc,eAAe,WAAW,YAAY,QAAQ;AAAA,YAAA;AAAA,UAC7E;AAAA,QAAA;AAAA,MAAA,GAEJ;AAAA,MACA,oBAAC,OAAI,MAAM,GAAI,qBAAW,YAAY,oBAAC,YAAW,EAAA,IAAA,CAAU,EAAG,CAAA;AAAA,MAC9D,qBAAA,MAAA,EAAK,OAAM,UAAS,KAAK,GACvB,UAAA;AAAA,QACC,eAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAAO;AAAA,YACP,SACE,oBAAC,MAAK,EAAA,MAAM,GAAG,OAAO,EAAC,YAAY,SAAQ,GACxC,UAAY,YAAA,oBAAe,SAC9B,CAAA;AAAA,YAEF,SAAS;AAAA,YAET,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,UAAU,CAAC;AAAA,gBACX,MAAK;AAAA,gBACL,UAAU,CAAC,CAAC;AAAA,gBACZ,SAAS;AAAA,gBACT,MAAM;AAAA,gBACN,SAAS;AAAA,gBACT,cAAW;AAAA,gBACX,SAAS,MAAM,aAAa;AAAA,cAAA;AAAA,YAC9B;AAAA,UAAA;AAAA,QAAA,IAEA;AAAA,QACJ;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAAO;AAAA,YACP,SACG,oBAAA,MAAA,EAAK,MAAM,GAAG,OAAO,EAAC,YAAY,SAAQ,GAAG,UAE9C,WAAA,CAAA;AAAA,YAEF,SAAS;AAAA,YAET,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,UAAU,CAAC;AAAA,gBACX,UAAU,CAAC,CAAC;AAAA,gBACZ,MAAM;AAAA,gBACN,SAAS,CAAC,CAAC;AAAA,gBACX,cAAW;AAAA,gBACX,SAAS,MAAM;AA9G/B,sBAAA;AA+GuB,mBAAA,KAAA,SAAA,OAAA,SAAA,MAAO,YAAP,QAAA,GAAgB,SAErB,KAAK,MAAM,QAAQ,KAAK,EAAE,KAAK,CAAC,WAAW;AAEvC,8BADE,SACQ;AAAA,sBACR,UAAU;AAAA,sBACV,QAAQ;AAAA,sBACR,OAAO;AAAA,oBAAA,IAGC;AAAA,sBACR,UAAU;AAAA,sBACV,QAAQ;AAAA,sBACR,OAAO;AAAA,oBAAA,CALR;AAAA,kBAAA,CAQJ;AAAA,gBACH;AAAA,cAAA;AAAA,YACF;AAAA,UAAA;AAAA,QACF;AAAA,QACA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAAO;AAAA,YACP,SACG,oBAAA,MAAA,EAAK,MAAM,GAAG,OAAO,EAAC,YAAY,SAAQ,GAAG,UAE9C,wBAAA,CAAA;AAAA,YAEF,SAAS;AAAA,YACT,WAAU;AAAA,YAEV,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,UAAU,CAAC;AAAA,gBACX,UAAU,CAAC,CAAC;AAAA,gBACZ,MAAM;AAAA,gBACN,MAAK;AAAA,gBACL,UAAU,CAAC,CAAC;AAAA,gBACZ,MAAK;AAAA,gBACL,cAAW;AAAA,gBACX,SAAS,WAAW,MAAM,OAAO,KAAK,IAAI,SAAA,CAAU,IAAI;AAAA,cAAA;AAAA,YAC1D;AAAA,UAAA;AAAA,QACF;AAAA,MAAA,GACF;AAAA,IAAA,EAAA,CACF,EACF,CAAA;AAAA,EACF,EAAA,CAAA;AAEJ;ACzFA,MAAM,aAAa,OAAO,IAAI;AAWvB,SAAS,OAAO,OAAoB;AACzC,QAAM,EAAC,UAAU,QAAA,IAAW,OACtB,QAAQ,SAAS,SAAS,SAAS,aAAa,SAAS,WAEzD,EAAC,cAAc,cAAc,QAAQ,YAAY,iBAAiB,IAAM,IAAA,IAAO,SAE/E,SAAS,OAAO,QAAQ,GAAG,GAC3B,CAAC,eAAe,gBAAgB,IAAI,SAAS,OAAO,EAAC,KAAK,MAAO,EAAA;AACvE,YAAU,MAAM;AACd,WAAO,UAAU,QAAQ;AAAA,KACxB,CAAC,QAAQ,GAAG,CAAC,GAChB,UAAU,MAAM;AACV,SAAK,UAAU,EAAC,KAAK,MAAM,CAAA,MAAM,KAAK,UAAU,aAAa,KAC/D,gBAAgB,MAAM,iBAAiB,EAAC,KAAK,MAAM,CAAA,CAAC;AAAA,EAErD,GAAA,CAAC,OAAO,eAAe,GAAG,CAAC;AACxB,QAAA,cAAc,eAAe,GAC7B,SAAS,UAAU,EAAC,YAAY,aAAA,CAAa,GAC7C,CAAC,WAAW,YAAY,IAAI,SAC5B,GAAA,mBAAmB,UACnB,CAAC,gBAAgB,eAAe,IAAI,iBACpC,MAAM;AAAA;AAAA,IAEV,OAAOA,WAAiC;AACtC,UAAI,OAAO,WAAa;AACtB;AAEF,YAAM,UAAU,OAAO;AACvB,UAAI,OAAO,WAAY;AACrB,eAAO,IAAI,IAAI,SAAS,SAAS,MAAM;AAErC,UAAA,OAAO,WAAY,YAAY;AAE3BC,cAAAA,OAAM,MAAM,QAAQD,MAAK;AACxB,eAAA,OAAOC,QAAQ,WAAW,IAAI,IAAIA,MAAK,SAAS,MAAM,IAAIA;AAAAA,MACnE;AACI,UAAA,OAAO,WAAY,UAAU;AACzB,cAAA,UACJ,OAAO,QAAQ,WAAY,aAAa,MAAM,QAAQ,QAAQD,MAAK,IAAI,QAAQ;AACjF,YAAI,OAAO,WAAY;AACd,iBAAA;AAEL,YAAA,CAAC,iBAAiB,SAAS;AAE7B,gBAAM,EAAC,QAAQ,WAAAE,WAAAA,IAAa,MAAM;AAAA,YAChC;AAAA,YACA;AAAA,YACA,SAAS;AAAA,YACT,eAAa,OAAA,SAAA,YAAA;AAAA,UAAA;AAEE,2BAAA,UAAU,QAC3B,gBAAgB,MAAM,aAAaA,WAAU,QAAS,CAAA,CAAC;AAAA,QACzD;AAUMD,cAAAA,OAAM,MARc,iBAAiB;AAAA,UACzC,QAAQ,QAAQ,WAAW,gBAAgB,SAAS,SAAS,QAAQ;AAAA,UACrE;AAAA,UACA,WAAW;AAAA,YACT,QAAQ,QAAQ;AAAA,UAClB;AAAA,QAAA,CACD,EAEmC;AAAA,UAClC;AAAA,UACA,kBAAkB,iBAAiB;AAAA,UACnC,oBAAoB;AAAA,QAAA,CACrB;AACD,eAAO,IAAI,IAAIA,MAAK,SAAS,MAAM;AAAA,MACrC;AAAA,IAEF;AAAA,IACA,CAAC,QAAQ,eAAA,OAAA,SAAA,YAAa,EAAE;AAAA,EAAA;AAE1B,SAAA,UAAU,MAAM;AACd,QAAI,WAAW;AACb,YAAM,UAAU;AAAA,QACd,MAAM;AACJ,0BAAgB,MAAM,aAAa,MAAS,CAAC,GAC7C,iBAAiB,UAAU;AAAA,QAC7B;AAAA,QACA,KAAK,IAAI,GAAG,YAAY,KAAK,KAAK;AAAA,MAAA;AAE7B,aAAA,MAAM,aAAa,OAAO;AAAA,IACnC;AAAA,EAEC,GAAA,CAAC,SAAS,CAAC,GAGZ,oBAAC,UAAS,EAAA,UAAW,oBAAA,SAAA,EAAQ,YAAW,UAAA,CAAU,GAChD,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MAEC,MAAM,cAAc;AAAA,MACpB,eAAe,cAAc;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,eAAa,OAAA,SAAA,YAAA;AAAA,IAAA;AAAA,IAThB,cAAc;AAAA,EAWvB,EAAA,CAAA;AAEJ;AAUA,MAAM,cAAc,KAAK,SAAqB,OAAyB;AAhMvE,MAAA;AAiMQ,QAAA;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA,aAAa,CAAC;AAAA,IACd,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE,OACE,CAAC,YAAY,aAAa,IAAI,UAAS,KAAQ,UAAA,QAAA,GAAA,WAAA,IAAe,cAAc,YAAY,GAExF,uBAAuB,wBAAA,GAEvB,MAAM;AAAA,IACV,MAAM,MAAM,IAAI,aAAa;AAAA,IAC7B;AAAA;AAAA,MAEE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EAAA,GAGI,CAAC,SAAS,UAAU,IAAI,SAAS,EAAI,GACrC,CAAC,YAAY,YAAY,IAAI,SAAS,EAAK,GAC3C,YAAY,cAAc,gBAE1B,SAAS,OAA0B,IAAI,GAEvC,eAAe,YAAY,MAAM;AAChC,cAAA,QAAA,OAAQ,YAMb,OAAO,QAAQ,MAAM,OAAO,QAAQ,KAEpC,aAAa,EAAI;AAAA,EACnB,GAAG,CAAE,CAAA;AAEL,6BACG,cAAa,EAAA,YAAY,uBAAuB,EAAC,UAAU,EAAC,IAAI,QAC/D,UAAA,qBAAC,QAAK,WAAU,UAAS,OAAO,EAAC,QAAQ,OACvC,GAAA,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT,cAAc,CAAC,EAAC,UAAQ,QAAA,OAAA;AAAA,QACxB;AAAA,MAAA;AAAA,IACF;AAAA,IACC,eAAe,QACb,oBAAA,WAAA,EAAU,OAAO,IAAK,CAAA,IAEtB,oBAAA,MAAA,EAAK,MAAK,eAAc,OAAO,EAAC,QAAQ,UACvC,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAAA,GAEJ;AAAA,EAAA,EAEJ,CAAA,EACF,CAAA;AAEJ,CAAC,GAUK,QAAQ,WAAW,SACvB,OACA,QACA;AACM,QAAA,EAAC,SAAS,YAAY,YAAY,YAAY,WAAW,KAAK,aAAgB,IAAA;AAEpF,WAAS,mBAAmB;AAC1B,eAAW,EAAK,GAChB,aAAa,EAAK,GAEd,WAAW,UAAU,OAAO,WAAW,UAAW,cACpD,WAAW,OAAO;AAAA,EAEtB;AAEA,SACG,qBAAA,MAAA,EAAK,OAAM,UAAS,SAAQ,UAAS,OAAO,EAAC,QAAQ,QAAQ,UAAU,WAAA,GACtE,UAAA;AAAA,IAAC,oBAAA,iBAAA,EACE,UAAC,CAAA,OACC,WACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,UAAU;AAAA,QACV,SAAQ;AAAA,QACR,OAAM;AAAA,QACN,OAAO,EAAC,OAAO,KAAK,UAAU,WAAU;AAAA,QAExC,UAAA,oBAAC,WAAQ,WAAwB,CAAA;AAAA,MAAA;AAAA,IAAA,GAGzC;AAAA,IACC,OACC;AAAA,MAAC,OAAO;AAAA,MAAP;AAAA,QACC,KAAK;AAAA,QACL,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,OAAO,EAAC,WAAW,OAAM;AAAA,QACzB,KAAK,IAAI,SAAS;AAAA,QAClB,SAAS,CAAC,cAAc,UAAU;AAAA,QAClC,UAAU;AAAA,QACV,SAAS;AAAA,UACP,UAAU,eAAe;AAAA,UACzB,YAAY,cAAc;AAAA,UAC1B;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QACJ,QAAQ;AAAA,MAAA;AAAA,IACV;AAAA,EAEJ,EAAA,CAAA;AAEJ,CAAC,GAEK,kBAAkB;AAAA,EACtB,SAAS,EAAC,SAAS,EAAC;AAAA,EACpB,SAAS,EAAC,SAAS,CAAC,GAAG,GAAG,CAAC,EAAC;AAAA,EAC5B,MAAM,EAAC,SAAS,CAAC,GAAG,GAAG,CAAC,EAAC;AAC3B,GAEM,iBAAiB;AAAA,EACrB,GAAG;AAAA,EACH,SAAS;AAAA,IACP,GAAG,MAAM;AAAA,IACT,WAAW;AAAA,EACb;AAAA,EACA,QAAQ;AAAA,IACN,GAAG,MAAM;AAAA,IACT,WAAW;AAAA,EACb;AAAA,EACA,YAAY;AAAA,IACV,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,EACT;AAAA,EACA,WAAW;AAAA,IACT,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI;AAAA,EACvB;AAAA,EACA,QAAQ;AAAA,IACN,SAAS,CAAC,GAAG,GAAG,CAAC;AAAA,IACjB,OAAO;AAAA,EACT;AACF;AAEA,SAAS,QAAQ,EAAC,cAA0C;AAC1D,8BACG,MAAK,EAAA,OAAO,EAAC,GAAG,MAAM,UAAU,EAAI,GAAA,SAAQ,UAAS,OAAM,UAAS,WAAU,UAAS,KAAK,GAC3F,UAAA;AAAA,IAAC,oBAAA,SAAA,EAAQ,OAAK,GAAC,CAAA;AAAA,wBACd,MAAK,EAAA,OAAK,IAAC,MAAM,GAAG,UAErB,iBAAA;AAAA,EACF,EAAA,CAAA;AAEJ;AAEgB,SAAA,UAAU,EAAC,SAAwB;AACjD,SACG,oBAAA,MAAA,EAAK,QAAO,QACX,UAAC,oBAAA,MAAA,EAAK,OAAM,UAAS,QAAO,QAAO,SAAQ,UAAS,SAAS,GAAG,QAAO,UACrE,UAAA,oBAAC,WAAU,EAAA,OAAO,GAChB,UAAA,oBAAC,QAAK,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAK,WAC3C,+BAAC,MACC,EAAA,UAAA;AAAA,IAAC,oBAAA,KAAA,EACC,8BAAC,MAAK,EAAA,MAAM,GACV,UAAC,oBAAA,oBAAA,CAAA,CAAmB,GACtB,EACF,CAAA;AAAA,yBACC,OAAM,EAAA,MAAM,GAAG,YAAY,GAAG,OAAO,GACpC,UAAA;AAAA,MAAC,oBAAA,MAAA,EAAK,IAAG,MAAK,MAAM,GAAG,QAAO,QAC3B,gBAAM,KACT,CAAA;AAAA,MACA,oBAAC,QAAK,IAAG,KAAI,OAAK,IAAC,MAAM,GACtB,UAAA,MAAM,QACT,CAAA;AAAA,IAAA,GACF;AAAA,EACF,EAAA,CAAA,EAAA,CACF,EACF,CAAA,EACF,CAAA,EACF,CAAA;AAEJ;AAGA,MAAM,cAAc,OAAO;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-iframe-pane",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.6",
|
|
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": {
|
|
@@ -18,11 +18,8 @@
|
|
|
18
18
|
".": {
|
|
19
19
|
"types": "./lib/index.d.ts",
|
|
20
20
|
"source": "./src/index.ts",
|
|
21
|
-
"require": "./lib/index.cjs",
|
|
22
|
-
"node": {
|
|
23
|
-
"import": "./lib/index.cjs.js"
|
|
24
|
-
},
|
|
25
21
|
"import": "./lib/index.js",
|
|
22
|
+
"require": "./lib/index.cjs",
|
|
26
23
|
"default": "./lib/index.js"
|
|
27
24
|
},
|
|
28
25
|
"./package.json": "./package.json"
|
|
@@ -49,44 +46,45 @@
|
|
|
49
46
|
"type-check": "tsc --noEmit",
|
|
50
47
|
"watch": "pkg-utils watch --strict"
|
|
51
48
|
},
|
|
49
|
+
"browserslist": "extends @sanity/browserslist-config",
|
|
52
50
|
"dependencies": {
|
|
53
51
|
"@sanity/icons": "^2.7.0",
|
|
54
52
|
"@sanity/incompatible-plugin": "^1.0.4",
|
|
55
|
-
"@sanity/preview-url-secret": "^1.
|
|
56
|
-
"@sanity/ui": "^
|
|
57
|
-
"framer-motion": "
|
|
53
|
+
"@sanity/preview-url-secret": "^1.6.4",
|
|
54
|
+
"@sanity/ui": "^2.0.10",
|
|
55
|
+
"framer-motion": "11.0.8",
|
|
58
56
|
"suspend-react": "0.1.3",
|
|
59
|
-
"usehooks-ts": "
|
|
57
|
+
"usehooks-ts": "3.0.1"
|
|
60
58
|
},
|
|
61
59
|
"devDependencies": {
|
|
62
60
|
"@commitlint/cli": "^19.2.0",
|
|
63
61
|
"@commitlint/config-conventional": "^19.1.0",
|
|
64
|
-
"@sanity/pkg-utils": "^
|
|
62
|
+
"@sanity/pkg-utils": "^5.0.4",
|
|
65
63
|
"@sanity/plugin-kit": "^3.1.10",
|
|
66
|
-
"@sanity/semantic-release-preset": "^4.1.
|
|
67
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
68
|
-
"@typescript-eslint/parser": "^
|
|
69
|
-
"eslint": "^8.55.0",
|
|
64
|
+
"@sanity/semantic-release-preset": "^4.1.7",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
|
66
|
+
"@typescript-eslint/parser": "^7.3.1",
|
|
70
67
|
"eslint-config-prettier": "^9.1.0",
|
|
71
68
|
"eslint-config-react-app": "^7.0.1",
|
|
72
|
-
"eslint-config-sanity": "^
|
|
73
|
-
"eslint-plugin-import": "^2.29.
|
|
74
|
-
"eslint-plugin-prettier": "^5.
|
|
75
|
-
"eslint-plugin-react": "^7.33.2",
|
|
69
|
+
"eslint-config-sanity": "^7.1.2",
|
|
70
|
+
"eslint-plugin-import": "^2.29.1",
|
|
71
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
76
72
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
73
|
+
"eslint-plugin-react": "^7.34.1",
|
|
74
|
+
"eslint": "^8.57.0",
|
|
77
75
|
"eslint-plugin-simple-import-sort": "^12.0.0",
|
|
78
76
|
"husky": "^8.0.3",
|
|
79
77
|
"lint-staged": "^15.0.1",
|
|
80
|
-
"npm-run-
|
|
81
|
-
"prettier": "^3.
|
|
82
|
-
"prettier-plugin-packagejson": "^2.4.
|
|
78
|
+
"npm-run-all2": "^5.0.0",
|
|
79
|
+
"prettier": "^3.2.5",
|
|
80
|
+
"prettier-plugin-packagejson": "^2.4.12",
|
|
83
81
|
"react": "^18.2.0",
|
|
84
82
|
"react-dom": "^18.2.0",
|
|
85
83
|
"react-is": "^18.2.0",
|
|
86
84
|
"rimraf": "^5.0.1",
|
|
87
|
-
"sanity": "^3.
|
|
88
|
-
"styled-components": "^6.1.
|
|
89
|
-
"typescript": "
|
|
85
|
+
"sanity": "^3.34.0",
|
|
86
|
+
"styled-components": "^6.1.8",
|
|
87
|
+
"typescript": "5.3.3"
|
|
90
88
|
},
|
|
91
89
|
"peerDependencies": {
|
|
92
90
|
"react": "^18.2.0",
|
package/src/DisplayUrl.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {getRedirectTo} from '@sanity/preview-url-secret/get-redirect-to'
|
|
2
2
|
import {Text} from '@sanity/ui'
|
|
3
|
-
import
|
|
3
|
+
import {useMemo} from 'react'
|
|
4
4
|
|
|
5
5
|
export function DisplayUrl(props: {url: URL}) {
|
|
6
6
|
const truncatedUrl = useMemo(() => {
|
package/src/Iframe.tsx
CHANGED
|
@@ -3,7 +3,8 @@ import {createPreviewSecret} from '@sanity/preview-url-secret/create-secret'
|
|
|
3
3
|
import {definePreviewUrl} from '@sanity/preview-url-secret/define-preview-url'
|
|
4
4
|
import {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotion} from '@sanity/ui'
|
|
5
5
|
import {AnimatePresence, motion, MotionConfig} from 'framer-motion'
|
|
6
|
-
import
|
|
6
|
+
import type {HTMLAttributeReferrerPolicy} from 'react'
|
|
7
|
+
import {
|
|
7
8
|
forwardRef,
|
|
8
9
|
memo,
|
|
9
10
|
Suspense,
|
|
@@ -13,12 +14,11 @@ import React, {
|
|
|
13
14
|
useState,
|
|
14
15
|
useTransition,
|
|
15
16
|
} from 'react'
|
|
16
|
-
import {
|
|
17
|
-
import {SanityDocument, useClient, useCurrentUser} from 'sanity'
|
|
17
|
+
import {type SanityDocument, useClient, useCurrentUser} from 'sanity'
|
|
18
18
|
import {suspend} from 'suspend-react'
|
|
19
19
|
|
|
20
20
|
import {DEFAULT_SIZE, sizes, Toolbar} from './Toolbar'
|
|
21
|
-
import {IframeSizeKey} from './types'
|
|
21
|
+
import type {IframeSizeKey} from './types'
|
|
22
22
|
|
|
23
23
|
export type UrlResolver = (
|
|
24
24
|
document: SanityDocument | null,
|
|
@@ -239,7 +239,7 @@ const IframeInner = memo(function IframeInner(props: IframeInnerProps) {
|
|
|
239
239
|
|
|
240
240
|
return (
|
|
241
241
|
<MotionConfig transition={prefersReducedMotion ? {duration: 0} : undefined}>
|
|
242
|
-
<Flex direction="column" style={{height:
|
|
242
|
+
<Flex direction="column" style={{height: '100%'}}>
|
|
243
243
|
<Toolbar
|
|
244
244
|
url={url}
|
|
245
245
|
iframeSize={iframeSize}
|
|
@@ -252,7 +252,7 @@ const IframeInner = memo(function IframeInner(props: IframeInnerProps) {
|
|
|
252
252
|
{url instanceof Error ? (
|
|
253
253
|
<ErrorCard error={url} />
|
|
254
254
|
) : (
|
|
255
|
-
<Card tone="transparent" style={{height:
|
|
255
|
+
<Card tone="transparent" style={{height: '100%'}}>
|
|
256
256
|
<Frame
|
|
257
257
|
ref={iframe}
|
|
258
258
|
loading={loading}
|
|
@@ -294,7 +294,7 @@ const Frame = forwardRef(function Frame(
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
return (
|
|
297
|
-
<Flex align="center" justify="center" style={{height:
|
|
297
|
+
<Flex align="center" justify="center" style={{height: '100%', position: 'relative'}}>
|
|
298
298
|
<AnimatePresence>
|
|
299
299
|
{!url ||
|
|
300
300
|
(loading && (
|
|
@@ -305,7 +305,7 @@ const Frame = forwardRef(function Frame(
|
|
|
305
305
|
variants={spinnerVariants}
|
|
306
306
|
justify="center"
|
|
307
307
|
align="center"
|
|
308
|
-
style={{inset:
|
|
308
|
+
style={{inset: '0', position: 'absolute'}}
|
|
309
309
|
>
|
|
310
310
|
<Loading iframeSize={iframeSize} />
|
|
311
311
|
</MotionFlex>
|
package/src/Toolbar.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {CopyIcon, LaunchIcon, MobileDeviceIcon, RefreshIcon} from '@sanity/icons'
|
|
2
2
|
import {Box, Button, Card, Flex, Text, Tooltip, useToast} from '@sanity/ui'
|
|
3
|
-
import
|
|
3
|
+
import {useRef} from 'react'
|
|
4
4
|
import {useCopyToClipboard} from 'usehooks-ts'
|
|
5
5
|
|
|
6
6
|
import {DisplayUrl} from './DisplayUrl'
|
|
7
|
-
import {IframeSizeKey,
|
|
7
|
+
import type {IframeSizeKey, SizeProps} from './types'
|
|
8
8
|
|
|
9
9
|
export const sizes: SizeProps = {
|
|
10
10
|
desktop: {
|
|
@@ -17,7 +17,7 @@ export const sizes: SizeProps = {
|
|
|
17
17
|
},
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export const DEFAULT_SIZE =
|
|
20
|
+
export const DEFAULT_SIZE = 'desktop'
|
|
21
21
|
|
|
22
22
|
export interface ToolbarProps {
|
|
23
23
|
url: URL | Error | undefined
|
|
@@ -39,7 +39,7 @@ export function Toolbar(props: ToolbarProps) {
|
|
|
39
39
|
return (
|
|
40
40
|
<>
|
|
41
41
|
<textarea
|
|
42
|
-
style={{position:
|
|
42
|
+
style={{position: 'absolute', pointerEvents: 'none', opacity: 0}}
|
|
43
43
|
ref={input}
|
|
44
44
|
value={validUrl ? url.toString() : ''}
|
|
45
45
|
readOnly
|
|
@@ -49,6 +49,7 @@ export function Toolbar(props: ToolbarProps) {
|
|
|
49
49
|
<Flex align="center" gap={2}>
|
|
50
50
|
<Flex align="center" gap={1}>
|
|
51
51
|
<Tooltip
|
|
52
|
+
animate
|
|
52
53
|
content={
|
|
53
54
|
<Text size={1} style={{whiteSpace: 'nowrap'}}>
|
|
54
55
|
{iframeSize === 'mobile' ? 'Exit mobile preview' : 'Preview mobile viewport'}
|
|
@@ -71,6 +72,7 @@ export function Toolbar(props: ToolbarProps) {
|
|
|
71
72
|
<Flex align="center" gap={1}>
|
|
72
73
|
{reloadButton ? (
|
|
73
74
|
<Tooltip
|
|
75
|
+
animate
|
|
74
76
|
content={
|
|
75
77
|
<Text size={1} style={{whiteSpace: 'nowrap'}}>
|
|
76
78
|
{reloading ? 'Reloading…' : 'Reload'}
|
|
@@ -91,6 +93,7 @@ export function Toolbar(props: ToolbarProps) {
|
|
|
91
93
|
</Tooltip>
|
|
92
94
|
) : null}
|
|
93
95
|
<Tooltip
|
|
96
|
+
animate
|
|
94
97
|
content={
|
|
95
98
|
<Text size={1} style={{whiteSpace: 'nowrap'}}>
|
|
96
99
|
Copy URL
|
|
@@ -108,16 +111,26 @@ export function Toolbar(props: ToolbarProps) {
|
|
|
108
111
|
onClick={() => {
|
|
109
112
|
if (!input?.current?.value) return
|
|
110
113
|
|
|
111
|
-
copy(input.current.value)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
copy(input.current.value).then((copied) => {
|
|
115
|
+
if (copied) {
|
|
116
|
+
pushToast({
|
|
117
|
+
closable: true,
|
|
118
|
+
status: 'success',
|
|
119
|
+
title: 'The URL is copied to the clipboard',
|
|
120
|
+
})
|
|
121
|
+
} else {
|
|
122
|
+
pushToast({
|
|
123
|
+
closable: true,
|
|
124
|
+
status: 'error',
|
|
125
|
+
title: 'Failed to copy the URL to the clipboard',
|
|
126
|
+
})
|
|
127
|
+
}
|
|
116
128
|
})
|
|
117
129
|
}}
|
|
118
130
|
/>
|
|
119
131
|
</Tooltip>
|
|
120
132
|
<Tooltip
|
|
133
|
+
animate
|
|
121
134
|
content={
|
|
122
135
|
<Text size={1} style={{whiteSpace: 'nowrap'}}>
|
|
123
136
|
Open URL in a new tab
|
package/lib/index.cjs.js
DELETED