@plugable-io/react 0.0.5 → 0.0.7
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/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +66 -18
- package/dist/index.mjs +67 -19
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -92,8 +92,9 @@ interface FileImageProps {
|
|
|
92
92
|
style?: CSSProperties;
|
|
93
93
|
onLoad?: () => void;
|
|
94
94
|
onError?: (error: Error) => void;
|
|
95
|
+
onRefetchNeeded?: () => Promise<void>;
|
|
95
96
|
}
|
|
96
|
-
declare function FileImage({ file, width, height, objectFit, borderRadius, alt, className, style, onLoad, onError, }: FileImageProps): react_jsx_runtime.JSX.Element;
|
|
97
|
+
declare function FileImage({ file, width, height, objectFit, borderRadius, alt, className, style, onLoad, onError, onRefetchNeeded, }: FileImageProps): react_jsx_runtime.JSX.Element;
|
|
97
98
|
declare function clearImageCache(): void;
|
|
98
99
|
|
|
99
100
|
interface FilePreviewProps {
|
|
@@ -106,7 +107,7 @@ interface FilePreviewProps {
|
|
|
106
107
|
showExtension?: boolean;
|
|
107
108
|
renderNonImage?: (file: FileObject) => React.ReactNode;
|
|
108
109
|
}
|
|
109
|
-
declare function FilePreview({ file, width, height, className, style, objectFit, showExtension, renderNonImage, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
|
|
110
|
+
declare function FilePreview({ file: initialFile, width, height, className, style, objectFit, showExtension, renderNonImage, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
|
|
110
111
|
|
|
111
112
|
interface UseFilesOptions {
|
|
112
113
|
metadata?: Record<string, any>;
|
package/dist/index.d.ts
CHANGED
|
@@ -92,8 +92,9 @@ interface FileImageProps {
|
|
|
92
92
|
style?: CSSProperties;
|
|
93
93
|
onLoad?: () => void;
|
|
94
94
|
onError?: (error: Error) => void;
|
|
95
|
+
onRefetchNeeded?: () => Promise<void>;
|
|
95
96
|
}
|
|
96
|
-
declare function FileImage({ file, width, height, objectFit, borderRadius, alt, className, style, onLoad, onError, }: FileImageProps): react_jsx_runtime.JSX.Element;
|
|
97
|
+
declare function FileImage({ file, width, height, objectFit, borderRadius, alt, className, style, onLoad, onError, onRefetchNeeded, }: FileImageProps): react_jsx_runtime.JSX.Element;
|
|
97
98
|
declare function clearImageCache(): void;
|
|
98
99
|
|
|
99
100
|
interface FilePreviewProps {
|
|
@@ -106,7 +107,7 @@ interface FilePreviewProps {
|
|
|
106
107
|
showExtension?: boolean;
|
|
107
108
|
renderNonImage?: (file: FileObject) => React.ReactNode;
|
|
108
109
|
}
|
|
109
|
-
declare function FilePreview({ file, width, height, className, style, objectFit, showExtension, renderNonImage, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
|
|
110
|
+
declare function FilePreview({ file: initialFile, width, height, className, style, objectFit, showExtension, renderNonImage, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
|
|
110
111
|
|
|
111
112
|
interface UseFilesOptions {
|
|
112
113
|
metadata?: Record<string, any>;
|
package/dist/index.js
CHANGED
|
@@ -579,11 +579,13 @@ function FileImage({
|
|
|
579
579
|
className,
|
|
580
580
|
style,
|
|
581
581
|
onLoad,
|
|
582
|
-
onError
|
|
582
|
+
onError,
|
|
583
|
+
onRefetchNeeded
|
|
583
584
|
}) {
|
|
584
585
|
const [imageSrc, setImageSrc] = (0, import_react4.useState)(null);
|
|
585
586
|
const [isLoading, setIsLoading] = (0, import_react4.useState)(true);
|
|
586
587
|
const [error, setError] = (0, import_react4.useState)(null);
|
|
588
|
+
const refetchAttemptedRef = (0, import_react4.useRef)(null);
|
|
587
589
|
(0, import_react4.useEffect)(() => {
|
|
588
590
|
let isMounted = true;
|
|
589
591
|
let objectUrl = null;
|
|
@@ -599,21 +601,47 @@ function FileImage({
|
|
|
599
601
|
return;
|
|
600
602
|
}
|
|
601
603
|
if (file.download_url) {
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
604
|
+
let response = null;
|
|
605
|
+
try {
|
|
606
|
+
response = await fetch(file.download_url, {
|
|
607
|
+
headers: {
|
|
608
|
+
"Cache-Control": "private, max-age=31536000",
|
|
609
|
+
"If-None-Match": file.checksum
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
if (!response.ok) {
|
|
613
|
+
const downloadUrlKey = `${file.id}-${file.download_url}`;
|
|
614
|
+
if (response.status === 403 && onRefetchNeeded && refetchAttemptedRef.current !== downloadUrlKey) {
|
|
615
|
+
refetchAttemptedRef.current = downloadUrlKey;
|
|
616
|
+
imageCache.delete(cacheKey);
|
|
617
|
+
await onRefetchNeeded();
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
throw new Error(`Failed to fetch image: ${response.statusText}`);
|
|
606
621
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
622
|
+
const blob = await response.blob();
|
|
623
|
+
objectUrl = URL.createObjectURL(blob);
|
|
624
|
+
imageCache.set(cacheKey, objectUrl);
|
|
625
|
+
if (isMounted) {
|
|
626
|
+
setImageSrc(objectUrl);
|
|
627
|
+
setIsLoading(false);
|
|
628
|
+
refetchAttemptedRef.current = null;
|
|
629
|
+
}
|
|
630
|
+
} catch (fetchError) {
|
|
631
|
+
const downloadUrlKey = `${file.id}-${file.download_url}`;
|
|
632
|
+
const isNetworkError = !response && (fetchError.message?.includes("Failed to fetch") || fetchError.message?.includes("CORS") || fetchError.name === "TypeError" || fetchError.message?.includes("network") || fetchError.message?.includes("ERR_FAILED"));
|
|
633
|
+
const is403Error = response?.status === 403;
|
|
634
|
+
if ((isNetworkError || is403Error) && onRefetchNeeded && refetchAttemptedRef.current !== downloadUrlKey) {
|
|
635
|
+
refetchAttemptedRef.current = downloadUrlKey;
|
|
636
|
+
imageCache.delete(cacheKey);
|
|
637
|
+
try {
|
|
638
|
+
await onRefetchNeeded();
|
|
639
|
+
return;
|
|
640
|
+
} catch (refetchError) {
|
|
641
|
+
console.error("Failed to refetch file:", refetchError);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
throw fetchError;
|
|
617
645
|
}
|
|
618
646
|
} else {
|
|
619
647
|
throw new Error("No download URL available for file");
|
|
@@ -632,7 +660,7 @@ function FileImage({
|
|
|
632
660
|
return () => {
|
|
633
661
|
isMounted = false;
|
|
634
662
|
};
|
|
635
|
-
}, [file.id, file.checksum, file.download_url, onError]);
|
|
663
|
+
}, [file.id, file.checksum, file.download_url, onError, onRefetchNeeded]);
|
|
636
664
|
const handleLoad = () => {
|
|
637
665
|
setIsLoading(false);
|
|
638
666
|
onLoad?.();
|
|
@@ -722,9 +750,10 @@ function clearImageCache() {
|
|
|
722
750
|
}
|
|
723
751
|
|
|
724
752
|
// src/components/FilePreview.tsx
|
|
753
|
+
var import_react5 = require("react");
|
|
725
754
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
726
755
|
function FilePreview({
|
|
727
|
-
file,
|
|
756
|
+
file: initialFile,
|
|
728
757
|
width = 80,
|
|
729
758
|
height = 80,
|
|
730
759
|
className,
|
|
@@ -733,6 +762,24 @@ function FilePreview({
|
|
|
733
762
|
showExtension = true,
|
|
734
763
|
renderNonImage
|
|
735
764
|
}) {
|
|
765
|
+
const { client } = usePlugable();
|
|
766
|
+
const [file, setFile] = (0, import_react5.useState)(initialFile);
|
|
767
|
+
const [isRefetching, setIsRefetching] = (0, import_react5.useState)(false);
|
|
768
|
+
(0, import_react5.useEffect)(() => {
|
|
769
|
+
setFile(initialFile);
|
|
770
|
+
}, [initialFile.id, initialFile.download_url]);
|
|
771
|
+
const handleRefetch = (0, import_react5.useCallback)(async () => {
|
|
772
|
+
if (isRefetching) return;
|
|
773
|
+
try {
|
|
774
|
+
setIsRefetching(true);
|
|
775
|
+
const refreshedFile = await client.get(file.id);
|
|
776
|
+
setFile(refreshedFile);
|
|
777
|
+
} catch (err) {
|
|
778
|
+
console.error("Failed to refetch file:", err);
|
|
779
|
+
} finally {
|
|
780
|
+
setIsRefetching(false);
|
|
781
|
+
}
|
|
782
|
+
}, [file.id, client]);
|
|
736
783
|
const isImage = file.content_type.startsWith("image/");
|
|
737
784
|
const containerStyle = {
|
|
738
785
|
width,
|
|
@@ -756,7 +803,8 @@ function FilePreview({
|
|
|
756
803
|
objectFit,
|
|
757
804
|
className,
|
|
758
805
|
style,
|
|
759
|
-
borderRadius: 4
|
|
806
|
+
borderRadius: 4,
|
|
807
|
+
onRefetchNeeded: handleRefetch
|
|
760
808
|
}
|
|
761
809
|
);
|
|
762
810
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -523,7 +523,7 @@ function FileList({
|
|
|
523
523
|
}
|
|
524
524
|
|
|
525
525
|
// src/components/FileImage.tsx
|
|
526
|
-
import { useEffect as useEffect2, useState as useState4 } from "react";
|
|
526
|
+
import { useEffect as useEffect2, useState as useState4, useRef as useRef3 } from "react";
|
|
527
527
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
528
528
|
var imageCache = /* @__PURE__ */ new Map();
|
|
529
529
|
function FileImage({
|
|
@@ -536,11 +536,13 @@ function FileImage({
|
|
|
536
536
|
className,
|
|
537
537
|
style,
|
|
538
538
|
onLoad,
|
|
539
|
-
onError
|
|
539
|
+
onError,
|
|
540
|
+
onRefetchNeeded
|
|
540
541
|
}) {
|
|
541
542
|
const [imageSrc, setImageSrc] = useState4(null);
|
|
542
543
|
const [isLoading, setIsLoading] = useState4(true);
|
|
543
544
|
const [error, setError] = useState4(null);
|
|
545
|
+
const refetchAttemptedRef = useRef3(null);
|
|
544
546
|
useEffect2(() => {
|
|
545
547
|
let isMounted = true;
|
|
546
548
|
let objectUrl = null;
|
|
@@ -556,21 +558,47 @@ function FileImage({
|
|
|
556
558
|
return;
|
|
557
559
|
}
|
|
558
560
|
if (file.download_url) {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
561
|
+
let response = null;
|
|
562
|
+
try {
|
|
563
|
+
response = await fetch(file.download_url, {
|
|
564
|
+
headers: {
|
|
565
|
+
"Cache-Control": "private, max-age=31536000",
|
|
566
|
+
"If-None-Match": file.checksum
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
if (!response.ok) {
|
|
570
|
+
const downloadUrlKey = `${file.id}-${file.download_url}`;
|
|
571
|
+
if (response.status === 403 && onRefetchNeeded && refetchAttemptedRef.current !== downloadUrlKey) {
|
|
572
|
+
refetchAttemptedRef.current = downloadUrlKey;
|
|
573
|
+
imageCache.delete(cacheKey);
|
|
574
|
+
await onRefetchNeeded();
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
throw new Error(`Failed to fetch image: ${response.statusText}`);
|
|
563
578
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
579
|
+
const blob = await response.blob();
|
|
580
|
+
objectUrl = URL.createObjectURL(blob);
|
|
581
|
+
imageCache.set(cacheKey, objectUrl);
|
|
582
|
+
if (isMounted) {
|
|
583
|
+
setImageSrc(objectUrl);
|
|
584
|
+
setIsLoading(false);
|
|
585
|
+
refetchAttemptedRef.current = null;
|
|
586
|
+
}
|
|
587
|
+
} catch (fetchError) {
|
|
588
|
+
const downloadUrlKey = `${file.id}-${file.download_url}`;
|
|
589
|
+
const isNetworkError = !response && (fetchError.message?.includes("Failed to fetch") || fetchError.message?.includes("CORS") || fetchError.name === "TypeError" || fetchError.message?.includes("network") || fetchError.message?.includes("ERR_FAILED"));
|
|
590
|
+
const is403Error = response?.status === 403;
|
|
591
|
+
if ((isNetworkError || is403Error) && onRefetchNeeded && refetchAttemptedRef.current !== downloadUrlKey) {
|
|
592
|
+
refetchAttemptedRef.current = downloadUrlKey;
|
|
593
|
+
imageCache.delete(cacheKey);
|
|
594
|
+
try {
|
|
595
|
+
await onRefetchNeeded();
|
|
596
|
+
return;
|
|
597
|
+
} catch (refetchError) {
|
|
598
|
+
console.error("Failed to refetch file:", refetchError);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
throw fetchError;
|
|
574
602
|
}
|
|
575
603
|
} else {
|
|
576
604
|
throw new Error("No download URL available for file");
|
|
@@ -589,7 +617,7 @@ function FileImage({
|
|
|
589
617
|
return () => {
|
|
590
618
|
isMounted = false;
|
|
591
619
|
};
|
|
592
|
-
}, [file.id, file.checksum, file.download_url, onError]);
|
|
620
|
+
}, [file.id, file.checksum, file.download_url, onError, onRefetchNeeded]);
|
|
593
621
|
const handleLoad = () => {
|
|
594
622
|
setIsLoading(false);
|
|
595
623
|
onLoad?.();
|
|
@@ -679,9 +707,10 @@ function clearImageCache() {
|
|
|
679
707
|
}
|
|
680
708
|
|
|
681
709
|
// src/components/FilePreview.tsx
|
|
710
|
+
import { useState as useState5, useCallback as useCallback4, useEffect as useEffect3 } from "react";
|
|
682
711
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
683
712
|
function FilePreview({
|
|
684
|
-
file,
|
|
713
|
+
file: initialFile,
|
|
685
714
|
width = 80,
|
|
686
715
|
height = 80,
|
|
687
716
|
className,
|
|
@@ -690,6 +719,24 @@ function FilePreview({
|
|
|
690
719
|
showExtension = true,
|
|
691
720
|
renderNonImage
|
|
692
721
|
}) {
|
|
722
|
+
const { client } = usePlugable();
|
|
723
|
+
const [file, setFile] = useState5(initialFile);
|
|
724
|
+
const [isRefetching, setIsRefetching] = useState5(false);
|
|
725
|
+
useEffect3(() => {
|
|
726
|
+
setFile(initialFile);
|
|
727
|
+
}, [initialFile.id, initialFile.download_url]);
|
|
728
|
+
const handleRefetch = useCallback4(async () => {
|
|
729
|
+
if (isRefetching) return;
|
|
730
|
+
try {
|
|
731
|
+
setIsRefetching(true);
|
|
732
|
+
const refreshedFile = await client.get(file.id);
|
|
733
|
+
setFile(refreshedFile);
|
|
734
|
+
} catch (err) {
|
|
735
|
+
console.error("Failed to refetch file:", err);
|
|
736
|
+
} finally {
|
|
737
|
+
setIsRefetching(false);
|
|
738
|
+
}
|
|
739
|
+
}, [file.id, client]);
|
|
693
740
|
const isImage = file.content_type.startsWith("image/");
|
|
694
741
|
const containerStyle = {
|
|
695
742
|
width,
|
|
@@ -713,7 +760,8 @@ function FilePreview({
|
|
|
713
760
|
objectFit,
|
|
714
761
|
className,
|
|
715
762
|
style,
|
|
716
|
-
borderRadius: 4
|
|
763
|
+
borderRadius: 4,
|
|
764
|
+
onRefetchNeeded: handleRefetch
|
|
717
765
|
}
|
|
718
766
|
);
|
|
719
767
|
}
|