react-file-preview-engine 0.1.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/index.d.mts +20 -0
- package/dist/index.mjs +237 -0
- package/dist/style.css +63 -0
- package/dist/types-DHt-OXXj.d.mts +48 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.mjs +1 -0
- package/package.json +11 -11
- package/dist/chunks/chunk-YEB7RW6X.js +0 -238
- package/dist/components.d.ts +0 -6
- package/dist/components.js +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -1
- package/dist/types.d.ts +0 -47
- package/dist/types.js +0 -1
package/README.md
CHANGED
|
@@ -50,6 +50,7 @@ This is the minimal setup. The previewer automatically infers the MIME type from
|
|
|
50
50
|
```tsx
|
|
51
51
|
import React from "react";
|
|
52
52
|
import FilePreviewer from "react-file-preview-engine";
|
|
53
|
+
import "react-file-preview-engine/style.css";
|
|
53
54
|
|
|
54
55
|
export default function App() {
|
|
55
56
|
return <FilePreviewer src="https://example.com/sample.pdf" fileName="sample.pdf" />;
|
|
@@ -63,6 +64,7 @@ You can preview files selected by the user without uploading them first. The eng
|
|
|
63
64
|
```tsx
|
|
64
65
|
import React, { useState } from "react";
|
|
65
66
|
import FilePreviewer from "react-file-preview-engine";
|
|
67
|
+
import "react-file-preview-engine/style.css";
|
|
66
68
|
|
|
67
69
|
export default function App() {
|
|
68
70
|
const [file, setFile] = useState<File>();
|
|
@@ -83,6 +85,7 @@ If you already know the MIME type, you can pass it directly. This ensures the en
|
|
|
83
85
|
```tsx
|
|
84
86
|
import React from "react";
|
|
85
87
|
import FilePreviewer from "react-file-preview-engine";
|
|
88
|
+
import "react-file-preview-engine/style.css";
|
|
86
89
|
|
|
87
90
|
export default function App() {
|
|
88
91
|
return <FilePreviewer src={new Blob(["Hello world"], { type: "text/plain" })} mimeType="text/plain" fileName="hello.txt" />;
|
|
@@ -96,6 +99,7 @@ You can listen to lifecycle events triggered by the active renderer.
|
|
|
96
99
|
```tsx
|
|
97
100
|
import React from "react";
|
|
98
101
|
import FilePreviewer from "react-file-preview-engine";
|
|
102
|
+
import "react-file-preview-engine/style.css";
|
|
99
103
|
|
|
100
104
|
export default function App() {
|
|
101
105
|
return (
|
|
@@ -120,6 +124,7 @@ For audio and video files, you can enable auto play.
|
|
|
120
124
|
```tsx
|
|
121
125
|
import React from "react";
|
|
122
126
|
import FilePreviewer from "react-file-preview-engine";
|
|
127
|
+
import "react-file-preview-engine/style.css";
|
|
123
128
|
|
|
124
129
|
export default function App() {
|
|
125
130
|
return <FilePreviewer src="https://example.com/video.mp4" fileName="video.mp4" autoPlay={true} />;
|
|
@@ -133,6 +138,7 @@ You can customize the loader, container props, and icon props without modifying
|
|
|
133
138
|
```tsx
|
|
134
139
|
import React from "react";
|
|
135
140
|
import FilePreviewer from "react-file-preview-engine";
|
|
141
|
+
import "react-file-preview-engine/style.css";
|
|
136
142
|
|
|
137
143
|
export default function App() {
|
|
138
144
|
return (
|
|
@@ -154,6 +160,7 @@ When a renderer reports an error, the previewer switches to `errorRenderer`.
|
|
|
154
160
|
```tsx
|
|
155
161
|
import React from "react";
|
|
156
162
|
import FilePreviewer from "react-file-preview-engine";
|
|
163
|
+
import "react-file-preview-engine/style.css";
|
|
157
164
|
|
|
158
165
|
const errorRenderer = {
|
|
159
166
|
Component() {
|
|
@@ -189,6 +196,7 @@ This example adds support for markdown files.
|
|
|
189
196
|
```tsx
|
|
190
197
|
import React, { useEffect, useState } from "react";
|
|
191
198
|
import FilePreviewer from "react-file-preview-engine";
|
|
199
|
+
import "react-file-preview-engine/style.css";
|
|
192
200
|
import type { Renderer } from "react-file-preview-engine/types";
|
|
193
201
|
import remarkGfm from "remark-gfm";
|
|
194
202
|
import rehypeRaw from "rehype-raw";
|
|
@@ -242,6 +250,7 @@ You can extend renderers with custom configuration using `additionalContext`. Th
|
|
|
242
250
|
```tsx
|
|
243
251
|
import React, { useEffect, useMemo, useState } from "react";
|
|
244
252
|
import FilePreviewer from "react-file-preview-engine";
|
|
253
|
+
import "react-file-preview-engine/style.css";
|
|
245
254
|
import type { Renderer } from "react-file-preview-engine/types";
|
|
246
255
|
import remarkGfm from "remark-gfm";
|
|
247
256
|
import rehypeRaw from "rehype-raw";
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { i as FilePreviewerProps } from "./types-DHt-OXXj.mjs";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/components.d.ts
|
|
5
|
+
declare function FilePreviewer<T extends object = {}>({
|
|
6
|
+
src,
|
|
7
|
+
mimeType,
|
|
8
|
+
fileName,
|
|
9
|
+
autoPlay,
|
|
10
|
+
loader,
|
|
11
|
+
customRenderers,
|
|
12
|
+
additionalContext,
|
|
13
|
+
errorRenderer,
|
|
14
|
+
containerProps,
|
|
15
|
+
iconProps,
|
|
16
|
+
onLoad,
|
|
17
|
+
onError
|
|
18
|
+
}: FilePreviewerProps<T>): React.JSX.Element;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { FilePreviewer as default };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { FileIcon, defaultStyles } from "react-file-icon";
|
|
3
|
+
import Mime from "mime/lite";
|
|
4
|
+
//#region src/constants.ts
|
|
5
|
+
const defaults = {
|
|
6
|
+
additionalContext: {},
|
|
7
|
+
customRenderers: [],
|
|
8
|
+
props: {}
|
|
9
|
+
};
|
|
10
|
+
const fileExtensionRegex = /\.([^.]+)$/;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/hooks.ts
|
|
13
|
+
function useResolvedSrc(src) {
|
|
14
|
+
const objectUrlRef = useRef(null);
|
|
15
|
+
const revokeObjectURL = () => {
|
|
16
|
+
if (!objectUrlRef.current) return;
|
|
17
|
+
URL.revokeObjectURL(objectUrlRef.current);
|
|
18
|
+
objectUrlRef.current = null;
|
|
19
|
+
};
|
|
20
|
+
const resolvedSrc = useMemo(() => {
|
|
21
|
+
revokeObjectURL();
|
|
22
|
+
if (typeof src === "string") return src;
|
|
23
|
+
const url = src instanceof File || src instanceof Blob ? URL.createObjectURL(src) : src instanceof ArrayBuffer ? URL.createObjectURL(new Blob([src])) : "";
|
|
24
|
+
if (url) objectUrlRef.current = url;
|
|
25
|
+
return url;
|
|
26
|
+
}, [src]);
|
|
27
|
+
useEffect(() => revokeObjectURL, []);
|
|
28
|
+
return resolvedSrc;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/lib/utils.ts
|
|
32
|
+
const composeClass = (baseClass, props) => `${baseClass}${props?.className ? " " + props.className : ""}`;
|
|
33
|
+
const composeProps = (baseClass, props, overrideProps) => {
|
|
34
|
+
const mergedProps = {
|
|
35
|
+
...props,
|
|
36
|
+
...overrideProps
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
...mergedProps,
|
|
40
|
+
style: {
|
|
41
|
+
...props?.style,
|
|
42
|
+
...overrideProps?.style
|
|
43
|
+
},
|
|
44
|
+
className: composeClass(baseClass, mergedProps)
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
async function fetchResource(src, type, signal) {
|
|
48
|
+
const res = await fetch(src, { signal });
|
|
49
|
+
if (!res.ok) throw new Error();
|
|
50
|
+
return res[type]();
|
|
51
|
+
}
|
|
52
|
+
const getFileExtension = (mimeType, fileName) => Mime.getExtension(mimeType) || fileName?.match(fileExtensionRegex)?.[1] || "";
|
|
53
|
+
const getFileType = (mimeType, fileName) => mimeType || fileName && Mime.getType(fileName) || "";
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/lib/rendererRegistry.tsx
|
|
56
|
+
const audioRenderer = {
|
|
57
|
+
canRender: ({ mimeType }) => mimeType.startsWith("audio/"),
|
|
58
|
+
Component({ src, mimeType, fileName, autoPlay, onLoad, onError }) {
|
|
59
|
+
return /* @__PURE__ */ React.createElement("audio", {
|
|
60
|
+
className: "rfpe-audio",
|
|
61
|
+
controls: true,
|
|
62
|
+
autoPlay,
|
|
63
|
+
onCanPlay: onLoad,
|
|
64
|
+
onError,
|
|
65
|
+
"aria-label": fileName || "Audio preview"
|
|
66
|
+
}, /* @__PURE__ */ React.createElement("source", {
|
|
67
|
+
src,
|
|
68
|
+
type: mimeType
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const fallbackRenderer = { Component({ mimeType, fileName, iconProps, onLoad }) {
|
|
73
|
+
const extension = useMemo(() => getFileExtension(mimeType, fileName), [mimeType, fileName]);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
onLoad();
|
|
76
|
+
}, []);
|
|
77
|
+
return /* @__PURE__ */ React.createElement("div", composeProps("rfpe-icon", iconProps), /* @__PURE__ */ React.createElement(FileIcon, {
|
|
78
|
+
extension,
|
|
79
|
+
...defaultStyles[extension]
|
|
80
|
+
}));
|
|
81
|
+
} };
|
|
82
|
+
const defaultRenderers$1 = [
|
|
83
|
+
{
|
|
84
|
+
canRender: ({ mimeType }) => mimeType === "text/plain",
|
|
85
|
+
Component({ src, onLoad, onError }) {
|
|
86
|
+
const [data, setData] = useState("");
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
fetchResource(src, "text", controller.signal).then((data) => {
|
|
90
|
+
setData(data);
|
|
91
|
+
onLoad();
|
|
92
|
+
}).catch(onError);
|
|
93
|
+
return () => controller.abort();
|
|
94
|
+
}, [src]);
|
|
95
|
+
return /* @__PURE__ */ React.createElement("div", { className: "rfpe-text" }, data);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
canRender: ({ mimeType }) => mimeType === "application/pdf",
|
|
100
|
+
Component({ src, onLoad, onError }) {
|
|
101
|
+
const [data, setData] = useState("");
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const controller = new AbortController();
|
|
104
|
+
let objectUrl;
|
|
105
|
+
fetchResource(src, "arrayBuffer", controller.signal).then((buffer) => {
|
|
106
|
+
const blob = new Blob([buffer], { type: "application/pdf" });
|
|
107
|
+
objectUrl = URL.createObjectURL(blob);
|
|
108
|
+
setData(objectUrl);
|
|
109
|
+
onLoad();
|
|
110
|
+
}).catch(onError);
|
|
111
|
+
return () => {
|
|
112
|
+
controller.abort();
|
|
113
|
+
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
114
|
+
};
|
|
115
|
+
}, [src]);
|
|
116
|
+
return /* @__PURE__ */ React.createElement("iframe", {
|
|
117
|
+
className: "rfpe-iframe",
|
|
118
|
+
src: data
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
canRender: ({ mimeType }) => mimeType === "text/html",
|
|
124
|
+
Component({ src, onLoad, onError }) {
|
|
125
|
+
const [data, setData] = useState("");
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
const controller = new AbortController();
|
|
128
|
+
fetchResource(src, "text", controller.signal).then((data) => {
|
|
129
|
+
setData(data);
|
|
130
|
+
onLoad();
|
|
131
|
+
}).catch(onError);
|
|
132
|
+
return () => controller.abort();
|
|
133
|
+
}, [src]);
|
|
134
|
+
return /* @__PURE__ */ React.createElement("iframe", {
|
|
135
|
+
className: "rfpe-iframe",
|
|
136
|
+
src: `data:text/html; charset=utf-8,${encodeURIComponent(data)}`,
|
|
137
|
+
sandbox: ""
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
canRender: ({ mimeType }) => mimeType.startsWith("image/"),
|
|
143
|
+
Component({ src, fileName, onLoad, onError }) {
|
|
144
|
+
return /* @__PURE__ */ React.createElement("img", {
|
|
145
|
+
className: "rfpe-image",
|
|
146
|
+
src,
|
|
147
|
+
alt: fileName || "Image preview",
|
|
148
|
+
onLoad,
|
|
149
|
+
onError
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
audioRenderer,
|
|
154
|
+
{
|
|
155
|
+
canRender: ({ mimeType }) => mimeType.startsWith("video/"),
|
|
156
|
+
Component({ src, mimeType, fileName, autoPlay, onLoad, onError }) {
|
|
157
|
+
return /* @__PURE__ */ React.createElement("video", {
|
|
158
|
+
className: "rfpe-video",
|
|
159
|
+
controls: true,
|
|
160
|
+
autoPlay,
|
|
161
|
+
onCanPlay: onLoad,
|
|
162
|
+
onError,
|
|
163
|
+
"aria-label": fileName || "Video preview"
|
|
164
|
+
}, /* @__PURE__ */ React.createElement("source", {
|
|
165
|
+
src,
|
|
166
|
+
type: mimeType
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
];
|
|
171
|
+
function resolveRenderer(customRenderers, ctx) {
|
|
172
|
+
return customRenderers.concat(defaultRenderers$1).find((r) => r.canRender?.(ctx)) ?? fallbackRenderer;
|
|
173
|
+
}
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/components.tsx
|
|
176
|
+
const { additionalContext: defaultContext, customRenderers: defaultRenderers, props: defaultProps } = defaults;
|
|
177
|
+
function FilePreviewer({ src, mimeType, fileName = "", autoPlay = false, loader = /* @__PURE__ */ React.createElement(Loader, null), customRenderers = defaultRenderers, additionalContext = defaultContext, errorRenderer = fallbackRenderer, containerProps = defaultProps, iconProps = defaultProps, onLoad, onError }) {
|
|
178
|
+
const resolvedSrc = useResolvedSrc(src);
|
|
179
|
+
const fileType = useMemo(() => getFileType(mimeType, fileName), [mimeType, fileName]);
|
|
180
|
+
const fileKey = `${resolvedSrc}|${fileType}|${fileName}`;
|
|
181
|
+
const [state, setState] = useState({
|
|
182
|
+
key: fileKey,
|
|
183
|
+
status: "loading"
|
|
184
|
+
});
|
|
185
|
+
if (state.key !== fileKey) setState({
|
|
186
|
+
key: fileKey,
|
|
187
|
+
status: "loading"
|
|
188
|
+
});
|
|
189
|
+
const isLoading = state.status === "loading";
|
|
190
|
+
const handleLoad = () => {
|
|
191
|
+
setState((prev) => {
|
|
192
|
+
if (prev.key !== fileKey || prev.status !== "loading") return prev;
|
|
193
|
+
onLoad?.();
|
|
194
|
+
return {
|
|
195
|
+
key: fileKey,
|
|
196
|
+
status: "ready"
|
|
197
|
+
};
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
const handleError = () => {
|
|
201
|
+
setState((prev) => {
|
|
202
|
+
if (prev.key !== fileKey || prev.status === "error") return prev;
|
|
203
|
+
onError?.();
|
|
204
|
+
return {
|
|
205
|
+
key: fileKey,
|
|
206
|
+
status: "error"
|
|
207
|
+
};
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
const context = {
|
|
211
|
+
src: resolvedSrc,
|
|
212
|
+
mimeType: fileType,
|
|
213
|
+
fileName,
|
|
214
|
+
autoPlay,
|
|
215
|
+
iconProps,
|
|
216
|
+
onLoad: handleLoad,
|
|
217
|
+
onError: handleError,
|
|
218
|
+
...additionalContext
|
|
219
|
+
};
|
|
220
|
+
const renderer = useMemo(() => resolveRenderer(customRenderers, context), [
|
|
221
|
+
resolvedSrc,
|
|
222
|
+
fileType,
|
|
223
|
+
fileName,
|
|
224
|
+
autoPlay,
|
|
225
|
+
additionalContext
|
|
226
|
+
]);
|
|
227
|
+
const ActiveRenderer = state.status === "error" ? errorRenderer : renderer;
|
|
228
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, isLoading && loader, /* @__PURE__ */ React.createElement("div", composeProps("rfpe-container", containerProps, { style: { visibility: isLoading ? "hidden" : "visible" } }), /* @__PURE__ */ React.createElement(ActiveRenderer.Component, {
|
|
229
|
+
key: fileKey,
|
|
230
|
+
...context
|
|
231
|
+
})));
|
|
232
|
+
}
|
|
233
|
+
function Loader({ children, text }) {
|
|
234
|
+
return /* @__PURE__ */ React.createElement("div", { className: "rfpe-loader" }, /* @__PURE__ */ React.createElement("div", { className: "rfpe-loader-spinner" }), children ?? /* @__PURE__ */ React.createElement("div", { className: "rfpe-loader-text" }, text));
|
|
235
|
+
}
|
|
236
|
+
//#endregion
|
|
237
|
+
export { FilePreviewer as default };
|
package/dist/style.css
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
@layer rfpe {
|
|
2
|
+
:where(.rfpe-container) {
|
|
3
|
+
justify-content: center;
|
|
4
|
+
align-items: center;
|
|
5
|
+
max-width: 100vw;
|
|
6
|
+
height: 100%;
|
|
7
|
+
display: flex;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
:where(.rfpe-icon) {
|
|
11
|
+
width: 50px;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.rfpe-audio {
|
|
16
|
+
width: 100%;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.rfpe-iframe {
|
|
20
|
+
background-color: #fff;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.rfpe-iframe, .rfpe-image, .rfpe-video {
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 100%;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.rfpe-image, .rfpe-video {
|
|
29
|
+
object-fit: contain;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.rfpe-text {
|
|
33
|
+
white-space: pre-wrap;
|
|
34
|
+
width: 100%;
|
|
35
|
+
height: 100%;
|
|
36
|
+
overflow: auto;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.rfpe-loader {
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: .5rem;
|
|
42
|
+
display: inline-flex;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.rfpe-loader-spinner {
|
|
46
|
+
box-sizing: border-box;
|
|
47
|
+
aspect-ratio: 1;
|
|
48
|
+
border: 2px solid #000;
|
|
49
|
+
border-color: #000 #0000;
|
|
50
|
+
border-radius: 50%;
|
|
51
|
+
width: 22px;
|
|
52
|
+
animation: .6s infinite rfpe-spin-fast;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.rfpe-loader-text {
|
|
56
|
+
font-size: .875rem;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@keyframes rfpe-spin-fast {
|
|
60
|
+
to {
|
|
61
|
+
transform: rotate(360deg);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { DetailedHTMLProps, HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
type LoaderProps = {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
text?: string;
|
|
7
|
+
};
|
|
8
|
+
type EventHandler = () => void;
|
|
9
|
+
type RenderBehaviour = {
|
|
10
|
+
autoPlay: boolean;
|
|
11
|
+
iconProps: DivProps;
|
|
12
|
+
onLoad: EventHandler;
|
|
13
|
+
onError: EventHandler;
|
|
14
|
+
};
|
|
15
|
+
type RenderContext<T extends object = {}> = {
|
|
16
|
+
src: string;
|
|
17
|
+
mimeType: string;
|
|
18
|
+
fileName: string;
|
|
19
|
+
} & RenderBehaviour & T;
|
|
20
|
+
type Renderer<T extends object = {}> = {
|
|
21
|
+
name?: string;
|
|
22
|
+
canRender?(ctx: RenderContext<T>): boolean;
|
|
23
|
+
Component(ctx: RenderContext<T>): ReactNode;
|
|
24
|
+
};
|
|
25
|
+
type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
|
26
|
+
type FetchType = "text" | "arrayBuffer" | "blob" | "json";
|
|
27
|
+
type FilePreviewerProps<T extends object> = {
|
|
28
|
+
src: FileSource;
|
|
29
|
+
loader?: ReactNode;
|
|
30
|
+
customRenderers?: Renderer<T>[];
|
|
31
|
+
additionalContext?: T;
|
|
32
|
+
errorRenderer?: Renderer<T>;
|
|
33
|
+
containerProps?: DivProps;
|
|
34
|
+
} & MimeTypeSource & Partial<RenderBehaviour>;
|
|
35
|
+
type FileSource = string | File | Blob | ArrayBuffer;
|
|
36
|
+
type MimeTypeSource = {
|
|
37
|
+
mimeType: string;
|
|
38
|
+
fileName?: string;
|
|
39
|
+
} | {
|
|
40
|
+
fileName: string;
|
|
41
|
+
mimeType?: string;
|
|
42
|
+
};
|
|
43
|
+
type State = {
|
|
44
|
+
key: string;
|
|
45
|
+
status: "loading" | "ready" | "error";
|
|
46
|
+
};
|
|
47
|
+
//#endregion
|
|
48
|
+
export { FileSource as a, RenderBehaviour as c, State as d, FilePreviewerProps as i, RenderContext as l, EventHandler as n, LoaderProps as o, FetchType as r, MimeTypeSource as s, DivProps as t, Renderer as u };
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as FileSource, c as RenderBehaviour, d as State, i as FilePreviewerProps, l as RenderContext, n as EventHandler, o as LoaderProps, r as FetchType, s as MimeTypeSource, t as DivProps, u as Renderer } from "./types-DHt-OXXj.mjs";
|
|
2
|
+
export { DivProps, EventHandler, FetchType, FilePreviewerProps, FileSource, LoaderProps, MimeTypeSource, RenderBehaviour, RenderContext, Renderer, State };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-file-preview-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "A renderer-driven React file preview engine with extensible architecture for images, video, audio, pdf, html, and custom formats.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sahil Aggarwal <aggarwalsahil2004@gmail.com>",
|
|
@@ -15,17 +15,17 @@
|
|
|
15
15
|
},
|
|
16
16
|
"type": "module",
|
|
17
17
|
"exports": {
|
|
18
|
-
".": "./dist/index.
|
|
19
|
-
"./
|
|
18
|
+
".": "./dist/index.mjs",
|
|
19
|
+
"./style.css": "./dist/style.css",
|
|
20
|
+
"./types": "./dist/types.mjs"
|
|
20
21
|
},
|
|
21
|
-
"main": "dist/index.js",
|
|
22
22
|
"files": [
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
25
|
"sideEffects": [
|
|
26
26
|
"**/*.css"
|
|
27
27
|
],
|
|
28
|
-
"types": "dist/index.d.
|
|
28
|
+
"types": "./dist/index.d.mts",
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"mime": "^4.1.0",
|
|
31
31
|
"react-file-icon": "^1.6.0"
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@release-it/conventional-changelog": "^10.0.
|
|
39
|
-
"@types/react": "^19.2.
|
|
38
|
+
"@release-it/conventional-changelog": "^10.0.6",
|
|
39
|
+
"@types/react": "^19.2.14",
|
|
40
40
|
"@types/react-file-icon": "^1.0.4",
|
|
41
41
|
"prettier-package-json": "^2.8.0",
|
|
42
|
-
"release-it": "^19.2.
|
|
43
|
-
"
|
|
42
|
+
"release-it": "^19.2.4",
|
|
43
|
+
"tsdown": "^0.21.2",
|
|
44
44
|
"typescript": "^5.9.3"
|
|
45
45
|
},
|
|
46
46
|
"keywords": [
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
],
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "pnpm i && pnpm run compile",
|
|
70
|
-
"compile": "
|
|
71
|
-
"dev": "
|
|
70
|
+
"compile": "tsdown",
|
|
71
|
+
"dev": "tsdown --watch",
|
|
72
72
|
"dry-release": "release-it --ci --dry-run",
|
|
73
73
|
"prettier": "prettier-package-json --write package.json",
|
|
74
74
|
"pub": "pnpm login && pnpm publish",
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import React, { useMemo, useState, useRef, useEffect } from 'react';
|
|
2
|
-
import { FileIcon, defaultStyles } from 'react-file-icon';
|
|
3
|
-
import Mime from 'mime/lite';
|
|
4
|
-
|
|
5
|
-
var __defProp = Object.defineProperty;
|
|
6
|
-
var __defProps = Object.defineProperties;
|
|
7
|
-
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
8
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
9
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
11
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
12
|
-
var __spreadValues = (a, b) => {
|
|
13
|
-
for (var prop in b || (b = {}))
|
|
14
|
-
if (__hasOwnProp.call(b, prop))
|
|
15
|
-
__defNormalProp(a, prop, b[prop]);
|
|
16
|
-
if (__getOwnPropSymbols)
|
|
17
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
18
|
-
if (__propIsEnum.call(b, prop))
|
|
19
|
-
__defNormalProp(a, prop, b[prop]);
|
|
20
|
-
}
|
|
21
|
-
return a;
|
|
22
|
-
};
|
|
23
|
-
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
24
|
-
var __async = (__this, __arguments, generator) => {
|
|
25
|
-
return new Promise((resolve, reject) => {
|
|
26
|
-
var fulfilled = (value) => {
|
|
27
|
-
try {
|
|
28
|
-
step(generator.next(value));
|
|
29
|
-
} catch (e) {
|
|
30
|
-
reject(e);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
var rejected = (value) => {
|
|
34
|
-
try {
|
|
35
|
-
step(generator.throw(value));
|
|
36
|
-
} catch (e) {
|
|
37
|
-
reject(e);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
41
|
-
step((generator = generator.apply(__this, __arguments)).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// src/constants.ts
|
|
46
|
-
var defaults = { additionalContext: {}, customRenderers: [], props: {} };
|
|
47
|
-
var fileExtensionRegex = /\.([^.]+)$/;
|
|
48
|
-
function useResolvedSrc(src) {
|
|
49
|
-
const objectUrlRef = useRef(null);
|
|
50
|
-
const revokeObjectURL = () => {
|
|
51
|
-
if (!objectUrlRef.current) return;
|
|
52
|
-
URL.revokeObjectURL(objectUrlRef.current);
|
|
53
|
-
objectUrlRef.current = null;
|
|
54
|
-
};
|
|
55
|
-
const resolvedSrc = useMemo(() => {
|
|
56
|
-
revokeObjectURL();
|
|
57
|
-
if (typeof src === "string") return src;
|
|
58
|
-
const url = src instanceof File || src instanceof Blob ? URL.createObjectURL(src) : src instanceof ArrayBuffer ? URL.createObjectURL(new Blob([src])) : "";
|
|
59
|
-
if (url) objectUrlRef.current = url;
|
|
60
|
-
return url;
|
|
61
|
-
}, [src]);
|
|
62
|
-
useEffect(() => revokeObjectURL, []);
|
|
63
|
-
return resolvedSrc;
|
|
64
|
-
}
|
|
65
|
-
var composeClass = (baseClass, props) => `${baseClass}${(props == null ? void 0 : props.className) ? " " + props.className : ""}`;
|
|
66
|
-
var composeProps = (baseClass, props, overrideProps) => {
|
|
67
|
-
const mergedProps = __spreadValues(__spreadValues({}, props), overrideProps);
|
|
68
|
-
return __spreadProps(__spreadValues({}, mergedProps), {
|
|
69
|
-
style: __spreadValues(__spreadValues({}, props == null ? void 0 : props.style), overrideProps == null ? void 0 : overrideProps.style),
|
|
70
|
-
className: composeClass(baseClass, mergedProps)
|
|
71
|
-
});
|
|
72
|
-
};
|
|
73
|
-
function fetchResource(src, type, signal) {
|
|
74
|
-
return __async(this, null, function* () {
|
|
75
|
-
const res = yield fetch(src, { signal });
|
|
76
|
-
if (!res.ok) throw new Error();
|
|
77
|
-
return res[type]();
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
var getFileExtension = (mimeType, fileName) => {
|
|
81
|
-
var _a;
|
|
82
|
-
return Mime.getExtension(mimeType) || ((_a = fileName == null ? void 0 : fileName.match(fileExtensionRegex)) == null ? void 0 : _a[1]) || "";
|
|
83
|
-
};
|
|
84
|
-
var getFileType = (mimeType, fileName) => mimeType || fileName && Mime.getType(fileName) || "";
|
|
85
|
-
|
|
86
|
-
// src/lib/rendererRegistry.tsx
|
|
87
|
-
var audioRenderer = {
|
|
88
|
-
canRender: ({ mimeType }) => mimeType.startsWith("audio/"),
|
|
89
|
-
Component({ src, mimeType, fileName, autoPlay, onLoad, onError }) {
|
|
90
|
-
return /* @__PURE__ */ React.createElement("audio", { className: "rfpe-audio", controls: true, autoPlay, onCanPlay: onLoad, onError, "aria-label": fileName || "Audio preview" }, /* @__PURE__ */ React.createElement("source", { src, type: mimeType }));
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
var fallbackRenderer = {
|
|
94
|
-
Component({ mimeType, fileName, iconProps, onLoad }) {
|
|
95
|
-
const extension = useMemo(() => getFileExtension(mimeType, fileName), [mimeType, fileName]);
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
onLoad();
|
|
98
|
-
}, []);
|
|
99
|
-
return /* @__PURE__ */ React.createElement("div", __spreadValues({}, composeProps("rfpe-icon", iconProps)), /* @__PURE__ */ React.createElement(FileIcon, __spreadValues({ extension }, defaultStyles[extension])));
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
var htmlRenderer = {
|
|
103
|
-
canRender: ({ mimeType }) => mimeType === "text/html",
|
|
104
|
-
Component({ src, onLoad, onError }) {
|
|
105
|
-
const [data, setData] = useState("");
|
|
106
|
-
useEffect(() => {
|
|
107
|
-
const controller = new AbortController();
|
|
108
|
-
fetchResource(src, "text", controller.signal).then((data2) => {
|
|
109
|
-
setData(data2);
|
|
110
|
-
onLoad();
|
|
111
|
-
}).catch(onError);
|
|
112
|
-
return () => controller.abort();
|
|
113
|
-
}, [src]);
|
|
114
|
-
return /* @__PURE__ */ React.createElement("iframe", { className: "rfpe-iframe", src: `data:text/html; charset=utf-8,${encodeURIComponent(data)}`, sandbox: "" });
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
var imageRenderer = {
|
|
118
|
-
canRender: ({ mimeType }) => mimeType.startsWith("image/"),
|
|
119
|
-
Component({ src, fileName, onLoad, onError }) {
|
|
120
|
-
return /* @__PURE__ */ React.createElement("img", { className: "rfpe-image", src, alt: fileName || "Image preview", onLoad, onError });
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
var pdfRenderer = {
|
|
124
|
-
canRender: ({ mimeType }) => mimeType === "application/pdf",
|
|
125
|
-
Component({ src, onLoad, onError }) {
|
|
126
|
-
const [data, setData] = useState("");
|
|
127
|
-
useEffect(() => {
|
|
128
|
-
const controller = new AbortController();
|
|
129
|
-
let objectUrl;
|
|
130
|
-
fetchResource(src, "arrayBuffer", controller.signal).then((buffer) => {
|
|
131
|
-
const blob = new Blob([buffer], { type: "application/pdf" });
|
|
132
|
-
objectUrl = URL.createObjectURL(blob);
|
|
133
|
-
setData(objectUrl);
|
|
134
|
-
onLoad();
|
|
135
|
-
}).catch(onError);
|
|
136
|
-
return () => {
|
|
137
|
-
controller.abort();
|
|
138
|
-
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
139
|
-
};
|
|
140
|
-
}, [src]);
|
|
141
|
-
return /* @__PURE__ */ React.createElement("iframe", { className: "rfpe-iframe", src: data });
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
var textRenderer = {
|
|
145
|
-
canRender: ({ mimeType }) => mimeType === "text/plain",
|
|
146
|
-
Component({ src, onLoad, onError }) {
|
|
147
|
-
const [data, setData] = useState("");
|
|
148
|
-
useEffect(() => {
|
|
149
|
-
const controller = new AbortController();
|
|
150
|
-
fetchResource(src, "text", controller.signal).then((data2) => {
|
|
151
|
-
setData(data2);
|
|
152
|
-
onLoad();
|
|
153
|
-
}).catch(onError);
|
|
154
|
-
return () => controller.abort();
|
|
155
|
-
}, [src]);
|
|
156
|
-
return /* @__PURE__ */ React.createElement("div", { className: "rfpe-text" }, data);
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
var videoRenderer = {
|
|
160
|
-
canRender: ({ mimeType }) => mimeType.startsWith("video/"),
|
|
161
|
-
Component({ src, mimeType, fileName, autoPlay, onLoad, onError }) {
|
|
162
|
-
return /* @__PURE__ */ React.createElement("video", { className: "rfpe-video", controls: true, autoPlay, onCanPlay: onLoad, onError, "aria-label": fileName || "Video preview" }, /* @__PURE__ */ React.createElement("source", { src, type: mimeType }));
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
var defaultRenderers = [textRenderer, pdfRenderer, htmlRenderer, imageRenderer, audioRenderer, videoRenderer];
|
|
166
|
-
function resolveRenderer(customRenderers, ctx) {
|
|
167
|
-
var _a;
|
|
168
|
-
return (_a = customRenderers.concat(defaultRenderers).find((r) => {
|
|
169
|
-
var _a2;
|
|
170
|
-
return (_a2 = r.canRender) == null ? void 0 : _a2.call(r, ctx);
|
|
171
|
-
})) != null ? _a : fallbackRenderer;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// src/styles.css
|
|
175
|
-
function injectStyle(css) {
|
|
176
|
-
if (typeof document === "undefined") return;
|
|
177
|
-
const head = document.head || document.getElementsByTagName("head")[0];
|
|
178
|
-
const style = document.createElement("style");
|
|
179
|
-
style.type = "text/css";
|
|
180
|
-
if (head.firstChild) {
|
|
181
|
-
head.insertBefore(style, head.firstChild);
|
|
182
|
-
} else {
|
|
183
|
-
head.appendChild(style);
|
|
184
|
-
}
|
|
185
|
-
if (style.styleSheet) {
|
|
186
|
-
style.styleSheet.cssText = css;
|
|
187
|
-
} else {
|
|
188
|
-
style.appendChild(document.createTextNode(css));
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
injectStyle("@layer rfpe {\n :where(.rfpe-container) {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n max-width: 100lvw;\n max-width: 100vw;\n }\n :where(.rfpe-icon) {\n width: 50px;\n }\n}\n.rfpe-audio {\n width: 100%;\n}\n.rfpe-iframe {\n background-color: white;\n}\n.rfpe-iframe,\n.rfpe-image,\n.rfpe-video {\n width: 100%;\n height: 100%;\n}\n.rfpe-image,\n.rfpe-video {\n object-fit: contain;\n}\n.rfpe-text {\n width: 100%;\n height: 100%;\n overflow: auto;\n white-space: pre-wrap;\n}\n.rfpe-loader {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n}\n.rfpe-loader-spinner {\n box-sizing: border-box;\n width: 22px;\n aspect-ratio: 1;\n border-radius: 50%;\n border: 2px solid transparent;\n border-top-color: black;\n border-bottom-color: black;\n animation: rfpe-spin-fast 0.6s ease infinite;\n}\n.rfpe-loader-text {\n font-size: 0.875rem;\n}\n@keyframes rfpe-spin-fast {\n to {\n transform: rotate(360deg);\n }\n}\n");
|
|
192
|
-
|
|
193
|
-
// src/components.tsx
|
|
194
|
-
var { additionalContext: defaultContext, customRenderers: defaultRenderers2, props: defaultProps } = defaults;
|
|
195
|
-
function FilePreviewer({
|
|
196
|
-
src,
|
|
197
|
-
mimeType,
|
|
198
|
-
fileName = "",
|
|
199
|
-
autoPlay = false,
|
|
200
|
-
loader = /* @__PURE__ */ React.createElement(Loader, null),
|
|
201
|
-
customRenderers = defaultRenderers2,
|
|
202
|
-
additionalContext = defaultContext,
|
|
203
|
-
errorRenderer = fallbackRenderer,
|
|
204
|
-
containerProps = defaultProps,
|
|
205
|
-
iconProps = defaultProps,
|
|
206
|
-
onLoad,
|
|
207
|
-
onError
|
|
208
|
-
}) {
|
|
209
|
-
const resolvedSrc = useResolvedSrc(src);
|
|
210
|
-
const fileType = useMemo(() => getFileType(mimeType, fileName), [mimeType, fileName]);
|
|
211
|
-
const fileKey = `${resolvedSrc}|${fileType}|${fileName}`;
|
|
212
|
-
const [state, setState] = useState({ key: fileKey, status: "loading" });
|
|
213
|
-
if (state.key !== fileKey) setState({ key: fileKey, status: "loading" });
|
|
214
|
-
const isLoading = state.status === "loading";
|
|
215
|
-
const handleLoad = () => {
|
|
216
|
-
setState((prev) => {
|
|
217
|
-
if (prev.key !== fileKey || prev.status !== "loading") return prev;
|
|
218
|
-
onLoad == null ? void 0 : onLoad();
|
|
219
|
-
return { key: fileKey, status: "ready" };
|
|
220
|
-
});
|
|
221
|
-
};
|
|
222
|
-
const handleError = () => {
|
|
223
|
-
setState((prev) => {
|
|
224
|
-
if (prev.key !== fileKey || prev.status === "error") return prev;
|
|
225
|
-
onError == null ? void 0 : onError();
|
|
226
|
-
return { key: fileKey, status: "error" };
|
|
227
|
-
});
|
|
228
|
-
};
|
|
229
|
-
const context = __spreadValues({ src: resolvedSrc, mimeType: fileType, fileName, autoPlay, iconProps, onLoad: handleLoad, onError: handleError }, additionalContext);
|
|
230
|
-
const renderer = useMemo(() => resolveRenderer(customRenderers, context), [resolvedSrc, fileType, fileName, autoPlay, additionalContext]);
|
|
231
|
-
const ActiveRenderer = state.status === "error" ? errorRenderer : renderer;
|
|
232
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, isLoading && loader, /* @__PURE__ */ React.createElement("div", __spreadValues({}, composeProps("rfpe-container", containerProps, { style: { visibility: isLoading ? "hidden" : "visible" } })), /* @__PURE__ */ React.createElement(ActiveRenderer.Component, __spreadValues({ key: fileKey }, context))));
|
|
233
|
-
}
|
|
234
|
-
function Loader({ children, text }) {
|
|
235
|
-
return /* @__PURE__ */ React.createElement("div", { className: "rfpe-loader" }, /* @__PURE__ */ React.createElement("div", { className: "rfpe-loader-spinner" }), children != null ? children : /* @__PURE__ */ React.createElement("div", { className: "rfpe-loader-text" }, text));
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export { FilePreviewer };
|
package/dist/components.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { FilePreviewerProps } from './types.js';
|
|
3
|
-
|
|
4
|
-
declare function FilePreviewer<T extends object = {}>({ src, mimeType, fileName, autoPlay, loader, customRenderers, additionalContext, errorRenderer, containerProps, iconProps, onLoad, onError, }: FilePreviewerProps<T>): React.JSX.Element;
|
|
5
|
-
|
|
6
|
-
export { FilePreviewer as default };
|
package/dist/components.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { FilePreviewer as default } from './chunks/chunk-YEB7RW6X.js';
|
package/dist/index.d.ts
DELETED
package/dist/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { FilePreviewer as default } from './chunks/chunk-YEB7RW6X.js';
|
package/dist/types.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { ReactNode, DetailedHTMLProps, HTMLAttributes } from 'react';
|
|
2
|
-
|
|
3
|
-
type LoaderProps = {
|
|
4
|
-
children?: ReactNode;
|
|
5
|
-
text?: string;
|
|
6
|
-
};
|
|
7
|
-
type EventHandler = () => void;
|
|
8
|
-
type RenderBehaviour = {
|
|
9
|
-
autoPlay: boolean;
|
|
10
|
-
iconProps: DivProps;
|
|
11
|
-
onLoad: EventHandler;
|
|
12
|
-
onError: EventHandler;
|
|
13
|
-
};
|
|
14
|
-
type RenderContext<T extends object = {}> = {
|
|
15
|
-
src: string;
|
|
16
|
-
mimeType: string;
|
|
17
|
-
fileName: string;
|
|
18
|
-
} & RenderBehaviour & T;
|
|
19
|
-
type Renderer<T extends object = {}> = {
|
|
20
|
-
name?: string;
|
|
21
|
-
canRender?(ctx: RenderContext<T>): boolean;
|
|
22
|
-
Component(ctx: RenderContext<T>): ReactNode;
|
|
23
|
-
};
|
|
24
|
-
type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
|
25
|
-
type FetchType = "text" | "arrayBuffer" | "blob" | "json";
|
|
26
|
-
type FilePreviewerProps<T extends object> = {
|
|
27
|
-
src: FileSource;
|
|
28
|
-
loader?: ReactNode;
|
|
29
|
-
customRenderers?: Renderer<T>[];
|
|
30
|
-
additionalContext?: T;
|
|
31
|
-
errorRenderer?: Renderer<T>;
|
|
32
|
-
containerProps?: DivProps;
|
|
33
|
-
} & MimeTypeSource & Partial<RenderBehaviour>;
|
|
34
|
-
type FileSource = string | File | Blob | ArrayBuffer;
|
|
35
|
-
type MimeTypeSource = {
|
|
36
|
-
mimeType: string;
|
|
37
|
-
fileName?: string;
|
|
38
|
-
} | {
|
|
39
|
-
fileName: string;
|
|
40
|
-
mimeType?: string;
|
|
41
|
-
};
|
|
42
|
-
type State = {
|
|
43
|
-
key: string;
|
|
44
|
-
status: "loading" | "ready" | "error";
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export type { DivProps, EventHandler, FetchType, FilePreviewerProps, FileSource, LoaderProps, MimeTypeSource, RenderBehaviour, RenderContext, Renderer, State };
|
package/dist/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|