@plugable-io/react 0.0.7 → 0.0.10
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 +111 -0
- package/dist/index.d.mts +33 -4
- package/dist/index.d.ts +33 -4
- package/dist/index.js +308 -83
- package/dist/index.mjs +312 -90
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,112 @@
|
|
|
1
1
|
// src/PlugableProvider.tsx
|
|
2
|
-
import { createContext, useContext, useMemo, useCallback, useRef, useState } from "react";
|
|
2
|
+
import { createContext, useContext, useMemo, useCallback, useRef, useState, useEffect } from "react";
|
|
3
3
|
import { BucketClient } from "@plugable-io/js";
|
|
4
|
+
|
|
5
|
+
// src/utils/theme.ts
|
|
6
|
+
var defaultLightTheme = {
|
|
7
|
+
// Purple to blue accent gradient
|
|
8
|
+
accentPrimary: "#9333ea",
|
|
9
|
+
// purple-600
|
|
10
|
+
accentSecondary: "#2563eb",
|
|
11
|
+
// blue-600
|
|
12
|
+
accentHover: "#7c3aed",
|
|
13
|
+
// purple-700
|
|
14
|
+
// Light backgrounds
|
|
15
|
+
baseBg: "#ffffff",
|
|
16
|
+
baseSurface: "#f8fafc",
|
|
17
|
+
// slate-50
|
|
18
|
+
baseBorder: "#e2e8f0",
|
|
19
|
+
// slate-200
|
|
20
|
+
// Dark text on light
|
|
21
|
+
textPrimary: "#0f172a",
|
|
22
|
+
// slate-900
|
|
23
|
+
textSecondary: "#475569",
|
|
24
|
+
// slate-600
|
|
25
|
+
textMuted: "#94a3b8",
|
|
26
|
+
// slate-400
|
|
27
|
+
// State colors
|
|
28
|
+
success: "#10b981",
|
|
29
|
+
// green-500
|
|
30
|
+
error: "#ef4444",
|
|
31
|
+
// red-500
|
|
32
|
+
warning: "#f59e0b",
|
|
33
|
+
// amber-500
|
|
34
|
+
// Overlay
|
|
35
|
+
overlay: "rgba(0, 0, 0, 0.05)",
|
|
36
|
+
backdropBlur: "blur(12px)"
|
|
37
|
+
};
|
|
38
|
+
var defaultDarkTheme = {
|
|
39
|
+
// Purple to blue accent gradient (same as light)
|
|
40
|
+
accentPrimary: "#9333ea",
|
|
41
|
+
accentSecondary: "#2563eb",
|
|
42
|
+
accentHover: "#a855f7",
|
|
43
|
+
// purple-500 (lighter for dark mode)
|
|
44
|
+
// Dark backgrounds
|
|
45
|
+
baseBg: "#0f172a",
|
|
46
|
+
// slate-900
|
|
47
|
+
baseSurface: "rgba(30, 41, 59, 0.5)",
|
|
48
|
+
// slate-800/50 with transparency
|
|
49
|
+
baseBorder: "rgba(255, 255, 255, 0.1)",
|
|
50
|
+
// Light text on dark
|
|
51
|
+
textPrimary: "#f1f5f9",
|
|
52
|
+
// slate-100
|
|
53
|
+
textSecondary: "#cbd5e1",
|
|
54
|
+
// slate-300
|
|
55
|
+
textMuted: "#64748b",
|
|
56
|
+
// slate-500
|
|
57
|
+
// State colors (slightly adjusted for dark mode)
|
|
58
|
+
success: "#34d399",
|
|
59
|
+
// green-400
|
|
60
|
+
error: "#f87171",
|
|
61
|
+
// red-400
|
|
62
|
+
warning: "#fbbf24",
|
|
63
|
+
// amber-400
|
|
64
|
+
// Overlay
|
|
65
|
+
overlay: "rgba(0, 0, 0, 0.3)",
|
|
66
|
+
backdropBlur: "blur(24px)"
|
|
67
|
+
};
|
|
68
|
+
function getThemeColors(config = {}) {
|
|
69
|
+
const { theme = "dark", accentColor, baseColor } = config;
|
|
70
|
+
const isDark = theme === "dark" || theme === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
71
|
+
const colors = isDark ? { ...defaultDarkTheme } : { ...defaultLightTheme };
|
|
72
|
+
if (accentColor) {
|
|
73
|
+
colors.accentPrimary = accentColor;
|
|
74
|
+
colors.accentSecondary = accentColor;
|
|
75
|
+
colors.accentHover = accentColor;
|
|
76
|
+
}
|
|
77
|
+
if (baseColor) {
|
|
78
|
+
colors.baseBg = baseColor;
|
|
79
|
+
colors.baseSurface = baseColor;
|
|
80
|
+
}
|
|
81
|
+
return colors;
|
|
82
|
+
}
|
|
83
|
+
function generateCSSVariables(colors) {
|
|
84
|
+
return {
|
|
85
|
+
"--plugable-accent-primary": colors.accentPrimary,
|
|
86
|
+
"--plugable-accent-secondary": colors.accentSecondary,
|
|
87
|
+
"--plugable-accent-hover": colors.accentHover,
|
|
88
|
+
"--plugable-base-bg": colors.baseBg,
|
|
89
|
+
"--plugable-base-surface": colors.baseSurface,
|
|
90
|
+
"--plugable-base-border": colors.baseBorder,
|
|
91
|
+
"--plugable-text-primary": colors.textPrimary,
|
|
92
|
+
"--plugable-text-secondary": colors.textSecondary,
|
|
93
|
+
"--plugable-text-muted": colors.textMuted,
|
|
94
|
+
"--plugable-success": colors.success,
|
|
95
|
+
"--plugable-error": colors.error,
|
|
96
|
+
"--plugable-warning": colors.warning,
|
|
97
|
+
"--plugable-overlay": colors.overlay,
|
|
98
|
+
"--plugable-backdrop-blur": colors.backdropBlur
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function applyCSSVariables(element, config = {}) {
|
|
102
|
+
const colors = getThemeColors(config);
|
|
103
|
+
const variables = generateCSSVariables(colors);
|
|
104
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
105
|
+
element.style.setProperty(key, value);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/PlugableProvider.tsx
|
|
4
110
|
import { jsx } from "react/jsx-runtime";
|
|
5
111
|
var PlugableContext = createContext(null);
|
|
6
112
|
function createAuthTokenGetter(authProvider, clerkJWTTemplate) {
|
|
@@ -45,6 +151,13 @@ function createAuthTokenGetter(authProvider, clerkJWTTemplate) {
|
|
|
45
151
|
"Firebase not found. Please ensure firebase is installed and initialized, or provide a custom getToken function."
|
|
46
152
|
);
|
|
47
153
|
};
|
|
154
|
+
case "generic_jwks":
|
|
155
|
+
case "generic_jwt":
|
|
156
|
+
return async () => {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`Manual token required for ${authProvider}. Please provide a custom getToken function.`
|
|
159
|
+
);
|
|
160
|
+
};
|
|
48
161
|
default:
|
|
49
162
|
throw new Error(
|
|
50
163
|
`Unknown auth provider: ${authProvider}. Please provide either a valid authProvider or a custom getToken function.`
|
|
@@ -58,11 +171,15 @@ function PlugableProvider({
|
|
|
58
171
|
authProvider,
|
|
59
172
|
clerkJWTTemplate,
|
|
60
173
|
baseUrl,
|
|
61
|
-
staleTime = 5 * 60 * 1e3
|
|
174
|
+
staleTime = 5 * 60 * 1e3,
|
|
62
175
|
// Default 5 minutes
|
|
176
|
+
accentColor,
|
|
177
|
+
baseColor,
|
|
178
|
+
theme = "dark"
|
|
63
179
|
}) {
|
|
64
180
|
const listenersRef = useRef({});
|
|
65
181
|
const [cache, setCacheState] = useState(/* @__PURE__ */ new Map());
|
|
182
|
+
const containerRef = useRef(null);
|
|
66
183
|
const client = useMemo(() => {
|
|
67
184
|
if (!getToken && !authProvider) {
|
|
68
185
|
throw new Error(
|
|
@@ -132,7 +249,12 @@ function PlugableProvider({
|
|
|
132
249
|
}),
|
|
133
250
|
[client, bucketId, on, emit, baseUrl, staleTime, getCache, setCache, invalidateCache]
|
|
134
251
|
);
|
|
135
|
-
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
if (containerRef.current) {
|
|
254
|
+
applyCSSVariables(containerRef.current, { accentColor, baseColor, theme });
|
|
255
|
+
}
|
|
256
|
+
}, [accentColor, baseColor, theme]);
|
|
257
|
+
return /* @__PURE__ */ jsx(PlugableContext.Provider, { value, children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "plugable-root", children }) });
|
|
136
258
|
}
|
|
137
259
|
function usePlugable() {
|
|
138
260
|
const context = useContext(PlugableContext);
|
|
@@ -277,6 +399,74 @@ function Dropzone({
|
|
|
277
399
|
}
|
|
278
400
|
);
|
|
279
401
|
}
|
|
402
|
+
const containerStyle = {
|
|
403
|
+
position: "relative",
|
|
404
|
+
border: `2px dashed ${isDragActive ? "var(--plugable-accent-primary)" : "var(--plugable-base-border)"}`,
|
|
405
|
+
borderRadius: "12px",
|
|
406
|
+
padding: "48px 24px",
|
|
407
|
+
textAlign: "center",
|
|
408
|
+
cursor: "pointer",
|
|
409
|
+
background: isDragActive ? "var(--plugable-accent-primary)10" : "var(--plugable-base-surface)",
|
|
410
|
+
backdropFilter: "var(--plugable-backdrop-blur)",
|
|
411
|
+
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
|
|
412
|
+
...style
|
|
413
|
+
};
|
|
414
|
+
const iconContainerStyle = {
|
|
415
|
+
width: "48px",
|
|
416
|
+
height: "48px",
|
|
417
|
+
margin: "0 auto 16px",
|
|
418
|
+
borderRadius: "50%",
|
|
419
|
+
display: "flex",
|
|
420
|
+
alignItems: "center",
|
|
421
|
+
justifyContent: "center",
|
|
422
|
+
background: isDragActive ? `linear-gradient(135deg, var(--plugable-accent-primary), var(--plugable-accent-secondary))` : "var(--plugable-overlay)",
|
|
423
|
+
transition: "all 0.3s ease",
|
|
424
|
+
transform: isDragActive ? "scale(1.1)" : "scale(1)"
|
|
425
|
+
};
|
|
426
|
+
const cloudIconStyle = {
|
|
427
|
+
width: "24px",
|
|
428
|
+
height: "24px",
|
|
429
|
+
color: isDragActive ? "#fff" : "var(--plugable-accent-primary)"
|
|
430
|
+
};
|
|
431
|
+
const titleStyle = {
|
|
432
|
+
margin: 0,
|
|
433
|
+
fontWeight: 600,
|
|
434
|
+
fontSize: "16px",
|
|
435
|
+
color: "var(--plugable-text-primary)",
|
|
436
|
+
marginBottom: "8px"
|
|
437
|
+
};
|
|
438
|
+
const subtitleStyle = {
|
|
439
|
+
margin: 0,
|
|
440
|
+
fontSize: "14px",
|
|
441
|
+
color: "var(--plugable-text-secondary)"
|
|
442
|
+
};
|
|
443
|
+
const maxFilesStyle = {
|
|
444
|
+
margin: "4px 0 0 0",
|
|
445
|
+
fontSize: "12px",
|
|
446
|
+
color: "var(--plugable-text-muted)"
|
|
447
|
+
};
|
|
448
|
+
const progressContainerStyle = {
|
|
449
|
+
marginTop: "16px"
|
|
450
|
+
};
|
|
451
|
+
const progressItemStyle = {
|
|
452
|
+
marginBottom: "12px",
|
|
453
|
+
textAlign: "left"
|
|
454
|
+
};
|
|
455
|
+
const progressLabelStyle = {
|
|
456
|
+
fontSize: "14px",
|
|
457
|
+
color: "var(--plugable-text-secondary)",
|
|
458
|
+
marginBottom: "6px",
|
|
459
|
+
display: "flex",
|
|
460
|
+
justifyContent: "space-between",
|
|
461
|
+
alignItems: "center"
|
|
462
|
+
};
|
|
463
|
+
const progressBarBgStyle = {
|
|
464
|
+
width: "100%",
|
|
465
|
+
height: "6px",
|
|
466
|
+
backgroundColor: "var(--plugable-overlay)",
|
|
467
|
+
borderRadius: "3px",
|
|
468
|
+
overflow: "hidden"
|
|
469
|
+
};
|
|
280
470
|
return /* @__PURE__ */ jsxs(
|
|
281
471
|
"div",
|
|
282
472
|
{
|
|
@@ -285,16 +475,7 @@ function Dropzone({
|
|
|
285
475
|
onDragLeave: handleDragLeave,
|
|
286
476
|
onClick: openFileDialog,
|
|
287
477
|
className,
|
|
288
|
-
style:
|
|
289
|
-
border: `2px dashed ${isDragActive ? "#0070f3" : "#ccc"}`,
|
|
290
|
-
borderRadius: "8px",
|
|
291
|
-
padding: "40px 20px",
|
|
292
|
-
textAlign: "center",
|
|
293
|
-
cursor: "pointer",
|
|
294
|
-
backgroundColor: isDragActive ? "#f0f8ff" : "#fafafa",
|
|
295
|
-
transition: "all 0.2s ease",
|
|
296
|
-
...style
|
|
297
|
-
},
|
|
478
|
+
style: containerStyle,
|
|
298
479
|
children: [
|
|
299
480
|
/* @__PURE__ */ jsx2(
|
|
300
481
|
"input",
|
|
@@ -308,42 +489,34 @@ function Dropzone({
|
|
|
308
489
|
}
|
|
309
490
|
),
|
|
310
491
|
isUploading ? /* @__PURE__ */ jsxs("div", { children: [
|
|
311
|
-
/* @__PURE__ */ jsx2("
|
|
312
|
-
/* @__PURE__ */ jsx2("
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
":
|
|
316
|
-
|
|
317
|
-
|
|
492
|
+
/* @__PURE__ */ jsx2("div", { style: iconContainerStyle, children: /* @__PURE__ */ jsx2("svg", { style: cloudIconStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }) }),
|
|
493
|
+
/* @__PURE__ */ jsx2("p", { style: titleStyle, children: "Uploading..." }),
|
|
494
|
+
/* @__PURE__ */ jsx2("div", { style: progressContainerStyle, children: Object.entries(uploadProgress).map(([fileName, progress]) => /* @__PURE__ */ jsxs("div", { style: progressItemStyle, children: [
|
|
495
|
+
/* @__PURE__ */ jsxs("div", { style: progressLabelStyle, children: [
|
|
496
|
+
/* @__PURE__ */ jsx2("span", { children: fileName }),
|
|
497
|
+
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 600 }, children: [
|
|
498
|
+
progress,
|
|
499
|
+
"%"
|
|
500
|
+
] })
|
|
318
501
|
] }),
|
|
319
|
-
/* @__PURE__ */ jsx2(
|
|
502
|
+
/* @__PURE__ */ jsx2("div", { style: progressBarBgStyle, children: /* @__PURE__ */ jsx2(
|
|
320
503
|
"div",
|
|
321
504
|
{
|
|
322
505
|
style: {
|
|
323
|
-
width:
|
|
324
|
-
height: "
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
children: /* @__PURE__ */ jsx2(
|
|
330
|
-
"div",
|
|
331
|
-
{
|
|
332
|
-
style: {
|
|
333
|
-
width: `${progress}%`,
|
|
334
|
-
height: "100%",
|
|
335
|
-
backgroundColor: "#0070f3",
|
|
336
|
-
transition: "width 0.3s ease"
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
)
|
|
506
|
+
width: `${progress}%`,
|
|
507
|
+
height: "100%",
|
|
508
|
+
background: `linear-gradient(90deg, var(--plugable-accent-primary), var(--plugable-accent-secondary))`,
|
|
509
|
+
transition: "width 0.3s ease",
|
|
510
|
+
borderRadius: "3px"
|
|
511
|
+
}
|
|
340
512
|
}
|
|
341
|
-
)
|
|
513
|
+
) })
|
|
342
514
|
] }, fileName)) })
|
|
343
515
|
] }) : /* @__PURE__ */ jsxs("div", { children: [
|
|
344
|
-
/* @__PURE__ */ jsx2("
|
|
345
|
-
/* @__PURE__ */ jsx2("p", { style:
|
|
346
|
-
|
|
516
|
+
/* @__PURE__ */ jsx2("div", { style: iconContainerStyle, children: /* @__PURE__ */ jsx2("svg", { style: cloudIconStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }) }),
|
|
517
|
+
/* @__PURE__ */ jsx2("p", { style: titleStyle, children: isDragActive ? "Drop files here" : "Click to upload or drag and drop" }),
|
|
518
|
+
/* @__PURE__ */ jsx2("p", { style: subtitleStyle, children: accept ? `Accepted: ${accept}` : "Any file type" }),
|
|
519
|
+
maxFiles && maxFiles > 1 && /* @__PURE__ */ jsxs("p", { style: maxFilesStyle, children: [
|
|
347
520
|
"(Maximum ",
|
|
348
521
|
maxFiles,
|
|
349
522
|
" files)"
|
|
@@ -355,7 +528,7 @@ function Dropzone({
|
|
|
355
528
|
}
|
|
356
529
|
|
|
357
530
|
// src/hooks/useFiles.ts
|
|
358
|
-
import { useState as useState3, useCallback as useCallback3, useEffect, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
531
|
+
import { useState as useState3, useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
359
532
|
function useFiles({
|
|
360
533
|
metadata,
|
|
361
534
|
startPage = 1,
|
|
@@ -440,7 +613,7 @@ function useFiles({
|
|
|
440
613
|
setIsLoading(false);
|
|
441
614
|
}
|
|
442
615
|
}, [client, stableMetadata, mediaType, perPage, orderBy, orderDirection, getCache, setCache, effectiveStaleTime]);
|
|
443
|
-
|
|
616
|
+
useEffect2(() => {
|
|
444
617
|
const paramsChanged = previousParamsRef.current !== null && previousParamsRef.current !== paramsKeyWithPage;
|
|
445
618
|
const isInitialMount = isInitialMountRef.current;
|
|
446
619
|
previousParamsRef.current = paramsKeyWithPage;
|
|
@@ -461,7 +634,7 @@ function useFiles({
|
|
|
461
634
|
fetchFiles(page, true);
|
|
462
635
|
}
|
|
463
636
|
}, [paramsKeyWithPage, autoLoad, getCache, effectiveStaleTime, fetchFiles, page]);
|
|
464
|
-
|
|
637
|
+
useEffect2(() => {
|
|
465
638
|
const unsubscribe = on("file.uploaded", () => {
|
|
466
639
|
fetchFiles(page, true);
|
|
467
640
|
});
|
|
@@ -523,7 +696,7 @@ function FileList({
|
|
|
523
696
|
}
|
|
524
697
|
|
|
525
698
|
// src/components/FileImage.tsx
|
|
526
|
-
import { useEffect as
|
|
699
|
+
import { useEffect as useEffect3, useState as useState4, useRef as useRef3 } from "react";
|
|
527
700
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
528
701
|
var imageCache = /* @__PURE__ */ new Map();
|
|
529
702
|
function FileImage({
|
|
@@ -543,7 +716,7 @@ function FileImage({
|
|
|
543
716
|
const [isLoading, setIsLoading] = useState4(true);
|
|
544
717
|
const [error, setError] = useState4(null);
|
|
545
718
|
const refetchAttemptedRef = useRef3(null);
|
|
546
|
-
|
|
719
|
+
useEffect3(() => {
|
|
547
720
|
let isMounted = true;
|
|
548
721
|
let objectUrl = null;
|
|
549
722
|
const loadImage = async () => {
|
|
@@ -636,20 +809,25 @@ function FileImage({
|
|
|
636
809
|
...style
|
|
637
810
|
};
|
|
638
811
|
if (error) {
|
|
639
|
-
return /* @__PURE__ */
|
|
812
|
+
return /* @__PURE__ */ jsxs2(
|
|
640
813
|
"div",
|
|
641
814
|
{
|
|
642
815
|
className,
|
|
643
816
|
style: {
|
|
644
817
|
...imageStyle,
|
|
645
818
|
display: "flex",
|
|
819
|
+
flexDirection: "column",
|
|
646
820
|
alignItems: "center",
|
|
647
821
|
justifyContent: "center",
|
|
648
|
-
backgroundColor: "
|
|
649
|
-
color: "
|
|
650
|
-
fontSize: "14px"
|
|
822
|
+
backgroundColor: "var(--plugable-base-surface)",
|
|
823
|
+
color: "var(--plugable-text-muted)",
|
|
824
|
+
fontSize: "14px",
|
|
825
|
+
gap: "8px"
|
|
651
826
|
},
|
|
652
|
-
children:
|
|
827
|
+
children: [
|
|
828
|
+
/* @__PURE__ */ jsx4("svg", { style: { width: "32px", height: "32px" }, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }),
|
|
829
|
+
/* @__PURE__ */ jsx4("span", { children: "Failed to load" })
|
|
830
|
+
]
|
|
653
831
|
}
|
|
654
832
|
);
|
|
655
833
|
}
|
|
@@ -660,29 +838,27 @@ function FileImage({
|
|
|
660
838
|
className,
|
|
661
839
|
style: {
|
|
662
840
|
...imageStyle,
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
backgroundColor: "#f0f0f0"
|
|
841
|
+
position: "relative",
|
|
842
|
+
overflow: "hidden",
|
|
843
|
+
backgroundColor: "rgba(0, 0, 0, 0.02)"
|
|
667
844
|
},
|
|
668
845
|
children: [
|
|
669
846
|
/* @__PURE__ */ jsx4(
|
|
670
847
|
"div",
|
|
671
848
|
{
|
|
672
849
|
style: {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
animation: "spin 1s linear infinite"
|
|
850
|
+
position: "absolute",
|
|
851
|
+
inset: 0,
|
|
852
|
+
background: "linear-gradient(110deg, transparent 40%, rgba(255, 255, 255, 0.3) 50%, transparent 60%)",
|
|
853
|
+
backgroundSize: "200% 100%",
|
|
854
|
+
animation: "shimmer-pulse 1.5s ease-in-out infinite"
|
|
679
855
|
}
|
|
680
856
|
}
|
|
681
857
|
),
|
|
682
858
|
/* @__PURE__ */ jsx4("style", { children: `
|
|
683
|
-
@keyframes
|
|
684
|
-
0% {
|
|
685
|
-
100% {
|
|
859
|
+
@keyframes shimmer-pulse {
|
|
860
|
+
0% { background-position: 200% 0; }
|
|
861
|
+
100% { background-position: -200% 0; }
|
|
686
862
|
}
|
|
687
863
|
` })
|
|
688
864
|
]
|
|
@@ -695,7 +871,11 @@ function FileImage({
|
|
|
695
871
|
src: imageSrc,
|
|
696
872
|
alt: alt || file.name,
|
|
697
873
|
className,
|
|
698
|
-
style:
|
|
874
|
+
style: {
|
|
875
|
+
...imageStyle,
|
|
876
|
+
opacity: isLoading ? 0 : 1,
|
|
877
|
+
transition: "opacity 0.3s ease-in"
|
|
878
|
+
},
|
|
699
879
|
onLoad: handleLoad,
|
|
700
880
|
onError: handleError
|
|
701
881
|
}
|
|
@@ -707,22 +887,36 @@ function clearImageCache() {
|
|
|
707
887
|
}
|
|
708
888
|
|
|
709
889
|
// src/components/FilePreview.tsx
|
|
710
|
-
import { useState as useState5, useCallback as useCallback4, useEffect as
|
|
890
|
+
import React2, { useState as useState5, useCallback as useCallback4, useEffect as useEffect4 } from "react";
|
|
711
891
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
712
892
|
function FilePreview({
|
|
713
893
|
file: initialFile,
|
|
714
|
-
width =
|
|
715
|
-
height =
|
|
894
|
+
width = 120,
|
|
895
|
+
height = 120,
|
|
716
896
|
className,
|
|
717
897
|
style,
|
|
718
898
|
objectFit = "cover",
|
|
719
|
-
showExtension = true,
|
|
720
899
|
renderNonImage
|
|
721
900
|
}) {
|
|
722
901
|
const { client } = usePlugable();
|
|
723
902
|
const [file, setFile] = useState5(initialFile);
|
|
724
903
|
const [isRefetching, setIsRefetching] = useState5(false);
|
|
725
|
-
|
|
904
|
+
const [containerSize, setContainerSize] = useState5({ width: 0, height: 0 });
|
|
905
|
+
const containerRef = React2.useRef(null);
|
|
906
|
+
useEffect4(() => {
|
|
907
|
+
if (!containerRef.current) return;
|
|
908
|
+
const observer = new ResizeObserver((entries) => {
|
|
909
|
+
for (const entry of entries) {
|
|
910
|
+
setContainerSize({
|
|
911
|
+
width: entry.contentRect.width,
|
|
912
|
+
height: entry.contentRect.height
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
});
|
|
916
|
+
observer.observe(containerRef.current);
|
|
917
|
+
return () => observer.disconnect();
|
|
918
|
+
}, []);
|
|
919
|
+
useEffect4(() => {
|
|
726
920
|
setFile(initialFile);
|
|
727
921
|
}, [initialFile.id, initialFile.download_url]);
|
|
728
922
|
const handleRefetch = useCallback4(async () => {
|
|
@@ -736,45 +930,70 @@ function FilePreview({
|
|
|
736
930
|
} finally {
|
|
737
931
|
setIsRefetching(false);
|
|
738
932
|
}
|
|
739
|
-
}, [file.id, client]);
|
|
933
|
+
}, [file.id, client, isRefetching]);
|
|
740
934
|
const isImage = file.content_type.startsWith("image/");
|
|
935
|
+
const isSmall = containerSize.width > 0 && containerSize.width <= 80 || containerSize.height > 0 && containerSize.height <= 80;
|
|
741
936
|
const containerStyle = {
|
|
742
937
|
width,
|
|
743
938
|
height,
|
|
744
|
-
borderRadius:
|
|
939
|
+
borderRadius: isSmall ? "4px" : "8px",
|
|
745
940
|
overflow: "hidden",
|
|
746
|
-
|
|
941
|
+
position: "relative",
|
|
747
942
|
display: "flex",
|
|
748
943
|
alignItems: "center",
|
|
749
944
|
justifyContent: "center",
|
|
750
|
-
|
|
945
|
+
background: "var(--plugable-base-surface)",
|
|
751
946
|
...style
|
|
752
947
|
};
|
|
753
948
|
if (isImage) {
|
|
754
949
|
return /* @__PURE__ */ jsx5(
|
|
755
|
-
|
|
950
|
+
"div",
|
|
756
951
|
{
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
height,
|
|
760
|
-
objectFit,
|
|
952
|
+
ref: containerRef,
|
|
953
|
+
style: containerStyle,
|
|
761
954
|
className,
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
955
|
+
children: /* @__PURE__ */ jsx5(
|
|
956
|
+
FileImage,
|
|
957
|
+
{
|
|
958
|
+
file,
|
|
959
|
+
width,
|
|
960
|
+
height,
|
|
961
|
+
objectFit,
|
|
962
|
+
style: { borderRadius: isSmall ? "4px" : "8px" },
|
|
963
|
+
onRefetchNeeded: handleRefetch
|
|
964
|
+
}
|
|
965
|
+
)
|
|
765
966
|
}
|
|
766
967
|
);
|
|
767
968
|
}
|
|
768
969
|
if (renderNonImage) {
|
|
769
|
-
return /* @__PURE__ */ jsx5(
|
|
970
|
+
return /* @__PURE__ */ jsx5(
|
|
971
|
+
"div",
|
|
972
|
+
{
|
|
973
|
+
ref: containerRef,
|
|
974
|
+
className,
|
|
975
|
+
style: containerStyle,
|
|
976
|
+
children: renderNonImage(file)
|
|
977
|
+
}
|
|
978
|
+
);
|
|
770
979
|
}
|
|
771
980
|
const extension = file.name.split(".").pop()?.toUpperCase() || "FILE";
|
|
772
|
-
|
|
773
|
-
fontSize: "12px",
|
|
774
|
-
fontWeight:
|
|
775
|
-
color: "
|
|
776
|
-
textTransform: "uppercase"
|
|
777
|
-
|
|
981
|
+
const extensionStyle = {
|
|
982
|
+
fontSize: isSmall ? "9px" : "12px",
|
|
983
|
+
fontWeight: 700,
|
|
984
|
+
color: "var(--plugable-text-secondary)",
|
|
985
|
+
textTransform: "uppercase",
|
|
986
|
+
letterSpacing: "0.5px"
|
|
987
|
+
};
|
|
988
|
+
return /* @__PURE__ */ jsx5(
|
|
989
|
+
"div",
|
|
990
|
+
{
|
|
991
|
+
ref: containerRef,
|
|
992
|
+
className,
|
|
993
|
+
style: containerStyle,
|
|
994
|
+
children: /* @__PURE__ */ jsx5("span", { style: extensionStyle, children: extension })
|
|
995
|
+
}
|
|
996
|
+
);
|
|
778
997
|
}
|
|
779
998
|
export {
|
|
780
999
|
Dropzone,
|
|
@@ -782,7 +1001,10 @@ export {
|
|
|
782
1001
|
FileList,
|
|
783
1002
|
FilePreview,
|
|
784
1003
|
PlugableProvider,
|
|
1004
|
+
applyCSSVariables,
|
|
785
1005
|
clearImageCache,
|
|
1006
|
+
generateCSSVariables,
|
|
1007
|
+
getThemeColors,
|
|
786
1008
|
useFiles,
|
|
787
1009
|
usePlugable
|
|
788
1010
|
};
|