react-file-preview-engine 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -302,7 +302,9 @@ You can explore the actual renderer definitions in the [`defaultRenderers` const
302
302
 
303
303
  ## API Reference
304
304
 
305
- ### FilePreviewer Props
305
+ ### FilePreviewer Component
306
+
307
+ Here is the full API for the `<FilePreviewer>` component, these properties can be set on an instance of FilePreviewer:
306
308
 
307
309
  | Prop | Type | Required | Default | Description |
308
310
  | ------------------- | ------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
@@ -324,7 +326,7 @@ You can explore the actual renderer definitions in the [`defaultRenderers` const
324
326
  ### DivProps
325
327
 
326
328
  ```typescript
327
- import { DetailedHTMLProps, HTMLAttributes } from "react";
329
+ import type { DetailedHTMLProps, HTMLAttributes } from "react";
328
330
 
329
331
  type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
330
332
  ```
@@ -360,6 +362,6 @@ type Renderer<T extends object = {}> = {
360
362
  };
361
363
  ```
362
364
 
363
- ## Author
365
+ ## License
364
366
 
365
- [Sahil Aggarwal](https://github.com/SahilAggarwal2004)
367
+ This project is licensed under the [MIT License](LICENSE).
@@ -0,0 +1,238 @@
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 };
@@ -0,0 +1,6 @@
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 };
@@ -0,0 +1 @@
1
+ export { FilePreviewer as default } from './chunks/chunk-YEB7RW6X.js';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,3 @@
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 };
1
+ export { default } from './components.js';
2
+ import 'react';
3
+ import './types.js';
package/dist/index.js CHANGED
@@ -1,238 +1 @@
1
- import React2, { 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
- function Loader({ children, text }) {
45
- return /* @__PURE__ */ React2.createElement("div", { className: "rfpe-loader" }, /* @__PURE__ */ React2.createElement("div", { className: "rfpe-loader-spinner" }), children != null ? children : /* @__PURE__ */ React2.createElement("div", { className: "rfpe-loader-text" }, text));
46
- }
47
-
48
- // src/constants.ts
49
- var defaults = { additionalContext: {}, customRenderers: [], props: {} };
50
- var fileExtensionRegex = /\.([^.]+)$/;
51
- function useResolvedSrc(src) {
52
- const objectUrlRef = useRef(null);
53
- const revokeObjectURL = () => {
54
- if (!objectUrlRef.current) return;
55
- URL.revokeObjectURL(objectUrlRef.current);
56
- objectUrlRef.current = null;
57
- };
58
- const resolvedSrc = useMemo(() => {
59
- revokeObjectURL();
60
- if (typeof src === "string") return src;
61
- const url = src instanceof File || src instanceof Blob ? URL.createObjectURL(src) : src instanceof ArrayBuffer ? URL.createObjectURL(new Blob([src])) : "";
62
- if (url) objectUrlRef.current = url;
63
- return url;
64
- }, [src]);
65
- useEffect(() => revokeObjectURL, []);
66
- return resolvedSrc;
67
- }
68
- var composeClass = (baseClass, props) => `${baseClass}${(props == null ? void 0 : props.className) ? " " + props.className : ""}`;
69
- var composeProps = (baseClass, props, overrideProps) => {
70
- const mergedProps = __spreadValues(__spreadValues({}, props), overrideProps);
71
- return __spreadProps(__spreadValues({}, mergedProps), {
72
- style: __spreadValues(__spreadValues({}, props == null ? void 0 : props.style), overrideProps == null ? void 0 : overrideProps.style),
73
- className: composeClass(baseClass, mergedProps)
74
- });
75
- };
76
- function fetchResource(src, type, signal) {
77
- return __async(this, null, function* () {
78
- const res = yield fetch(src, { signal });
79
- if (!res.ok) throw new Error();
80
- return res[type]();
81
- });
82
- }
83
- var getFileExtension = (mimeType, fileName) => {
84
- var _a;
85
- return Mime.getExtension(mimeType) || ((_a = fileName == null ? void 0 : fileName.match(fileExtensionRegex)) == null ? void 0 : _a[1]) || "";
86
- };
87
- var getFileType = (mimeType, fileName) => mimeType || fileName && Mime.getType(fileName) || "";
88
-
89
- // src/lib/rendererRegistry.tsx
90
- var audioRenderer = {
91
- canRender: ({ mimeType }) => mimeType.startsWith("audio/"),
92
- Component({ src, mimeType, fileName, autoPlay, onLoad, onError }) {
93
- return /* @__PURE__ */ React2.createElement("audio", { className: "rfpe-audio", controls: true, autoPlay, onCanPlay: onLoad, onError, "aria-label": fileName || "Audio preview" }, /* @__PURE__ */ React2.createElement("source", { src, type: mimeType }));
94
- }
95
- };
96
- var fallbackRenderer = {
97
- Component({ mimeType, fileName, iconProps, onLoad }) {
98
- const extension = useMemo(() => getFileExtension(mimeType, fileName), [mimeType, fileName]);
99
- useEffect(() => {
100
- onLoad();
101
- }, []);
102
- return /* @__PURE__ */ React2.createElement("div", __spreadValues({}, composeProps("rfpe-icon", iconProps)), /* @__PURE__ */ React2.createElement(FileIcon, __spreadValues({ extension }, defaultStyles[extension])));
103
- }
104
- };
105
- var htmlRenderer = {
106
- canRender: ({ mimeType }) => mimeType === "text/html",
107
- Component({ src, onLoad, onError }) {
108
- const [data, setData] = useState("");
109
- useEffect(() => {
110
- const controller = new AbortController();
111
- fetchResource(src, "text", controller.signal).then((data2) => {
112
- setData(data2);
113
- onLoad();
114
- }).catch(onError);
115
- return () => controller.abort();
116
- }, [src]);
117
- return /* @__PURE__ */ React2.createElement("iframe", { className: "rfpe-iframe", src: `data:text/html; charset=utf-8,${encodeURIComponent(data)}`, sandbox: "" });
118
- }
119
- };
120
- var imageRenderer = {
121
- canRender: ({ mimeType }) => mimeType.startsWith("image/"),
122
- Component({ src, fileName, onLoad, onError }) {
123
- return /* @__PURE__ */ React2.createElement("img", { className: "rfpe-image", src, alt: fileName || "Image preview", onLoad, onError });
124
- }
125
- };
126
- var pdfRenderer = {
127
- canRender: ({ mimeType }) => mimeType === "application/pdf",
128
- Component({ src, onLoad, onError }) {
129
- const [data, setData] = useState("");
130
- useEffect(() => {
131
- const controller = new AbortController();
132
- let objectUrl;
133
- fetchResource(src, "arrayBuffer", controller.signal).then((buffer) => {
134
- const blob = new Blob([buffer], { type: "application/pdf" });
135
- objectUrl = URL.createObjectURL(blob);
136
- setData(objectUrl);
137
- onLoad();
138
- }).catch(onError);
139
- return () => {
140
- controller.abort();
141
- if (objectUrl) URL.revokeObjectURL(objectUrl);
142
- };
143
- }, [src]);
144
- return /* @__PURE__ */ React2.createElement("iframe", { className: "rfpe-iframe", src: data });
145
- }
146
- };
147
- var textRenderer = {
148
- canRender: ({ mimeType }) => mimeType === "text/plain",
149
- Component({ src, onLoad, onError }) {
150
- const [data, setData] = useState("");
151
- useEffect(() => {
152
- const controller = new AbortController();
153
- fetchResource(src, "text", controller.signal).then((data2) => {
154
- setData(data2);
155
- onLoad();
156
- }).catch(onError);
157
- return () => controller.abort();
158
- }, [src]);
159
- return /* @__PURE__ */ React2.createElement("div", { className: "rfpe-text" }, data);
160
- }
161
- };
162
- var videoRenderer = {
163
- canRender: ({ mimeType }) => mimeType.startsWith("video/"),
164
- Component({ src, mimeType, fileName, autoPlay, onLoad, onError }) {
165
- return /* @__PURE__ */ React2.createElement("video", { className: "rfpe-video", controls: true, autoPlay, onCanPlay: onLoad, onError, "aria-label": fileName || "Video preview" }, /* @__PURE__ */ React2.createElement("source", { src, type: mimeType }));
166
- }
167
- };
168
- var defaultRenderers = [textRenderer, pdfRenderer, htmlRenderer, imageRenderer, audioRenderer, videoRenderer];
169
- function resolveRenderer(customRenderers, ctx) {
170
- var _a;
171
- return (_a = customRenderers.concat(defaultRenderers).find((r) => {
172
- var _a2;
173
- return (_a2 = r.canRender) == null ? void 0 : _a2.call(r, ctx);
174
- })) != null ? _a : fallbackRenderer;
175
- }
176
-
177
- // src/styles.css
178
- function injectStyle(css) {
179
- if (typeof document === "undefined") return;
180
- const head = document.head || document.getElementsByTagName("head")[0];
181
- const style = document.createElement("style");
182
- style.type = "text/css";
183
- if (head.firstChild) {
184
- head.insertBefore(style, head.firstChild);
185
- } else {
186
- head.appendChild(style);
187
- }
188
- if (style.styleSheet) {
189
- style.styleSheet.cssText = css;
190
- } else {
191
- style.appendChild(document.createTextNode(css));
192
- }
193
- }
194
- 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");
195
-
196
- // src/index.tsx
197
- var { additionalContext: defaultContext, customRenderers: defaultRenderers2, props: defaultProps } = defaults;
198
- function FilePreviewer({
199
- src,
200
- mimeType,
201
- fileName = "",
202
- autoPlay = false,
203
- loader = /* @__PURE__ */ React2.createElement(Loader, null),
204
- customRenderers = defaultRenderers2,
205
- additionalContext = defaultContext,
206
- errorRenderer = fallbackRenderer,
207
- containerProps = defaultProps,
208
- iconProps = defaultProps,
209
- onLoad,
210
- onError
211
- }) {
212
- const resolvedSrc = useResolvedSrc(src);
213
- const fileType = useMemo(() => getFileType(mimeType, fileName), [mimeType, fileName]);
214
- const fileKey = `${resolvedSrc}|${fileType}|${fileName}`;
215
- const [state, setState] = useState({ key: fileKey, status: "loading" });
216
- if (state.key !== fileKey) setState({ key: fileKey, status: "loading" });
217
- const isLoading = state.status === "loading";
218
- const handleLoad = () => {
219
- setState((prev) => {
220
- if (prev.key !== fileKey || prev.status !== "loading") return prev;
221
- onLoad == null ? void 0 : onLoad();
222
- return { key: fileKey, status: "ready" };
223
- });
224
- };
225
- const handleError = () => {
226
- setState((prev) => {
227
- if (prev.key !== fileKey || prev.status === "error") return prev;
228
- onError == null ? void 0 : onError();
229
- return { key: fileKey, status: "error" };
230
- });
231
- };
232
- const context = __spreadValues({ src: resolvedSrc, mimeType: fileType, fileName, autoPlay, iconProps, onLoad: handleLoad, onError: handleError }, additionalContext);
233
- const renderer = useMemo(() => resolveRenderer(customRenderers, context), [resolvedSrc, fileType, fileName, autoPlay, additionalContext]);
234
- const ActiveRenderer = state.status === "error" ? errorRenderer : renderer;
235
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, isLoading && loader, /* @__PURE__ */ React2.createElement("div", __spreadValues({}, composeProps("rfpe-container", containerProps, { style: { visibility: isLoading ? "hidden" : "visible" } })), /* @__PURE__ */ React2.createElement(ActiveRenderer.Component, __spreadValues({ key: fileKey }, context))));
236
- }
237
-
238
- export { FilePreviewer as default };
1
+ export { FilePreviewer as default } from './chunks/chunk-YEB7RW6X.js';
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ReactNode, DetailedHTMLProps, HTMLAttributes, JSX } from 'react';
1
+ import { ReactNode, DetailedHTMLProps, HTMLAttributes } from 'react';
2
2
 
3
3
  type LoaderProps = {
4
4
  children?: ReactNode;
@@ -19,7 +19,7 @@ type RenderContext<T extends object = {}> = {
19
19
  type Renderer<T extends object = {}> = {
20
20
  name?: string;
21
21
  canRender?(ctx: RenderContext<T>): boolean;
22
- Component(ctx: RenderContext<T>): JSX.Element;
22
+ Component(ctx: RenderContext<T>): ReactNode;
23
23
  };
24
24
  type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
25
25
  type FetchType = "text" | "arrayBuffer" | "blob" | "json";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-file-preview-engine",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
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>",
@@ -14,34 +14,35 @@
14
14
  "url": "https://github.com/SahilAggarwal2004/react-file-preview-engine/issues"
15
15
  },
16
16
  "type": "module",
17
- "files": [
18
- "dist"
19
- ],
20
17
  "exports": {
21
18
  ".": "./dist/index.js",
22
19
  "./types": "./dist/types.js"
23
20
  },
24
21
  "main": "dist/index.js",
25
- "types": "dist/index.d.ts",
22
+ "files": [
23
+ "dist"
24
+ ],
26
25
  "sideEffects": [
27
26
  "**/*.css"
28
27
  ],
28
+ "types": "dist/index.d.ts",
29
29
  "dependencies": {
30
30
  "mime": "^4.1.0",
31
31
  "react-file-icon": "^1.6.0"
32
32
  },
33
+ "peerDependencies": {
34
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
35
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
36
+ },
33
37
  "devDependencies": {
34
38
  "@release-it/conventional-changelog": "^10.0.4",
35
39
  "@types/react": "^19.2.7",
36
40
  "@types/react-file-icon": "^1.0.4",
41
+ "prettier-package-json": "^2.8.0",
37
42
  "release-it": "^19.2.2",
38
43
  "tsup": "^8.5.1",
39
44
  "typescript": "^5.9.3"
40
45
  },
41
- "peerDependencies": {
42
- "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
43
- "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
44
- },
45
46
  "keywords": [
46
47
  "arraybuffer",
47
48
  "audio-preview",
@@ -69,6 +70,8 @@
69
70
  "compile": "tsup",
70
71
  "dev": "tsup --watch",
71
72
  "dry-release": "release-it --ci --dry-run",
73
+ "prettier": "prettier-package-json --write package.json",
74
+ "pub": "pnpm login && pnpm publish",
72
75
  "release": "release-it --ci"
73
76
  }
74
77
  }