@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/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
- return /* @__PURE__ */ jsx(PlugableContext.Provider, { value, children });
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("p", { style: { margin: 0, fontWeight: "bold", color: "#333" }, children: "Uploading..." }),
312
- /* @__PURE__ */ jsx2("div", { style: { marginTop: "16px" }, children: Object.entries(uploadProgress).map(([fileName, progress]) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: "8px" }, children: [
313
- /* @__PURE__ */ jsxs("div", { style: { fontSize: "14px", color: "#666", marginBottom: "4px" }, children: [
314
- fileName,
315
- ": ",
316
- progress,
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: "100%",
324
- height: "8px",
325
- backgroundColor: "#e0e0e0",
326
- borderRadius: "4px",
327
- overflow: "hidden"
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("p", { style: { margin: 0, fontWeight: "bold", fontSize: "16px", color: "#333" }, children: isDragActive ? "Drop files here" : "Drag and drop files here" }),
345
- /* @__PURE__ */ jsx2("p", { style: { margin: "8px 0 0 0", fontSize: "14px", color: "#666" }, children: "or click to select files" }),
346
- maxFiles && maxFiles > 1 && /* @__PURE__ */ jsxs("p", { style: { margin: "4px 0 0 0", fontSize: "12px", color: "#999" }, children: [
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
- useEffect(() => {
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
- useEffect(() => {
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 useEffect2, useState as useState4, useRef as useRef3 } from "react";
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
- useEffect2(() => {
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__ */ jsx4(
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: "#f0f0f0",
649
- color: "#999",
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: "Failed to load image"
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
- display: "flex",
664
- alignItems: "center",
665
- justifyContent: "center",
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
- width: "40px",
674
- height: "40px",
675
- border: "3px solid #e0e0e0",
676
- borderTop: "3px solid #0070f3",
677
- borderRadius: "50%",
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 spin {
684
- 0% { transform: rotate(0deg); }
685
- 100% { transform: rotate(360deg); }
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: imageStyle,
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 useEffect3 } from "react";
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 = 80,
715
- height = 80,
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
- useEffect3(() => {
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: 4,
939
+ borderRadius: isSmall ? "4px" : "8px",
745
940
  overflow: "hidden",
746
- backgroundColor: "#f5f5f5",
941
+ position: "relative",
747
942
  display: "flex",
748
943
  alignItems: "center",
749
944
  justifyContent: "center",
750
- border: "1px solid #eee",
945
+ background: "var(--plugable-base-surface)",
751
946
  ...style
752
947
  };
753
948
  if (isImage) {
754
949
  return /* @__PURE__ */ jsx5(
755
- FileImage,
950
+ "div",
756
951
  {
757
- file,
758
- width,
759
- height,
760
- objectFit,
952
+ ref: containerRef,
953
+ style: containerStyle,
761
954
  className,
762
- style,
763
- borderRadius: 4,
764
- onRefetchNeeded: handleRefetch
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("div", { className, style: containerStyle, children: renderNonImage(file) });
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
- return /* @__PURE__ */ jsx5("div", { className, style: containerStyle, children: showExtension && /* @__PURE__ */ jsx5("span", { style: {
773
- fontSize: "12px",
774
- fontWeight: "bold",
775
- color: "#666",
776
- textTransform: "uppercase"
777
- }, children: extension }) });
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plugable-io/react",
3
- "version": "0.0.7",
3
+ "version": "0.0.10",
4
4
  "description": "React components and hooks for Plugable File Management API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",