@particle-academy/react-fancy 5.53.1 → 5.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/dist/PdfViewer.types-BEk2Jq6p.d.ts +97 -0
- package/dist/PdfViewer.types-DyoUBa2g.d.cts +97 -0
- package/dist/chunk-7MDHCYEB.cjs +414 -0
- package/dist/chunk-7MDHCYEB.cjs.map +1 -0
- package/dist/chunk-MORXQ5UM.js +412 -0
- package/dist/chunk-MORXQ5UM.js.map +1 -0
- package/dist/{chunk-D4QOV56U.js → chunk-MTTRPPHH.js} +3 -3
- package/dist/{chunk-D4QOV56U.js.map → chunk-MTTRPPHH.js.map} +1 -1
- package/dist/{chunk-E4TRDGSU.cjs → chunk-SLCR7A6W.cjs} +4 -4
- package/dist/{chunk-E4TRDGSU.cjs.map → chunk-SLCR7A6W.cjs.map} +1 -1
- package/dist/{index-AesVUjQE.d.cts → index-Bd4br4sF.d.cts} +1 -1
- package/dist/{index-D3wJ8hrZ.d.ts → index-Bwrc9ktU.d.ts} +1 -1
- package/dist/index.cjs +5 -5
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/media-viewer.cjs +3 -3
- package/dist/media-viewer.d.cts +2 -2
- package/dist/media-viewer.d.ts +2 -2
- package/dist/media-viewer.js +2 -2
- package/dist/pdf-viewer.cjs +2 -2
- package/dist/pdf-viewer.d.cts +13 -1
- package/dist/pdf-viewer.d.ts +13 -1
- package/dist/pdf-viewer.js +1 -1
- package/docs/PdfViewer.md +106 -4
- package/package.json +1 -1
- package/dist/PdfViewer.types-Bgn9EmZT.d.cts +0 -22
- package/dist/PdfViewer.types-xnPpdjJa.d.ts +0 -22
- package/dist/chunk-HRH5BIYG.js +0 -56
- package/dist/chunk-HRH5BIYG.js.map +0 -1
- package/dist/chunk-XM3W5ETT.cjs +0 -58
- package/dist/chunk-XM3W5ETT.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/media-type.ts","../src/components/MediaViewer/MediaFallback.tsx","../src/components/MediaViewer/MediaViewer.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-D4QOV56U.js","sourcesContent":["/**\n * Resolve what kind of media a source is, from its MIME type (preferred) or its\n * URL — a file extension, or the type embedded in a `data:` URI.\n *\n * Shared by `<MediaViewer>` to pick the right per-type viewer, and exported so\n * downstream packages (e.g. fancy-code's file viewer) can make the same\n * text-vs-media decision without re-deriving the table.\n */\n\nexport type MediaKind = \"image\" | \"video\" | \"audio\" | \"pdf\" | \"unknown\";\n\nexport interface ResolveMediaTypeInput {\n /** MIME type — preferred when known (e.g. `\"image/png\"`, `\"video/mp4\"`). */\n mime?: string | null;\n /**\n * Source URL — used to sniff the kind from a file extension, or from the type\n * embedded in a `data:` URI, when no `mime` is given. `http(s):` / `data:` /\n * `blob:` are all accepted (a bare `blob:` URL carries no type, so pass\n * `mime` alongside it).\n */\n src?: string | null;\n}\n\nconst IMAGE_EXTS = new Set([\n \"png\", \"jpg\", \"jpeg\", \"jfif\", \"pjpeg\", \"gif\", \"webp\", \"avif\", \"bmp\", \"ico\",\n \"cur\", \"svg\", \"svgz\", \"apng\", \"tif\", \"tiff\", \"heic\", \"heif\",\n]);\nconst VIDEO_EXTS = new Set([\n \"mp4\", \"m4v\", \"webm\", \"ogv\", \"ogm\", \"mov\", \"mkv\", \"avi\", \"wmv\", \"flv\", \"3gp\",\n \"3g2\", \"mpg\", \"mpeg\",\n]);\nconst AUDIO_EXTS = new Set([\n \"mp3\", \"wav\", \"wave\", \"ogg\", \"oga\", \"m4a\", \"m4b\", \"aac\", \"flac\", \"opus\",\n \"weba\", \"mid\", \"midi\", \"aiff\", \"aif\",\n]);\n\n/** Map a (possibly parameterized) MIME type to a media kind. */\nfunction mimeToKind(mime: string): MediaKind {\n // Strip any parameters (`; charset=…`) and normalize.\n const m = mime.toLowerCase().split(\";\")[0].trim();\n if (!m) return \"unknown\";\n if (m === \"application/pdf\" || m === \"application/x-pdf\") return \"pdf\";\n if (m.startsWith(\"image/\")) return \"image\";\n if (m.startsWith(\"video/\")) return \"video\";\n if (m.startsWith(\"audio/\")) return \"audio\";\n // `application/ogg` is audio in practice; treat it as such.\n if (m === \"application/ogg\") return \"audio\";\n return \"unknown\";\n}\n\n/** Map a bare file extension (no leading dot) to a media kind. */\nfunction extToKind(ext: string): MediaKind {\n const e = ext.toLowerCase();\n if (e === \"pdf\") return \"pdf\";\n if (IMAGE_EXTS.has(e)) return \"image\";\n if (VIDEO_EXTS.has(e)) return \"video\";\n if (AUDIO_EXTS.has(e)) return \"audio\";\n return \"unknown\";\n}\n\n/** Pull the file extension out of a URL, ignoring its query/hash. */\nfunction extFromSrc(src: string): string | null {\n const clean = src.split(/[?#]/, 1)[0];\n const lastSeg = clean.split(\"/\").pop() ?? \"\";\n const dot = lastSeg.lastIndexOf(\".\");\n if (dot <= 0 || dot === lastSeg.length - 1) return null;\n return lastSeg.slice(dot + 1);\n}\n\n/** Extract the MIME type embedded in a `data:` URI, if present. */\nfunction mimeFromDataUri(src: string): string | null {\n if (!/^data:/i.test(src)) return null;\n const header = src.slice(5).split(\",\", 1)[0]; // text after `data:`, before the comma\n const mt = header.split(\";\")[0].trim();\n return mt || null;\n}\n\n/**\n * Resolve a {@link MediaKind} from a MIME type and/or source URL. MIME wins\n * when it's conclusive; otherwise the `src` is sniffed (a `data:` URI's\n * embedded type first, then the file extension). Returns `\"unknown\"` when\n * nothing matches — callers treat that as \"not previewable media\" (e.g. text).\n */\nexport function resolveMediaType({ mime, src }: ResolveMediaTypeInput): MediaKind {\n if (mime) {\n const k = mimeToKind(mime);\n if (k !== \"unknown\") return k;\n }\n if (src) {\n const dataMime = mimeFromDataUri(src);\n if (dataMime) {\n const k = mimeToKind(dataMime);\n if (k !== \"unknown\") return k;\n }\n const ext = extFromSrc(src);\n if (ext) return extToKind(ext);\n }\n return \"unknown\";\n}\n","import { cn } from \"../../utils/cn\";\n\ninterface MediaFallbackProps {\n src: string;\n mime?: string;\n label?: string;\n className?: string;\n}\n\n/** Filename guess from a URL, ignoring query/hash and `data:`/`blob:` URLs. */\nfunction basename(src: string): string | null {\n if (/^(data|blob):/i.test(src)) return null;\n const seg = src.split(/[?#]/, 1)[0].split(\"/\").pop();\n return seg ? decodeURIComponent(seg) : null;\n}\n\n/**\n * Shown by `<MediaViewer>` when a source isn't a previewable media type — a\n * small themed card naming the file and offering a download.\n */\nexport function MediaFallback({ src, mime, label, className }: MediaFallbackProps) {\n const name = label || basename(src);\n return (\n <div\n data-react-fancy-media-fallback=\"\"\n className={cn(\n \"flex flex-col items-center justify-center gap-2 rounded-lg border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-6 text-center dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n <span className=\"text-sm font-medium text-zinc-700 dark:text-zinc-200\">\n No preview available\n </span>\n {(name || mime) && (\n <span className=\"max-w-full truncate text-xs text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\">\n {name}\n {name && mime ? \" · \" : \"\"}\n {mime}\n </span>\n )}\n <a\n href={src}\n download={name ?? undefined}\n className=\"text-xs font-medium text-blue-600 hover:underline dark:text-blue-400\"\n >\n Download\n </a>\n </div>\n );\n}\n","import { forwardRef } from \"react\";\nimport { resolveMediaType } from \"../../utils/media-type\";\nimport { ImageViewer } from \"../ImageViewer\";\nimport { VideoViewer } from \"../VideoViewer\";\nimport { AudioViewer } from \"../AudioViewer\";\nimport { PdfViewer } from \"../PdfViewer\";\nimport { MediaFallback } from \"./MediaFallback\";\nimport type { MediaViewerProps } from \"./MediaViewer.types\";\n\n/**\n * Renders the right viewer for a media file, picked from its `mime` (preferred)\n * or `src` — image, video, audio, or PDF — and a download fallback for anything\n * else. SVG renders through `<ImageViewer>`. The single entry point for showing\n * a file from a tree/workspace when you don't know its type ahead of time.\n *\n * ```tsx\n * <MediaViewer src={url} mime=\"image/png\" alt=\"logo.png\" style={{ height: 320 }} />\n * ```\n */\nexport const MediaViewer = forwardRef<HTMLDivElement, MediaViewerProps>(\n (\n {\n src,\n mime,\n alt,\n kind,\n imageProps,\n videoProps,\n audioProps,\n pdfProps,\n fallback,\n onError,\n className,\n style,\n },\n ref,\n ) => {\n const resolved = kind ?? resolveMediaType({ mime, src });\n\n switch (resolved) {\n case \"image\":\n return (\n <ImageViewer\n ref={ref}\n src={src}\n alt={alt ?? \"\"}\n onError={onError}\n className={className}\n style={style}\n {...imageProps}\n />\n );\n case \"video\":\n return (\n <VideoViewer\n ref={ref}\n src={src}\n onError={onError}\n className={className}\n style={style}\n {...videoProps}\n />\n );\n case \"audio\":\n return (\n <AudioViewer\n ref={ref}\n src={src}\n title={alt}\n onError={onError}\n className={className}\n style={style}\n {...audioProps}\n />\n );\n case \"pdf\":\n return (\n <PdfViewer\n ref={ref}\n src={src}\n title={alt}\n className={className}\n style={style}\n {...pdfProps}\n />\n );\n default:\n return (\n <div\n ref={ref}\n data-react-fancy-media-viewer=\"\"\n className={className}\n style={style}\n >\n {fallback ?? <MediaFallback src={src} mime={mime} label={alt} />}\n </div>\n );\n }\n },\n);\n\nMediaViewer.displayName = \"MediaViewer\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/media-type.ts","../src/components/MediaViewer/MediaFallback.tsx","../src/components/MediaViewer/MediaViewer.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-MTTRPPHH.js","sourcesContent":["/**\n * Resolve what kind of media a source is, from its MIME type (preferred) or its\n * URL — a file extension, or the type embedded in a `data:` URI.\n *\n * Shared by `<MediaViewer>` to pick the right per-type viewer, and exported so\n * downstream packages (e.g. fancy-code's file viewer) can make the same\n * text-vs-media decision without re-deriving the table.\n */\n\nexport type MediaKind = \"image\" | \"video\" | \"audio\" | \"pdf\" | \"unknown\";\n\nexport interface ResolveMediaTypeInput {\n /** MIME type — preferred when known (e.g. `\"image/png\"`, `\"video/mp4\"`). */\n mime?: string | null;\n /**\n * Source URL — used to sniff the kind from a file extension, or from the type\n * embedded in a `data:` URI, when no `mime` is given. `http(s):` / `data:` /\n * `blob:` are all accepted (a bare `blob:` URL carries no type, so pass\n * `mime` alongside it).\n */\n src?: string | null;\n}\n\nconst IMAGE_EXTS = new Set([\n \"png\", \"jpg\", \"jpeg\", \"jfif\", \"pjpeg\", \"gif\", \"webp\", \"avif\", \"bmp\", \"ico\",\n \"cur\", \"svg\", \"svgz\", \"apng\", \"tif\", \"tiff\", \"heic\", \"heif\",\n]);\nconst VIDEO_EXTS = new Set([\n \"mp4\", \"m4v\", \"webm\", \"ogv\", \"ogm\", \"mov\", \"mkv\", \"avi\", \"wmv\", \"flv\", \"3gp\",\n \"3g2\", \"mpg\", \"mpeg\",\n]);\nconst AUDIO_EXTS = new Set([\n \"mp3\", \"wav\", \"wave\", \"ogg\", \"oga\", \"m4a\", \"m4b\", \"aac\", \"flac\", \"opus\",\n \"weba\", \"mid\", \"midi\", \"aiff\", \"aif\",\n]);\n\n/** Map a (possibly parameterized) MIME type to a media kind. */\nfunction mimeToKind(mime: string): MediaKind {\n // Strip any parameters (`; charset=…`) and normalize.\n const m = mime.toLowerCase().split(\";\")[0].trim();\n if (!m) return \"unknown\";\n if (m === \"application/pdf\" || m === \"application/x-pdf\") return \"pdf\";\n if (m.startsWith(\"image/\")) return \"image\";\n if (m.startsWith(\"video/\")) return \"video\";\n if (m.startsWith(\"audio/\")) return \"audio\";\n // `application/ogg` is audio in practice; treat it as such.\n if (m === \"application/ogg\") return \"audio\";\n return \"unknown\";\n}\n\n/** Map a bare file extension (no leading dot) to a media kind. */\nfunction extToKind(ext: string): MediaKind {\n const e = ext.toLowerCase();\n if (e === \"pdf\") return \"pdf\";\n if (IMAGE_EXTS.has(e)) return \"image\";\n if (VIDEO_EXTS.has(e)) return \"video\";\n if (AUDIO_EXTS.has(e)) return \"audio\";\n return \"unknown\";\n}\n\n/** Pull the file extension out of a URL, ignoring its query/hash. */\nfunction extFromSrc(src: string): string | null {\n const clean = src.split(/[?#]/, 1)[0];\n const lastSeg = clean.split(\"/\").pop() ?? \"\";\n const dot = lastSeg.lastIndexOf(\".\");\n if (dot <= 0 || dot === lastSeg.length - 1) return null;\n return lastSeg.slice(dot + 1);\n}\n\n/** Extract the MIME type embedded in a `data:` URI, if present. */\nfunction mimeFromDataUri(src: string): string | null {\n if (!/^data:/i.test(src)) return null;\n const header = src.slice(5).split(\",\", 1)[0]; // text after `data:`, before the comma\n const mt = header.split(\";\")[0].trim();\n return mt || null;\n}\n\n/**\n * Resolve a {@link MediaKind} from a MIME type and/or source URL. MIME wins\n * when it's conclusive; otherwise the `src` is sniffed (a `data:` URI's\n * embedded type first, then the file extension). Returns `\"unknown\"` when\n * nothing matches — callers treat that as \"not previewable media\" (e.g. text).\n */\nexport function resolveMediaType({ mime, src }: ResolveMediaTypeInput): MediaKind {\n if (mime) {\n const k = mimeToKind(mime);\n if (k !== \"unknown\") return k;\n }\n if (src) {\n const dataMime = mimeFromDataUri(src);\n if (dataMime) {\n const k = mimeToKind(dataMime);\n if (k !== \"unknown\") return k;\n }\n const ext = extFromSrc(src);\n if (ext) return extToKind(ext);\n }\n return \"unknown\";\n}\n","import { cn } from \"../../utils/cn\";\n\ninterface MediaFallbackProps {\n src: string;\n mime?: string;\n label?: string;\n className?: string;\n}\n\n/** Filename guess from a URL, ignoring query/hash and `data:`/`blob:` URLs. */\nfunction basename(src: string): string | null {\n if (/^(data|blob):/i.test(src)) return null;\n const seg = src.split(/[?#]/, 1)[0].split(\"/\").pop();\n return seg ? decodeURIComponent(seg) : null;\n}\n\n/**\n * Shown by `<MediaViewer>` when a source isn't a previewable media type — a\n * small themed card naming the file and offering a download.\n */\nexport function MediaFallback({ src, mime, label, className }: MediaFallbackProps) {\n const name = label || basename(src);\n return (\n <div\n data-react-fancy-media-fallback=\"\"\n className={cn(\n \"flex flex-col items-center justify-center gap-2 rounded-lg border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-6 text-center dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n <span className=\"text-sm font-medium text-zinc-700 dark:text-zinc-200\">\n No preview available\n </span>\n {(name || mime) && (\n <span className=\"max-w-full truncate text-xs text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\">\n {name}\n {name && mime ? \" · \" : \"\"}\n {mime}\n </span>\n )}\n <a\n href={src}\n download={name ?? undefined}\n className=\"text-xs font-medium text-blue-600 hover:underline dark:text-blue-400\"\n >\n Download\n </a>\n </div>\n );\n}\n","import { forwardRef } from \"react\";\nimport { resolveMediaType } from \"../../utils/media-type\";\nimport { ImageViewer } from \"../ImageViewer\";\nimport { VideoViewer } from \"../VideoViewer\";\nimport { AudioViewer } from \"../AudioViewer\";\nimport { PdfViewer } from \"../PdfViewer\";\nimport { MediaFallback } from \"./MediaFallback\";\nimport type { MediaViewerProps } from \"./MediaViewer.types\";\n\n/**\n * Renders the right viewer for a media file, picked from its `mime` (preferred)\n * or `src` — image, video, audio, or PDF — and a download fallback for anything\n * else. SVG renders through `<ImageViewer>`. The single entry point for showing\n * a file from a tree/workspace when you don't know its type ahead of time.\n *\n * ```tsx\n * <MediaViewer src={url} mime=\"image/png\" alt=\"logo.png\" style={{ height: 320 }} />\n * ```\n */\nexport const MediaViewer = forwardRef<HTMLDivElement, MediaViewerProps>(\n (\n {\n src,\n mime,\n alt,\n kind,\n imageProps,\n videoProps,\n audioProps,\n pdfProps,\n fallback,\n onError,\n className,\n style,\n },\n ref,\n ) => {\n const resolved = kind ?? resolveMediaType({ mime, src });\n\n switch (resolved) {\n case \"image\":\n return (\n <ImageViewer\n ref={ref}\n src={src}\n alt={alt ?? \"\"}\n onError={onError}\n className={className}\n style={style}\n {...imageProps}\n />\n );\n case \"video\":\n return (\n <VideoViewer\n ref={ref}\n src={src}\n onError={onError}\n className={className}\n style={style}\n {...videoProps}\n />\n );\n case \"audio\":\n return (\n <AudioViewer\n ref={ref}\n src={src}\n title={alt}\n onError={onError}\n className={className}\n style={style}\n {...audioProps}\n />\n );\n case \"pdf\":\n return (\n <PdfViewer\n ref={ref}\n src={src}\n title={alt}\n className={className}\n style={style}\n {...pdfProps}\n />\n );\n default:\n return (\n <div\n ref={ref}\n data-react-fancy-media-viewer=\"\"\n className={className}\n style={style}\n >\n {fallback ?? <MediaFallback src={src} mime={mime} label={alt} />}\n </div>\n );\n }\n },\n);\n\nMediaViewer.displayName = \"MediaViewer\";\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkTH7VP4CL_cjs = require('./chunk-TH7VP4CL.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunk7MDHCYEB_cjs = require('./chunk-7MDHCYEB.cjs');
|
|
5
5
|
var chunk7QENPLOP_cjs = require('./chunk-7QENPLOP.cjs');
|
|
6
6
|
var chunkKE4XURZD_cjs = require('./chunk-KE4XURZD.cjs');
|
|
7
7
|
var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
|
|
@@ -201,7 +201,7 @@ var MediaViewer = react.forwardRef(
|
|
|
201
201
|
);
|
|
202
202
|
case "pdf":
|
|
203
203
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
204
|
-
|
|
204
|
+
chunk7MDHCYEB_cjs.PdfViewer,
|
|
205
205
|
{
|
|
206
206
|
ref,
|
|
207
207
|
src,
|
|
@@ -229,5 +229,5 @@ MediaViewer.displayName = "MediaViewer";
|
|
|
229
229
|
|
|
230
230
|
exports.MediaViewer = MediaViewer;
|
|
231
231
|
exports.resolveMediaType = resolveMediaType;
|
|
232
|
-
//# sourceMappingURL=chunk-
|
|
233
|
-
//# sourceMappingURL=chunk-
|
|
232
|
+
//# sourceMappingURL=chunk-SLCR7A6W.cjs.map
|
|
233
|
+
//# sourceMappingURL=chunk-SLCR7A6W.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/media-type.ts","../src/components/MediaViewer/MediaFallback.tsx","../src/components/MediaViewer/MediaViewer.tsx"],"names":["jsxs","cn","jsx","forwardRef","ImageViewer","VideoViewer","AudioViewer","PdfViewer"],"mappings":"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","file":"chunk-E4TRDGSU.cjs","sourcesContent":["/**\n * Resolve what kind of media a source is, from its MIME type (preferred) or its\n * URL — a file extension, or the type embedded in a `data:` URI.\n *\n * Shared by `<MediaViewer>` to pick the right per-type viewer, and exported so\n * downstream packages (e.g. fancy-code's file viewer) can make the same\n * text-vs-media decision without re-deriving the table.\n */\n\nexport type MediaKind = \"image\" | \"video\" | \"audio\" | \"pdf\" | \"unknown\";\n\nexport interface ResolveMediaTypeInput {\n /** MIME type — preferred when known (e.g. `\"image/png\"`, `\"video/mp4\"`). */\n mime?: string | null;\n /**\n * Source URL — used to sniff the kind from a file extension, or from the type\n * embedded in a `data:` URI, when no `mime` is given. `http(s):` / `data:` /\n * `blob:` are all accepted (a bare `blob:` URL carries no type, so pass\n * `mime` alongside it).\n */\n src?: string | null;\n}\n\nconst IMAGE_EXTS = new Set([\n \"png\", \"jpg\", \"jpeg\", \"jfif\", \"pjpeg\", \"gif\", \"webp\", \"avif\", \"bmp\", \"ico\",\n \"cur\", \"svg\", \"svgz\", \"apng\", \"tif\", \"tiff\", \"heic\", \"heif\",\n]);\nconst VIDEO_EXTS = new Set([\n \"mp4\", \"m4v\", \"webm\", \"ogv\", \"ogm\", \"mov\", \"mkv\", \"avi\", \"wmv\", \"flv\", \"3gp\",\n \"3g2\", \"mpg\", \"mpeg\",\n]);\nconst AUDIO_EXTS = new Set([\n \"mp3\", \"wav\", \"wave\", \"ogg\", \"oga\", \"m4a\", \"m4b\", \"aac\", \"flac\", \"opus\",\n \"weba\", \"mid\", \"midi\", \"aiff\", \"aif\",\n]);\n\n/** Map a (possibly parameterized) MIME type to a media kind. */\nfunction mimeToKind(mime: string): MediaKind {\n // Strip any parameters (`; charset=…`) and normalize.\n const m = mime.toLowerCase().split(\";\")[0].trim();\n if (!m) return \"unknown\";\n if (m === \"application/pdf\" || m === \"application/x-pdf\") return \"pdf\";\n if (m.startsWith(\"image/\")) return \"image\";\n if (m.startsWith(\"video/\")) return \"video\";\n if (m.startsWith(\"audio/\")) return \"audio\";\n // `application/ogg` is audio in practice; treat it as such.\n if (m === \"application/ogg\") return \"audio\";\n return \"unknown\";\n}\n\n/** Map a bare file extension (no leading dot) to a media kind. */\nfunction extToKind(ext: string): MediaKind {\n const e = ext.toLowerCase();\n if (e === \"pdf\") return \"pdf\";\n if (IMAGE_EXTS.has(e)) return \"image\";\n if (VIDEO_EXTS.has(e)) return \"video\";\n if (AUDIO_EXTS.has(e)) return \"audio\";\n return \"unknown\";\n}\n\n/** Pull the file extension out of a URL, ignoring its query/hash. */\nfunction extFromSrc(src: string): string | null {\n const clean = src.split(/[?#]/, 1)[0];\n const lastSeg = clean.split(\"/\").pop() ?? \"\";\n const dot = lastSeg.lastIndexOf(\".\");\n if (dot <= 0 || dot === lastSeg.length - 1) return null;\n return lastSeg.slice(dot + 1);\n}\n\n/** Extract the MIME type embedded in a `data:` URI, if present. */\nfunction mimeFromDataUri(src: string): string | null {\n if (!/^data:/i.test(src)) return null;\n const header = src.slice(5).split(\",\", 1)[0]; // text after `data:`, before the comma\n const mt = header.split(\";\")[0].trim();\n return mt || null;\n}\n\n/**\n * Resolve a {@link MediaKind} from a MIME type and/or source URL. MIME wins\n * when it's conclusive; otherwise the `src` is sniffed (a `data:` URI's\n * embedded type first, then the file extension). Returns `\"unknown\"` when\n * nothing matches — callers treat that as \"not previewable media\" (e.g. text).\n */\nexport function resolveMediaType({ mime, src }: ResolveMediaTypeInput): MediaKind {\n if (mime) {\n const k = mimeToKind(mime);\n if (k !== \"unknown\") return k;\n }\n if (src) {\n const dataMime = mimeFromDataUri(src);\n if (dataMime) {\n const k = mimeToKind(dataMime);\n if (k !== \"unknown\") return k;\n }\n const ext = extFromSrc(src);\n if (ext) return extToKind(ext);\n }\n return \"unknown\";\n}\n","import { cn } from \"../../utils/cn\";\n\ninterface MediaFallbackProps {\n src: string;\n mime?: string;\n label?: string;\n className?: string;\n}\n\n/** Filename guess from a URL, ignoring query/hash and `data:`/`blob:` URLs. */\nfunction basename(src: string): string | null {\n if (/^(data|blob):/i.test(src)) return null;\n const seg = src.split(/[?#]/, 1)[0].split(\"/\").pop();\n return seg ? decodeURIComponent(seg) : null;\n}\n\n/**\n * Shown by `<MediaViewer>` when a source isn't a previewable media type — a\n * small themed card naming the file and offering a download.\n */\nexport function MediaFallback({ src, mime, label, className }: MediaFallbackProps) {\n const name = label || basename(src);\n return (\n <div\n data-react-fancy-media-fallback=\"\"\n className={cn(\n \"flex flex-col items-center justify-center gap-2 rounded-lg border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-6 text-center dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n <span className=\"text-sm font-medium text-zinc-700 dark:text-zinc-200\">\n No preview available\n </span>\n {(name || mime) && (\n <span className=\"max-w-full truncate text-xs text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\">\n {name}\n {name && mime ? \" · \" : \"\"}\n {mime}\n </span>\n )}\n <a\n href={src}\n download={name ?? undefined}\n className=\"text-xs font-medium text-blue-600 hover:underline dark:text-blue-400\"\n >\n Download\n </a>\n </div>\n );\n}\n","import { forwardRef } from \"react\";\nimport { resolveMediaType } from \"../../utils/media-type\";\nimport { ImageViewer } from \"../ImageViewer\";\nimport { VideoViewer } from \"../VideoViewer\";\nimport { AudioViewer } from \"../AudioViewer\";\nimport { PdfViewer } from \"../PdfViewer\";\nimport { MediaFallback } from \"./MediaFallback\";\nimport type { MediaViewerProps } from \"./MediaViewer.types\";\n\n/**\n * Renders the right viewer for a media file, picked from its `mime` (preferred)\n * or `src` — image, video, audio, or PDF — and a download fallback for anything\n * else. SVG renders through `<ImageViewer>`. The single entry point for showing\n * a file from a tree/workspace when you don't know its type ahead of time.\n *\n * ```tsx\n * <MediaViewer src={url} mime=\"image/png\" alt=\"logo.png\" style={{ height: 320 }} />\n * ```\n */\nexport const MediaViewer = forwardRef<HTMLDivElement, MediaViewerProps>(\n (\n {\n src,\n mime,\n alt,\n kind,\n imageProps,\n videoProps,\n audioProps,\n pdfProps,\n fallback,\n onError,\n className,\n style,\n },\n ref,\n ) => {\n const resolved = kind ?? resolveMediaType({ mime, src });\n\n switch (resolved) {\n case \"image\":\n return (\n <ImageViewer\n ref={ref}\n src={src}\n alt={alt ?? \"\"}\n onError={onError}\n className={className}\n style={style}\n {...imageProps}\n />\n );\n case \"video\":\n return (\n <VideoViewer\n ref={ref}\n src={src}\n onError={onError}\n className={className}\n style={style}\n {...videoProps}\n />\n );\n case \"audio\":\n return (\n <AudioViewer\n ref={ref}\n src={src}\n title={alt}\n onError={onError}\n className={className}\n style={style}\n {...audioProps}\n />\n );\n case \"pdf\":\n return (\n <PdfViewer\n ref={ref}\n src={src}\n title={alt}\n className={className}\n style={style}\n {...pdfProps}\n />\n );\n default:\n return (\n <div\n ref={ref}\n data-react-fancy-media-viewer=\"\"\n className={className}\n style={style}\n >\n {fallback ?? <MediaFallback src={src} mime={mime} label={alt} />}\n </div>\n );\n }\n },\n);\n\nMediaViewer.displayName = \"MediaViewer\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/media-type.ts","../src/components/MediaViewer/MediaFallback.tsx","../src/components/MediaViewer/MediaViewer.tsx"],"names":["jsxs","cn","jsx","forwardRef","ImageViewer","VideoViewer","AudioViewer","PdfViewer"],"mappings":"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","file":"chunk-SLCR7A6W.cjs","sourcesContent":["/**\n * Resolve what kind of media a source is, from its MIME type (preferred) or its\n * URL — a file extension, or the type embedded in a `data:` URI.\n *\n * Shared by `<MediaViewer>` to pick the right per-type viewer, and exported so\n * downstream packages (e.g. fancy-code's file viewer) can make the same\n * text-vs-media decision without re-deriving the table.\n */\n\nexport type MediaKind = \"image\" | \"video\" | \"audio\" | \"pdf\" | \"unknown\";\n\nexport interface ResolveMediaTypeInput {\n /** MIME type — preferred when known (e.g. `\"image/png\"`, `\"video/mp4\"`). */\n mime?: string | null;\n /**\n * Source URL — used to sniff the kind from a file extension, or from the type\n * embedded in a `data:` URI, when no `mime` is given. `http(s):` / `data:` /\n * `blob:` are all accepted (a bare `blob:` URL carries no type, so pass\n * `mime` alongside it).\n */\n src?: string | null;\n}\n\nconst IMAGE_EXTS = new Set([\n \"png\", \"jpg\", \"jpeg\", \"jfif\", \"pjpeg\", \"gif\", \"webp\", \"avif\", \"bmp\", \"ico\",\n \"cur\", \"svg\", \"svgz\", \"apng\", \"tif\", \"tiff\", \"heic\", \"heif\",\n]);\nconst VIDEO_EXTS = new Set([\n \"mp4\", \"m4v\", \"webm\", \"ogv\", \"ogm\", \"mov\", \"mkv\", \"avi\", \"wmv\", \"flv\", \"3gp\",\n \"3g2\", \"mpg\", \"mpeg\",\n]);\nconst AUDIO_EXTS = new Set([\n \"mp3\", \"wav\", \"wave\", \"ogg\", \"oga\", \"m4a\", \"m4b\", \"aac\", \"flac\", \"opus\",\n \"weba\", \"mid\", \"midi\", \"aiff\", \"aif\",\n]);\n\n/** Map a (possibly parameterized) MIME type to a media kind. */\nfunction mimeToKind(mime: string): MediaKind {\n // Strip any parameters (`; charset=…`) and normalize.\n const m = mime.toLowerCase().split(\";\")[0].trim();\n if (!m) return \"unknown\";\n if (m === \"application/pdf\" || m === \"application/x-pdf\") return \"pdf\";\n if (m.startsWith(\"image/\")) return \"image\";\n if (m.startsWith(\"video/\")) return \"video\";\n if (m.startsWith(\"audio/\")) return \"audio\";\n // `application/ogg` is audio in practice; treat it as such.\n if (m === \"application/ogg\") return \"audio\";\n return \"unknown\";\n}\n\n/** Map a bare file extension (no leading dot) to a media kind. */\nfunction extToKind(ext: string): MediaKind {\n const e = ext.toLowerCase();\n if (e === \"pdf\") return \"pdf\";\n if (IMAGE_EXTS.has(e)) return \"image\";\n if (VIDEO_EXTS.has(e)) return \"video\";\n if (AUDIO_EXTS.has(e)) return \"audio\";\n return \"unknown\";\n}\n\n/** Pull the file extension out of a URL, ignoring its query/hash. */\nfunction extFromSrc(src: string): string | null {\n const clean = src.split(/[?#]/, 1)[0];\n const lastSeg = clean.split(\"/\").pop() ?? \"\";\n const dot = lastSeg.lastIndexOf(\".\");\n if (dot <= 0 || dot === lastSeg.length - 1) return null;\n return lastSeg.slice(dot + 1);\n}\n\n/** Extract the MIME type embedded in a `data:` URI, if present. */\nfunction mimeFromDataUri(src: string): string | null {\n if (!/^data:/i.test(src)) return null;\n const header = src.slice(5).split(\",\", 1)[0]; // text after `data:`, before the comma\n const mt = header.split(\";\")[0].trim();\n return mt || null;\n}\n\n/**\n * Resolve a {@link MediaKind} from a MIME type and/or source URL. MIME wins\n * when it's conclusive; otherwise the `src` is sniffed (a `data:` URI's\n * embedded type first, then the file extension). Returns `\"unknown\"` when\n * nothing matches — callers treat that as \"not previewable media\" (e.g. text).\n */\nexport function resolveMediaType({ mime, src }: ResolveMediaTypeInput): MediaKind {\n if (mime) {\n const k = mimeToKind(mime);\n if (k !== \"unknown\") return k;\n }\n if (src) {\n const dataMime = mimeFromDataUri(src);\n if (dataMime) {\n const k = mimeToKind(dataMime);\n if (k !== \"unknown\") return k;\n }\n const ext = extFromSrc(src);\n if (ext) return extToKind(ext);\n }\n return \"unknown\";\n}\n","import { cn } from \"../../utils/cn\";\n\ninterface MediaFallbackProps {\n src: string;\n mime?: string;\n label?: string;\n className?: string;\n}\n\n/** Filename guess from a URL, ignoring query/hash and `data:`/`blob:` URLs. */\nfunction basename(src: string): string | null {\n if (/^(data|blob):/i.test(src)) return null;\n const seg = src.split(/[?#]/, 1)[0].split(\"/\").pop();\n return seg ? decodeURIComponent(seg) : null;\n}\n\n/**\n * Shown by `<MediaViewer>` when a source isn't a previewable media type — a\n * small themed card naming the file and offering a download.\n */\nexport function MediaFallback({ src, mime, label, className }: MediaFallbackProps) {\n const name = label || basename(src);\n return (\n <div\n data-react-fancy-media-fallback=\"\"\n className={cn(\n \"flex flex-col items-center justify-center gap-2 rounded-lg border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-6 text-center dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n <span className=\"text-sm font-medium text-zinc-700 dark:text-zinc-200\">\n No preview available\n </span>\n {(name || mime) && (\n <span className=\"max-w-full truncate text-xs text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\">\n {name}\n {name && mime ? \" · \" : \"\"}\n {mime}\n </span>\n )}\n <a\n href={src}\n download={name ?? undefined}\n className=\"text-xs font-medium text-blue-600 hover:underline dark:text-blue-400\"\n >\n Download\n </a>\n </div>\n );\n}\n","import { forwardRef } from \"react\";\nimport { resolveMediaType } from \"../../utils/media-type\";\nimport { ImageViewer } from \"../ImageViewer\";\nimport { VideoViewer } from \"../VideoViewer\";\nimport { AudioViewer } from \"../AudioViewer\";\nimport { PdfViewer } from \"../PdfViewer\";\nimport { MediaFallback } from \"./MediaFallback\";\nimport type { MediaViewerProps } from \"./MediaViewer.types\";\n\n/**\n * Renders the right viewer for a media file, picked from its `mime` (preferred)\n * or `src` — image, video, audio, or PDF — and a download fallback for anything\n * else. SVG renders through `<ImageViewer>`. The single entry point for showing\n * a file from a tree/workspace when you don't know its type ahead of time.\n *\n * ```tsx\n * <MediaViewer src={url} mime=\"image/png\" alt=\"logo.png\" style={{ height: 320 }} />\n * ```\n */\nexport const MediaViewer = forwardRef<HTMLDivElement, MediaViewerProps>(\n (\n {\n src,\n mime,\n alt,\n kind,\n imageProps,\n videoProps,\n audioProps,\n pdfProps,\n fallback,\n onError,\n className,\n style,\n },\n ref,\n ) => {\n const resolved = kind ?? resolveMediaType({ mime, src });\n\n switch (resolved) {\n case \"image\":\n return (\n <ImageViewer\n ref={ref}\n src={src}\n alt={alt ?? \"\"}\n onError={onError}\n className={className}\n style={style}\n {...imageProps}\n />\n );\n case \"video\":\n return (\n <VideoViewer\n ref={ref}\n src={src}\n onError={onError}\n className={className}\n style={style}\n {...videoProps}\n />\n );\n case \"audio\":\n return (\n <AudioViewer\n ref={ref}\n src={src}\n title={alt}\n onError={onError}\n className={className}\n style={style}\n {...audioProps}\n />\n );\n case \"pdf\":\n return (\n <PdfViewer\n ref={ref}\n src={src}\n title={alt}\n className={className}\n style={style}\n {...pdfProps}\n />\n );\n default:\n return (\n <div\n ref={ref}\n data-react-fancy-media-viewer=\"\"\n className={className}\n style={style}\n >\n {fallback ?? <MediaFallback src={src} mime={mime} label={alt} />}\n </div>\n );\n }\n },\n);\n\nMediaViewer.displayName = \"MediaViewer\";\n"]}
|
|
@@ -3,7 +3,7 @@ import { ReactNode, CSSProperties } from 'react';
|
|
|
3
3
|
import { I as ImageViewerProps } from './ImageViewer.types-CtqaA6KV.cjs';
|
|
4
4
|
import { V as VideoViewerProps } from './VideoViewer.types-_AwQ8DQr.cjs';
|
|
5
5
|
import { A as AudioViewerProps } from './AudioViewer.types-CyhmQVQd.cjs';
|
|
6
|
-
import {
|
|
6
|
+
import { b as PdfViewerProps } from './PdfViewer.types-DyoUBa2g.cjs';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Resolve what kind of media a source is, from its MIME type (preferred) or its
|
|
@@ -3,7 +3,7 @@ import { ReactNode, CSSProperties } from 'react';
|
|
|
3
3
|
import { I as ImageViewerProps } from './ImageViewer.types-BDTxBYEN.js';
|
|
4
4
|
import { V as VideoViewerProps } from './VideoViewer.types-_AwQ8DQr.js';
|
|
5
5
|
import { A as AudioViewerProps } from './AudioViewer.types-CyhmQVQd.js';
|
|
6
|
-
import {
|
|
6
|
+
import { b as PdfViewerProps } from './PdfViewer.types-BEk2Jq6p.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Resolve what kind of media a source is, from its MIME type (preferred) or its
|
package/dist/index.cjs
CHANGED
|
@@ -59,9 +59,9 @@ var chunkP53432AK_cjs = require('./chunk-P53432AK.cjs');
|
|
|
59
59
|
var chunkQF7CD4JH_cjs = require('./chunk-QF7CD4JH.cjs');
|
|
60
60
|
require('./chunk-O3F6DYWR.cjs');
|
|
61
61
|
var chunkZVDW2VX5_cjs = require('./chunk-ZVDW2VX5.cjs');
|
|
62
|
-
var
|
|
62
|
+
var chunkSLCR7A6W_cjs = require('./chunk-SLCR7A6W.cjs');
|
|
63
63
|
var chunkTH7VP4CL_cjs = require('./chunk-TH7VP4CL.cjs');
|
|
64
|
-
var
|
|
64
|
+
var chunk7MDHCYEB_cjs = require('./chunk-7MDHCYEB.cjs');
|
|
65
65
|
var chunkLIVC3WUU_cjs = require('./chunk-LIVC3WUU.cjs');
|
|
66
66
|
var chunkG5DMYAWL_cjs = require('./chunk-G5DMYAWL.cjs');
|
|
67
67
|
var chunk2GFM5WD4_cjs = require('./chunk-2GFM5WD4.cjs');
|
|
@@ -538,11 +538,11 @@ Object.defineProperty(exports, "Marquee", {
|
|
|
538
538
|
});
|
|
539
539
|
Object.defineProperty(exports, "MediaViewer", {
|
|
540
540
|
enumerable: true,
|
|
541
|
-
get: function () { return
|
|
541
|
+
get: function () { return chunkSLCR7A6W_cjs.MediaViewer; }
|
|
542
542
|
});
|
|
543
543
|
Object.defineProperty(exports, "resolveMediaType", {
|
|
544
544
|
enumerable: true,
|
|
545
|
-
get: function () { return
|
|
545
|
+
get: function () { return chunkSLCR7A6W_cjs.resolveMediaType; }
|
|
546
546
|
});
|
|
547
547
|
Object.defineProperty(exports, "VideoViewer", {
|
|
548
548
|
enumerable: true,
|
|
@@ -550,7 +550,7 @@ Object.defineProperty(exports, "VideoViewer", {
|
|
|
550
550
|
});
|
|
551
551
|
Object.defineProperty(exports, "PdfViewer", {
|
|
552
552
|
enumerable: true,
|
|
553
|
-
get: function () { return
|
|
553
|
+
get: function () { return chunk7MDHCYEB_cjs.PdfViewer; }
|
|
554
554
|
});
|
|
555
555
|
Object.defineProperty(exports, "Eyebrow", {
|
|
556
556
|
enumerable: true,
|
package/dist/index.d.cts
CHANGED
|
@@ -82,7 +82,7 @@ export { MobileMenu, MobileMenuBottomBarProps, MobileMenuContextValue, MobileMen
|
|
|
82
82
|
export { Kanban, KanbanCardMoveHandler, KanbanCardProps, KanbanColumnHandleProps, KanbanColumnMoveHandler, KanbanColumnProps, KanbanContextValue, KanbanProps, useKanban } from './kanban.cjs';
|
|
83
83
|
export { DropPosition, TreeNav, TreeNavContextValue, TreeNavProps, TreeNodeData, TreeNodeProps, useTreeNav } from './tree-nav.cjs';
|
|
84
84
|
export { FileBrowser, FileBrowserContextValue, FileBrowserNewFolder, FileBrowserNodeProps, FileBrowserPathBarProps, FileBrowserProps, FileBrowserProvider, FileBrowserRow, FileBrowserToolbarProps, FileBrowserTreeProps, FileEntry, FileKind, FileLoadStatus, FileSelectMode, FileSnapshotNode, FileSort, FileSortDirection, FileSortField, useFileBrowser, validateFolderName } from './file-browser.cjs';
|
|
85
|
-
export { M as MediaKind, a as MediaViewer, b as MediaViewerProps, R as ResolveMediaTypeInput, r as resolveMediaType } from './index-
|
|
85
|
+
export { M as MediaKind, a as MediaViewer, b as MediaViewerProps, R as ResolveMediaTypeInput, r as resolveMediaType } from './index-Bd4br4sF.cjs';
|
|
86
86
|
export { F as FancyPlatform, P as PlatformHints, a as PromptAttachment, b as PromptCmd, c as PromptInput, d as PromptInputProps, e as PromptMention, f as browserPlatformHints, g as detectPlatform, m as modifierKeyLabel } from './index-BF5qsQur.cjs';
|
|
87
87
|
import { P as Placement } from './types-DJI492iY.cjs';
|
|
88
88
|
export { A as ActionColor, B as ButtonColor, C as Color, S as Size, V as Variant } from './types-DJI492iY.cjs';
|
|
@@ -99,7 +99,7 @@ export { V as VideoViewerProps } from './VideoViewer.types-_AwQ8DQr.cjs';
|
|
|
99
99
|
export { AudioViewer } from './audio-viewer.cjs';
|
|
100
100
|
export { A as AudioViewerProps } from './AudioViewer.types-CyhmQVQd.cjs';
|
|
101
101
|
export { PdfViewer } from './pdf-viewer.cjs';
|
|
102
|
-
export { P as PdfViewerProps } from './PdfViewer.types-
|
|
102
|
+
export { P as PdfPageSource, a as PdfViewerPolicy, b as PdfViewerProps, c as PdfViewerWatermark } from './PdfViewer.types-DyoUBa2g.cjs';
|
|
103
103
|
export { J as JSON_FIELD_TYPES, a as JsonArray, b as JsonEditor, c as JsonEditorActivity, d as JsonEditorEdit, e as JsonEditorIssue, f as JsonEditorNode, g as JsonEditorPendingEdit, h as JsonEditorProps, i as JsonFieldType, j as JsonKeyMapEntry, k as JsonKeyRule, l as JsonObject, m as JsonPath, n as JsonPrimitive, o as JsonValue, P as ParsedKeyMap, p as applyJsonEdit, q as describeEdit, r as findJsonConflicts, s as getAtPath, t as inferType, u as parseKeyMap, v as parsePath, w as pathToString, x as resolveKeyRule, y as typeMatches } from './index-CEb-loCl.cjs';
|
|
104
104
|
|
|
105
105
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export { MobileMenu, MobileMenuBottomBarProps, MobileMenuContextValue, MobileMen
|
|
|
82
82
|
export { Kanban, KanbanCardMoveHandler, KanbanCardProps, KanbanColumnHandleProps, KanbanColumnMoveHandler, KanbanColumnProps, KanbanContextValue, KanbanProps, useKanban } from './kanban.js';
|
|
83
83
|
export { DropPosition, TreeNav, TreeNavContextValue, TreeNavProps, TreeNodeData, TreeNodeProps, useTreeNav } from './tree-nav.js';
|
|
84
84
|
export { FileBrowser, FileBrowserContextValue, FileBrowserNewFolder, FileBrowserNodeProps, FileBrowserPathBarProps, FileBrowserProps, FileBrowserProvider, FileBrowserRow, FileBrowserToolbarProps, FileBrowserTreeProps, FileEntry, FileKind, FileLoadStatus, FileSelectMode, FileSnapshotNode, FileSort, FileSortDirection, FileSortField, useFileBrowser, validateFolderName } from './file-browser.js';
|
|
85
|
-
export { M as MediaKind, a as MediaViewer, b as MediaViewerProps, R as ResolveMediaTypeInput, r as resolveMediaType } from './index-
|
|
85
|
+
export { M as MediaKind, a as MediaViewer, b as MediaViewerProps, R as ResolveMediaTypeInput, r as resolveMediaType } from './index-Bwrc9ktU.js';
|
|
86
86
|
export { F as FancyPlatform, P as PlatformHints, a as PromptAttachment, b as PromptCmd, c as PromptInput, d as PromptInputProps, e as PromptMention, f as browserPlatformHints, g as detectPlatform, m as modifierKeyLabel } from './index-BZON-gXr.js';
|
|
87
87
|
import { P as Placement } from './types-DJI492iY.js';
|
|
88
88
|
export { A as ActionColor, B as ButtonColor, C as Color, S as Size, V as Variant } from './types-DJI492iY.js';
|
|
@@ -99,7 +99,7 @@ export { V as VideoViewerProps } from './VideoViewer.types-_AwQ8DQr.js';
|
|
|
99
99
|
export { AudioViewer } from './audio-viewer.js';
|
|
100
100
|
export { A as AudioViewerProps } from './AudioViewer.types-CyhmQVQd.js';
|
|
101
101
|
export { PdfViewer } from './pdf-viewer.js';
|
|
102
|
-
export { P as PdfViewerProps } from './PdfViewer.types-
|
|
102
|
+
export { P as PdfPageSource, a as PdfViewerPolicy, b as PdfViewerProps, c as PdfViewerWatermark } from './PdfViewer.types-BEk2Jq6p.js';
|
|
103
103
|
export { J as JSON_FIELD_TYPES, a as JsonArray, b as JsonEditor, c as JsonEditorActivity, d as JsonEditorEdit, e as JsonEditorIssue, f as JsonEditorNode, g as JsonEditorPendingEdit, h as JsonEditorProps, i as JsonFieldType, j as JsonKeyMapEntry, k as JsonKeyRule, l as JsonObject, m as JsonPath, n as JsonPrimitive, o as JsonValue, P as ParsedKeyMap, p as applyJsonEdit, q as describeEdit, r as findJsonConflicts, s as getAtPath, t as inferType, u as parseKeyMap, v as parsePath, w as pathToString, x as resolveKeyRule, y as typeMatches } from './index-DeAJbVOn.js';
|
|
104
104
|
|
|
105
105
|
/**
|
package/dist/index.js
CHANGED
|
@@ -57,9 +57,9 @@ export { DisplayValue } from './chunk-WX5XYDVN.js';
|
|
|
57
57
|
export { Field } from './chunk-5WQ6FPSP.js';
|
|
58
58
|
import './chunk-USWQAMI3.js';
|
|
59
59
|
export { Marquee } from './chunk-RSLZL6VP.js';
|
|
60
|
-
export { MediaViewer, resolveMediaType } from './chunk-
|
|
60
|
+
export { MediaViewer, resolveMediaType } from './chunk-MTTRPPHH.js';
|
|
61
61
|
export { VideoViewer } from './chunk-VOGI7GX3.js';
|
|
62
|
-
export { PdfViewer } from './chunk-
|
|
62
|
+
export { PdfViewer } from './chunk-MORXQ5UM.js';
|
|
63
63
|
export { Eyebrow } from './chunk-EQ7G5F6K.js';
|
|
64
64
|
export { FileBrowser, FileBrowserNewFolder, useFileBrowser, validateFolderName } from './chunk-XS3EIQFP.js';
|
|
65
65
|
export { FileUpload, useFileUpload } from './chunk-ZAX72LXL.js';
|
package/dist/media-viewer.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkSLCR7A6W_cjs = require('./chunk-SLCR7A6W.cjs');
|
|
4
4
|
require('./chunk-TH7VP4CL.cjs');
|
|
5
|
-
require('./chunk-
|
|
5
|
+
require('./chunk-7MDHCYEB.cjs');
|
|
6
6
|
require('./chunk-7QENPLOP.cjs');
|
|
7
7
|
require('./chunk-M5SEYDSS.cjs');
|
|
8
8
|
require('./chunk-T6YELZPJ.cjs');
|
|
@@ -14,7 +14,7 @@ require('./chunk-ZU5Q77OT.cjs');
|
|
|
14
14
|
|
|
15
15
|
Object.defineProperty(exports, "MediaViewer", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkSLCR7A6W_cjs.MediaViewer; }
|
|
18
18
|
});
|
|
19
19
|
//# sourceMappingURL=media-viewer.cjs.map
|
|
20
20
|
//# sourceMappingURL=media-viewer.cjs.map
|
package/dist/media-viewer.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { a as MediaViewer, b as MediaViewerProps } from './index-
|
|
1
|
+
export { a as MediaViewer, b as MediaViewerProps } from './index-Bd4br4sF.cjs';
|
|
2
2
|
import 'react';
|
|
3
3
|
import './ImageViewer.types-CtqaA6KV.cjs';
|
|
4
4
|
import './FauxClient.types-Dtk9aRs6.cjs';
|
|
5
5
|
import './VideoViewer.types-_AwQ8DQr.cjs';
|
|
6
6
|
import './AudioViewer.types-CyhmQVQd.cjs';
|
|
7
|
-
import './PdfViewer.types-
|
|
7
|
+
import './PdfViewer.types-DyoUBa2g.cjs';
|
package/dist/media-viewer.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { a as MediaViewer, b as MediaViewerProps } from './index-
|
|
1
|
+
export { a as MediaViewer, b as MediaViewerProps } from './index-Bwrc9ktU.js';
|
|
2
2
|
import 'react';
|
|
3
3
|
import './ImageViewer.types-BDTxBYEN.js';
|
|
4
4
|
import './FauxClient.types-Dtk9aRs6.js';
|
|
5
5
|
import './VideoViewer.types-_AwQ8DQr.js';
|
|
6
6
|
import './AudioViewer.types-CyhmQVQd.js';
|
|
7
|
-
import './PdfViewer.types-
|
|
7
|
+
import './PdfViewer.types-BEk2Jq6p.js';
|
package/dist/media-viewer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { MediaViewer } from './chunk-
|
|
1
|
+
export { MediaViewer } from './chunk-MTTRPPHH.js';
|
|
2
2
|
import './chunk-VOGI7GX3.js';
|
|
3
|
-
import './chunk-
|
|
3
|
+
import './chunk-MORXQ5UM.js';
|
|
4
4
|
import './chunk-ICMLLZKZ.js';
|
|
5
5
|
import './chunk-GVMWJ4NI.js';
|
|
6
6
|
import './chunk-CPY7NHXM.js';
|
package/dist/pdf-viewer.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk7MDHCYEB_cjs = require('./chunk-7MDHCYEB.cjs');
|
|
4
4
|
require('./chunk-M5SEYDSS.cjs');
|
|
5
5
|
require('./chunk-SNHU2AI4.cjs');
|
|
6
6
|
require('./chunk-ZU5Q77OT.cjs');
|
|
@@ -9,7 +9,7 @@ require('./chunk-ZU5Q77OT.cjs');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "PdfViewer", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunk7MDHCYEB_cjs.PdfViewer; }
|
|
13
13
|
});
|
|
14
14
|
//# sourceMappingURL=pdf-viewer.cjs.map
|
|
15
15
|
//# sourceMappingURL=pdf-viewer.cjs.map
|
package/dist/pdf-viewer.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { b as PdfViewerProps } from './PdfViewer.types-DyoUBa2g.cjs';
|
|
3
|
+
export { P as PdfPageSource, a as PdfViewerPolicy, c as PdfViewerWatermark } from './PdfViewer.types-DyoUBa2g.cjs';
|
|
3
4
|
import './FauxClient.types-Dtk9aRs6.cjs';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -11,6 +12,17 @@ import './FauxClient.types-Dtk9aRs6.cjs';
|
|
|
11
12
|
* ```tsx
|
|
12
13
|
* <PdfViewer src="/report.pdf" title="report.pdf" style={{ height: 600 }} />
|
|
13
14
|
* ```
|
|
15
|
+
*
|
|
16
|
+
* With `pages` it shows page images the app rendered instead, and never
|
|
17
|
+
* fetches or references the PDF; `policy` and `watermark` apply there.
|
|
18
|
+
*
|
|
19
|
+
* ```tsx
|
|
20
|
+
* <PdfViewer
|
|
21
|
+
* pages={{ count: 12, url: (n, scale) => `/docs/7/pages/${n}.png?scale=${scale}` }}
|
|
22
|
+
* policy={{ download: false, print: false, copy: false, screenshot: "deter" }}
|
|
23
|
+
* watermark={{ text: "jane@example.com" }}
|
|
24
|
+
* />
|
|
25
|
+
* ```
|
|
14
26
|
*/
|
|
15
27
|
declare const PdfViewer: react.ForwardRefExoticComponent<PdfViewerProps & react.RefAttributes<HTMLDivElement>>;
|
|
16
28
|
|
package/dist/pdf-viewer.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { b as PdfViewerProps } from './PdfViewer.types-BEk2Jq6p.js';
|
|
3
|
+
export { P as PdfPageSource, a as PdfViewerPolicy, c as PdfViewerWatermark } from './PdfViewer.types-BEk2Jq6p.js';
|
|
3
4
|
import './FauxClient.types-Dtk9aRs6.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -11,6 +12,17 @@ import './FauxClient.types-Dtk9aRs6.js';
|
|
|
11
12
|
* ```tsx
|
|
12
13
|
* <PdfViewer src="/report.pdf" title="report.pdf" style={{ height: 600 }} />
|
|
13
14
|
* ```
|
|
15
|
+
*
|
|
16
|
+
* With `pages` it shows page images the app rendered instead, and never
|
|
17
|
+
* fetches or references the PDF; `policy` and `watermark` apply there.
|
|
18
|
+
*
|
|
19
|
+
* ```tsx
|
|
20
|
+
* <PdfViewer
|
|
21
|
+
* pages={{ count: 12, url: (n, scale) => `/docs/7/pages/${n}.png?scale=${scale}` }}
|
|
22
|
+
* policy={{ download: false, print: false, copy: false, screenshot: "deter" }}
|
|
23
|
+
* watermark={{ text: "jane@example.com" }}
|
|
24
|
+
* />
|
|
25
|
+
* ```
|
|
14
26
|
*/
|
|
15
27
|
declare const PdfViewer: react.ForwardRefExoticComponent<PdfViewerProps & react.RefAttributes<HTMLDivElement>>;
|
|
16
28
|
|
package/dist/pdf-viewer.js
CHANGED
package/docs/PdfViewer.md
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
# PdfViewer
|
|
2
2
|
|
|
3
|
-
A standalone PDF viewer
|
|
4
|
-
|
|
3
|
+
A standalone PDF viewer with two modes:
|
|
4
|
+
|
|
5
|
+
- **`src`**: embeds the document via the browser's native PDF plugin
|
|
6
|
+
(`<object>`), falling back to an `<iframe>`, then to a download link.
|
|
7
|
+
- **`pages`** (page-image mode): shows page images your app rendered from the
|
|
8
|
+
PDF, behind its own auth, under an access `policy`, with an optional
|
|
9
|
+
`watermark`. The viewer never fetches or references the PDF.
|
|
10
|
+
|
|
5
11
|
Renders for PDF sources inside `MediaViewer`.
|
|
6
12
|
|
|
7
13
|
## Import
|
|
@@ -19,11 +25,107 @@ import { PdfViewer } from "@particle-academy/react-fancy";
|
|
|
19
25
|
The viewer fills its container, so give it a height. A `min-h` floor (`20rem`)
|
|
20
26
|
is built in so it stays usable even without an explicit height.
|
|
21
27
|
|
|
28
|
+
The native plugin always shows its own download and print buttons and exposes
|
|
29
|
+
the file's URL, and a page cannot restrict it. If a viewer must not get the
|
|
30
|
+
file, use page-image mode.
|
|
31
|
+
|
|
32
|
+
## Page-image mode
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
<PdfViewer
|
|
36
|
+
frame
|
|
37
|
+
title="contract-7.pdf"
|
|
38
|
+
pages={{ count: 12, url: (page, scale) => `/documents/7/pages/${page}.png?scale=${scale}` }}
|
|
39
|
+
policy={{ download: false, print: false, copy: false, screenshot: "deter" }}
|
|
40
|
+
watermark={{ text: "Jane Doe · jane@example.com · 2026-10-21 14:02" }}
|
|
41
|
+
style={{ height: 640 }}
|
|
42
|
+
/>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Your app turns the PDF into one image per page on its server, with whatever
|
|
46
|
+
tool it already uses, and serves them behind its own auth. react-fancy only
|
|
47
|
+
displays them. The `pages.url` images are the only requests the viewer makes;
|
|
48
|
+
`src` is ignored in this mode, even if you pass one.
|
|
49
|
+
|
|
50
|
+
- **`url(page, scale)`**: `page` is 1-based. `scale` is a resolution hint: the
|
|
51
|
+
zoom times the device pixel ratio, rounded **up** to one of `1`, `1.5`, `2`,
|
|
52
|
+
`3` or `4`, so a page is fetched at a handful of sizes rather than once per
|
|
53
|
+
zoom click. Render scale 1 at a width that reads sharply at fit-width in your
|
|
54
|
+
layout (e.g. 1000-1200 px).
|
|
55
|
+
- **`aspectRatio`** (optional, width / height) sizes a page before its image
|
|
56
|
+
arrives. Default A4 portrait. Each page switches to its image's real ratio
|
|
57
|
+
once it has loaded.
|
|
58
|
+
- **Lazy**: only pages near the viewport get an `<img>` (a viewport's height
|
|
59
|
+
above and below).
|
|
60
|
+
- **Toolbar**: previous / next page with "n / total", zoom out / zoom
|
|
61
|
+
percentage (click to reset) / zoom in, **Width** (fit width, which is 100%)
|
|
62
|
+
and **Page** (fit one page to the height). With `frame`, the `FauxClient`
|
|
63
|
+
frame adds full screen; the current page stays in place when the viewer
|
|
64
|
+
resizes.
|
|
65
|
+
- **No search.** Page images carry no text, so there is nothing to search.
|
|
66
|
+
This is a consequence of not sending the PDF.
|
|
67
|
+
- **Controlled state** for agents and hosts: `page` / `onPageChange` and
|
|
68
|
+
`zoom` / `onZoomChange`. Stable handles:
|
|
69
|
+
`[data-react-fancy-pdf-viewer-page][data-page="3"]`, and
|
|
70
|
+
`data-react-fancy-pdf-viewer-{prev,next,zoom-in,zoom-out,zoom-reset,fit-width,fit-page}`
|
|
71
|
+
on the buttons.
|
|
72
|
+
|
|
73
|
+
### Policy: what each flag does and does not do
|
|
74
|
+
|
|
75
|
+
Every flag defaults to allowed. **These are deterrents.** A web page cannot stop
|
|
76
|
+
someone who is determined: anything drawn on a screen can be photographed,
|
|
77
|
+
screenshotted or pulled out of devtools. The real protection is that in this
|
|
78
|
+
mode the app never serves the PDF, and page images are all a viewer ever gets.
|
|
79
|
+
|
|
80
|
+
| Flag | Does | Does not |
|
|
81
|
+
|------|------|----------|
|
|
82
|
+
| `download: false` | Suppresses the context menu ("Save image as…") on the pages, and makes the images non-draggable. There is no download control in this mode at all, whatever the flag. | Stop the page images being captured: they are ordinary images the browser has fetched, visible in devtools and the browser's cache. |
|
|
83
|
+
| `print: false` | Print CSS blanks the viewer, so printing (Ctrl/Cmd+P, the browser menu, `window.print()`) produces an empty frame. Ctrl/Cmd+P is also intercepted while focus is inside the viewer. | Stop a screenshot, a "save page", or a user who edits the CSS in devtools. |
|
|
84
|
+
| `copy: false` | Turns user selection off. (There is no text layer to copy anyway.) | Anything else; the images can still be captured. |
|
|
85
|
+
| `screenshot: "deter"` | Blurs the pages while the tab is hidden or the window has lost focus. On a PrintScreen key it blurs them for 1.5 s and tries to clear the clipboard, best effort. | **Prevent screenshots. A web page cannot.** OS tools, other apps and phone cameras are all out of its reach, and PrintScreen usually captures before the page hears the key. |
|
|
86
|
+
|
|
87
|
+
### Watermark
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
watermark={{ text: "jane@example.com", opacity: 0.15, angle: -30, density: 1 }}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
A tiled text overlay drawn over every page in the browser, with
|
|
94
|
+
`pointer-events: none`. Defaults: `opacity` 0.15, `angle` -30°, `density` 1
|
|
95
|
+
(2 halves the gap between repeats).
|
|
96
|
+
|
|
97
|
+
**A client-side watermark can be removed with devtools.** If yours must hold,
|
|
98
|
+
burn it into the page images on your server: the `url(page, scale)` callback is
|
|
99
|
+
the place to ask for that (e.g. a per-viewer URL your server stamps).
|
|
100
|
+
|
|
22
101
|
## Props
|
|
23
102
|
|
|
24
103
|
| Prop | Type | Default | Description |
|
|
25
104
|
|------|------|---------|-------------|
|
|
26
|
-
| src | `string` | — | PDF source (`http(s):` / `data:` / `blob:`) |
|
|
27
|
-
|
|
|
105
|
+
| src | `string` | — | PDF source (`http(s):` / `data:` / `blob:`) for the native plugin. Ignored with `pages` |
|
|
106
|
+
| pages | `{ count: number; url: (page, scale) => string; aspectRatio?: number }` | — | Page-image mode |
|
|
107
|
+
| page | `number` | — | Current page (1-based), controlled |
|
|
108
|
+
| defaultPage | `number` | `1` | Starting page, uncontrolled |
|
|
109
|
+
| onPageChange | `(page: number) => void` | — | Page changed (toolbar or scrolling) |
|
|
110
|
+
| zoom | `number` | — | Zoom, 1 = fit width, controlled (page-image mode) |
|
|
111
|
+
| defaultZoom | `number` | `1` | Starting zoom, uncontrolled |
|
|
112
|
+
| onZoomChange | `(zoom: number) => void` | — | Zoom changed |
|
|
113
|
+
| policy | `{ download?: boolean; print?: boolean; copy?: boolean; screenshot?: "allow" \| "deter" }` | all allowed | See above (page-image mode only) |
|
|
114
|
+
| watermark | `{ text: string; opacity?: number; angle?: number; density?: number }` | — | See above (page-image mode only) |
|
|
115
|
+
| frame | `boolean` | `false` | Show inside the `FauxClient` frame, with full screen |
|
|
116
|
+
| frameProps | `Partial<FauxClientProps>` | — | Passed to the frame |
|
|
117
|
+
| title | `string` | `"PDF document"` | Accessible title, and the frame's address-bar text |
|
|
28
118
|
| className | `string` | — | Classes for the container |
|
|
29
119
|
| style | `CSSProperties` | — | Styles for the container (e.g. a height) |
|
|
120
|
+
|
|
121
|
+
## Through MediaViewer and FileViewer
|
|
122
|
+
|
|
123
|
+
Both already forward `pdfProps` untouched, so page-image mode needs no new
|
|
124
|
+
props on either:
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
<MediaViewer kind="pdf" src="" pdfProps={{ pages, policy, watermark }} />
|
|
128
|
+
|
|
129
|
+
// @particle-academy/fancy-code
|
|
130
|
+
<FileViewer filename="contract.pdf" mediaProps={{ pdfProps: { pages, policy, watermark } }} />
|
|
131
|
+
```
|
package/package.json
CHANGED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { F as FauxClientProps } from './FauxClient.types-Dtk9aRs6.cjs';
|
|
2
|
-
import { CSSProperties } from 'react';
|
|
3
|
-
|
|
4
|
-
interface PdfViewerProps {
|
|
5
|
-
/**
|
|
6
|
-
* Show the PDF in react-fancy's `FauxClient` frame with a full-screen button,
|
|
7
|
-
* revealed on hover. Zoom stays on the browser's own PDF toolbar. Default `false`.
|
|
8
|
-
*/
|
|
9
|
-
frame?: boolean;
|
|
10
|
-
/** Passed to the frame (`variant`, `onFullscreenChange`, …). */
|
|
11
|
-
frameProps?: Partial<FauxClientProps>;
|
|
12
|
-
/** PDF source — an `http(s):`, `data:`, or `blob:` URL. */
|
|
13
|
-
src: string;
|
|
14
|
-
/** Accessible title for the embedded document (default `"PDF document"`). */
|
|
15
|
-
title?: string;
|
|
16
|
-
/** Additional CSS classes for the container. */
|
|
17
|
-
className?: string;
|
|
18
|
-
/** Inline styles for the container (e.g. a fixed height). */
|
|
19
|
-
style?: CSSProperties;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type { PdfViewerProps as P };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { F as FauxClientProps } from './FauxClient.types-Dtk9aRs6.js';
|
|
2
|
-
import { CSSProperties } from 'react';
|
|
3
|
-
|
|
4
|
-
interface PdfViewerProps {
|
|
5
|
-
/**
|
|
6
|
-
* Show the PDF in react-fancy's `FauxClient` frame with a full-screen button,
|
|
7
|
-
* revealed on hover. Zoom stays on the browser's own PDF toolbar. Default `false`.
|
|
8
|
-
*/
|
|
9
|
-
frame?: boolean;
|
|
10
|
-
/** Passed to the frame (`variant`, `onFullscreenChange`, …). */
|
|
11
|
-
frameProps?: Partial<FauxClientProps>;
|
|
12
|
-
/** PDF source — an `http(s):`, `data:`, or `blob:` URL. */
|
|
13
|
-
src: string;
|
|
14
|
-
/** Accessible title for the embedded document (default `"PDF document"`). */
|
|
15
|
-
title?: string;
|
|
16
|
-
/** Additional CSS classes for the container. */
|
|
17
|
-
className?: string;
|
|
18
|
-
/** Inline styles for the container (e.g. a fixed height). */
|
|
19
|
-
style?: CSSProperties;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type { PdfViewerProps as P };
|