@plugable-io/react 0.0.8 → 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.d.mts CHANGED
@@ -111,7 +111,7 @@ interface FilePreviewProps {
111
111
  showExtension?: boolean;
112
112
  renderNonImage?: (file: FileObject) => React.ReactNode;
113
113
  }
114
- declare function FilePreview({ file: initialFile, width, height, className, style, objectFit, showExtension, renderNonImage, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
114
+ declare function FilePreview({ file: initialFile, width, height, className, style, objectFit, renderNonImage, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
115
115
 
116
116
  interface UseFilesOptions {
117
117
  metadata?: Record<string, any>;
package/dist/index.d.ts CHANGED
@@ -111,7 +111,7 @@ interface FilePreviewProps {
111
111
  showExtension?: boolean;
112
112
  renderNonImage?: (file: FileObject) => React.ReactNode;
113
113
  }
114
- declare function FilePreview({ file: initialFile, width, height, className, style, objectFit, showExtension, renderNonImage, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
114
+ declare function FilePreview({ file: initialFile, width, height, className, style, objectFit, renderNonImage, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
115
115
 
116
116
  interface UseFilesOptions {
117
117
  metadata?: Record<string, any>;
package/dist/index.js CHANGED
@@ -886,7 +886,7 @@ function FileImage({
886
886
  ...imageStyle,
887
887
  position: "relative",
888
888
  overflow: "hidden",
889
- backgroundColor: "var(--plugable-base-surface)"
889
+ backgroundColor: "rgba(0, 0, 0, 0.02)"
890
890
  },
891
891
  children: [
892
892
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -894,19 +894,17 @@ function FileImage({
894
894
  {
895
895
  style: {
896
896
  position: "absolute",
897
- top: 0,
898
- left: "-100%",
899
- width: "100%",
900
- height: "100%",
901
- background: "linear-gradient(90deg, transparent, var(--plugable-overlay), transparent)",
902
- animation: "shimmer 1.5s infinite"
897
+ inset: 0,
898
+ background: "linear-gradient(110deg, transparent 40%, rgba(255, 255, 255, 0.3) 50%, transparent 60%)",
899
+ backgroundSize: "200% 100%",
900
+ animation: "shimmer-pulse 1.5s ease-in-out infinite"
903
901
  }
904
902
  }
905
903
  ),
906
904
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
907
- @keyframes shimmer {
908
- 0% { left: -100%; }
909
- 100% { left: 100%; }
905
+ @keyframes shimmer-pulse {
906
+ 0% { background-position: 200% 0; }
907
+ 100% { background-position: -200% 0; }
910
908
  }
911
909
  ` })
912
910
  ]
@@ -935,31 +933,8 @@ function clearImageCache() {
935
933
  }
936
934
 
937
935
  // src/components/FilePreview.tsx
938
- var import_react5 = require("react");
936
+ var import_react5 = __toESM(require("react"));
939
937
  var import_jsx_runtime5 = require("react/jsx-runtime");
940
- var fileTypeColors = {
941
- pdf: { bg: "transparent", text: "#94a3b8" },
942
- // Slate-400
943
- doc: { bg: "transparent", text: "#94a3b8" },
944
- docx: { bg: "transparent", text: "#94a3b8" },
945
- xls: { bg: "transparent", text: "#94a3b8" },
946
- xlsx: { bg: "transparent", text: "#94a3b8" },
947
- csv: { bg: "transparent", text: "#94a3b8" },
948
- txt: { bg: "transparent", text: "#94a3b8" },
949
- zip: { bg: "transparent", text: "#94a3b8" },
950
- rar: { bg: "transparent", text: "#94a3b8" },
951
- mp4: { bg: "transparent", text: "#94a3b8" },
952
- mov: { bg: "transparent", text: "#94a3b8" },
953
- avi: { bg: "transparent", text: "#94a3b8" },
954
- mp3: { bg: "transparent", text: "#94a3b8" },
955
- wav: { bg: "transparent", text: "#94a3b8" },
956
- default: { bg: "transparent", text: "#64748b" }
957
- // Slate-500
958
- };
959
- function getFileTypeColor(filename) {
960
- const ext = filename.split(".").pop()?.toLowerCase() || "";
961
- return fileTypeColors[ext] || fileTypeColors.default;
962
- }
963
938
  function FilePreview({
964
939
  file: initialFile,
965
940
  width = 120,
@@ -967,13 +942,26 @@ function FilePreview({
967
942
  className,
968
943
  style,
969
944
  objectFit = "cover",
970
- showExtension = true,
971
945
  renderNonImage
972
946
  }) {
973
947
  const { client } = usePlugable();
974
948
  const [file, setFile] = (0, import_react5.useState)(initialFile);
975
949
  const [isRefetching, setIsRefetching] = (0, import_react5.useState)(false);
976
- const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
950
+ const [containerSize, setContainerSize] = (0, import_react5.useState)({ width: 0, height: 0 });
951
+ const containerRef = import_react5.default.useRef(null);
952
+ (0, import_react5.useEffect)(() => {
953
+ if (!containerRef.current) return;
954
+ const observer = new ResizeObserver((entries) => {
955
+ for (const entry of entries) {
956
+ setContainerSize({
957
+ width: entry.contentRect.width,
958
+ height: entry.contentRect.height
959
+ });
960
+ }
961
+ });
962
+ observer.observe(containerRef.current);
963
+ return () => observer.disconnect();
964
+ }, []);
977
965
  (0, import_react5.useEffect)(() => {
978
966
  setFile(initialFile);
979
967
  }, [initialFile.id, initialFile.download_url]);
@@ -990,30 +978,26 @@ function FilePreview({
990
978
  }
991
979
  }, [file.id, client, isRefetching]);
992
980
  const isImage = file.content_type.startsWith("image/");
981
+ const isSmall = containerSize.width > 0 && containerSize.width <= 80 || containerSize.height > 0 && containerSize.height <= 80;
993
982
  const containerStyle = {
994
983
  width,
995
984
  height,
996
- borderRadius: "8px",
985
+ borderRadius: isSmall ? "4px" : "8px",
997
986
  overflow: "hidden",
998
987
  position: "relative",
999
988
  display: "flex",
1000
989
  alignItems: "center",
1001
990
  justifyContent: "center",
1002
- border: isHovered ? "1px solid var(--plugable-accent-primary)" : "1px solid var(--plugable-base-border)",
1003
991
  background: "var(--plugable-base-surface)",
1004
- transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
1005
- boxShadow: "0 2px 4px rgba(0, 0, 0, 0.05)",
1006
- cursor: "pointer",
1007
992
  ...style
1008
993
  };
1009
994
  if (isImage) {
1010
995
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1011
996
  "div",
1012
997
  {
998
+ ref: containerRef,
1013
999
  style: containerStyle,
1014
1000
  className,
1015
- onMouseEnter: () => setIsHovered(true),
1016
- onMouseLeave: () => setIsHovered(false),
1017
1001
  children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1018
1002
  FileImage,
1019
1003
  {
@@ -1021,7 +1005,7 @@ function FilePreview({
1021
1005
  width,
1022
1006
  height,
1023
1007
  objectFit,
1024
- style: { borderRadius: "8px" },
1008
+ style: { borderRadius: isSmall ? "4px" : "8px" },
1025
1009
  onRefetchNeeded: handleRefetch
1026
1010
  }
1027
1011
  )
@@ -1032,59 +1016,28 @@ function FilePreview({
1032
1016
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1033
1017
  "div",
1034
1018
  {
1019
+ ref: containerRef,
1035
1020
  className,
1036
1021
  style: containerStyle,
1037
- onMouseEnter: () => setIsHovered(true),
1038
- onMouseLeave: () => setIsHovered(false),
1039
1022
  children: renderNonImage(file)
1040
1023
  }
1041
1024
  );
1042
1025
  }
1043
1026
  const extension = file.name.split(".").pop()?.toUpperCase() || "FILE";
1044
- const colors = getFileTypeColor(file.name);
1045
- const badgeStyle = {
1046
- padding: "2px 8px",
1047
- borderRadius: "4px",
1048
- border: "1px solid var(--plugable-base-border)",
1049
- backgroundColor: "var(--plugable-overlay)",
1050
- display: "inline-flex",
1051
- alignItems: "center",
1052
- justifyContent: "center"
1053
- };
1054
1027
  const extensionStyle = {
1055
- fontSize: "11px",
1056
- fontWeight: 600,
1028
+ fontSize: isSmall ? "9px" : "12px",
1029
+ fontWeight: 700,
1057
1030
  color: "var(--plugable-text-secondary)",
1058
1031
  textTransform: "uppercase",
1059
- letterSpacing: "0.05em"
1060
- };
1061
- const iconStyle = {
1062
- width: "28px",
1063
- height: "28px",
1064
- marginBottom: "6px",
1065
- color: colors.text
1066
- };
1067
- const wrapperStyle = {
1068
- textAlign: "center",
1069
- padding: "12px",
1070
- display: "flex",
1071
- flexDirection: "column",
1072
- alignItems: "center",
1073
- justifyContent: "center",
1074
- width: "100%",
1075
- height: "100%"
1032
+ letterSpacing: "0.5px"
1076
1033
  };
1077
1034
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1078
1035
  "div",
1079
1036
  {
1037
+ ref: containerRef,
1080
1038
  className,
1081
1039
  style: containerStyle,
1082
- onMouseEnter: () => setIsHovered(true),
1083
- onMouseLeave: () => setIsHovered(false),
1084
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: wrapperStyle, children: [
1085
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { style: iconStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
1086
- showExtension && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: badgeStyle, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: extensionStyle, children: extension }) })
1087
- ] })
1040
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: extensionStyle, children: extension })
1088
1041
  }
1089
1042
  );
1090
1043
  }
package/dist/index.mjs CHANGED
@@ -840,7 +840,7 @@ function FileImage({
840
840
  ...imageStyle,
841
841
  position: "relative",
842
842
  overflow: "hidden",
843
- backgroundColor: "var(--plugable-base-surface)"
843
+ backgroundColor: "rgba(0, 0, 0, 0.02)"
844
844
  },
845
845
  children: [
846
846
  /* @__PURE__ */ jsx4(
@@ -848,19 +848,17 @@ function FileImage({
848
848
  {
849
849
  style: {
850
850
  position: "absolute",
851
- top: 0,
852
- left: "-100%",
853
- width: "100%",
854
- height: "100%",
855
- background: "linear-gradient(90deg, transparent, var(--plugable-overlay), transparent)",
856
- animation: "shimmer 1.5s infinite"
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"
857
855
  }
858
856
  }
859
857
  ),
860
858
  /* @__PURE__ */ jsx4("style", { children: `
861
- @keyframes shimmer {
862
- 0% { left: -100%; }
863
- 100% { left: 100%; }
859
+ @keyframes shimmer-pulse {
860
+ 0% { background-position: 200% 0; }
861
+ 100% { background-position: -200% 0; }
864
862
  }
865
863
  ` })
866
864
  ]
@@ -889,31 +887,8 @@ function clearImageCache() {
889
887
  }
890
888
 
891
889
  // src/components/FilePreview.tsx
892
- import { useState as useState5, useCallback as useCallback4, useEffect as useEffect4 } from "react";
893
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
894
- var fileTypeColors = {
895
- pdf: { bg: "transparent", text: "#94a3b8" },
896
- // Slate-400
897
- doc: { bg: "transparent", text: "#94a3b8" },
898
- docx: { bg: "transparent", text: "#94a3b8" },
899
- xls: { bg: "transparent", text: "#94a3b8" },
900
- xlsx: { bg: "transparent", text: "#94a3b8" },
901
- csv: { bg: "transparent", text: "#94a3b8" },
902
- txt: { bg: "transparent", text: "#94a3b8" },
903
- zip: { bg: "transparent", text: "#94a3b8" },
904
- rar: { bg: "transparent", text: "#94a3b8" },
905
- mp4: { bg: "transparent", text: "#94a3b8" },
906
- mov: { bg: "transparent", text: "#94a3b8" },
907
- avi: { bg: "transparent", text: "#94a3b8" },
908
- mp3: { bg: "transparent", text: "#94a3b8" },
909
- wav: { bg: "transparent", text: "#94a3b8" },
910
- default: { bg: "transparent", text: "#64748b" }
911
- // Slate-500
912
- };
913
- function getFileTypeColor(filename) {
914
- const ext = filename.split(".").pop()?.toLowerCase() || "";
915
- return fileTypeColors[ext] || fileTypeColors.default;
916
- }
890
+ import React2, { useState as useState5, useCallback as useCallback4, useEffect as useEffect4 } from "react";
891
+ import { jsx as jsx5 } from "react/jsx-runtime";
917
892
  function FilePreview({
918
893
  file: initialFile,
919
894
  width = 120,
@@ -921,13 +896,26 @@ function FilePreview({
921
896
  className,
922
897
  style,
923
898
  objectFit = "cover",
924
- showExtension = true,
925
899
  renderNonImage
926
900
  }) {
927
901
  const { client } = usePlugable();
928
902
  const [file, setFile] = useState5(initialFile);
929
903
  const [isRefetching, setIsRefetching] = useState5(false);
930
- const [isHovered, setIsHovered] = useState5(false);
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
+ }, []);
931
919
  useEffect4(() => {
932
920
  setFile(initialFile);
933
921
  }, [initialFile.id, initialFile.download_url]);
@@ -944,30 +932,26 @@ function FilePreview({
944
932
  }
945
933
  }, [file.id, client, isRefetching]);
946
934
  const isImage = file.content_type.startsWith("image/");
935
+ const isSmall = containerSize.width > 0 && containerSize.width <= 80 || containerSize.height > 0 && containerSize.height <= 80;
947
936
  const containerStyle = {
948
937
  width,
949
938
  height,
950
- borderRadius: "8px",
939
+ borderRadius: isSmall ? "4px" : "8px",
951
940
  overflow: "hidden",
952
941
  position: "relative",
953
942
  display: "flex",
954
943
  alignItems: "center",
955
944
  justifyContent: "center",
956
- border: isHovered ? "1px solid var(--plugable-accent-primary)" : "1px solid var(--plugable-base-border)",
957
945
  background: "var(--plugable-base-surface)",
958
- transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
959
- boxShadow: "0 2px 4px rgba(0, 0, 0, 0.05)",
960
- cursor: "pointer",
961
946
  ...style
962
947
  };
963
948
  if (isImage) {
964
949
  return /* @__PURE__ */ jsx5(
965
950
  "div",
966
951
  {
952
+ ref: containerRef,
967
953
  style: containerStyle,
968
954
  className,
969
- onMouseEnter: () => setIsHovered(true),
970
- onMouseLeave: () => setIsHovered(false),
971
955
  children: /* @__PURE__ */ jsx5(
972
956
  FileImage,
973
957
  {
@@ -975,7 +959,7 @@ function FilePreview({
975
959
  width,
976
960
  height,
977
961
  objectFit,
978
- style: { borderRadius: "8px" },
962
+ style: { borderRadius: isSmall ? "4px" : "8px" },
979
963
  onRefetchNeeded: handleRefetch
980
964
  }
981
965
  )
@@ -986,59 +970,28 @@ function FilePreview({
986
970
  return /* @__PURE__ */ jsx5(
987
971
  "div",
988
972
  {
973
+ ref: containerRef,
989
974
  className,
990
975
  style: containerStyle,
991
- onMouseEnter: () => setIsHovered(true),
992
- onMouseLeave: () => setIsHovered(false),
993
976
  children: renderNonImage(file)
994
977
  }
995
978
  );
996
979
  }
997
980
  const extension = file.name.split(".").pop()?.toUpperCase() || "FILE";
998
- const colors = getFileTypeColor(file.name);
999
- const badgeStyle = {
1000
- padding: "2px 8px",
1001
- borderRadius: "4px",
1002
- border: "1px solid var(--plugable-base-border)",
1003
- backgroundColor: "var(--plugable-overlay)",
1004
- display: "inline-flex",
1005
- alignItems: "center",
1006
- justifyContent: "center"
1007
- };
1008
981
  const extensionStyle = {
1009
- fontSize: "11px",
1010
- fontWeight: 600,
982
+ fontSize: isSmall ? "9px" : "12px",
983
+ fontWeight: 700,
1011
984
  color: "var(--plugable-text-secondary)",
1012
985
  textTransform: "uppercase",
1013
- letterSpacing: "0.05em"
1014
- };
1015
- const iconStyle = {
1016
- width: "28px",
1017
- height: "28px",
1018
- marginBottom: "6px",
1019
- color: colors.text
1020
- };
1021
- const wrapperStyle = {
1022
- textAlign: "center",
1023
- padding: "12px",
1024
- display: "flex",
1025
- flexDirection: "column",
1026
- alignItems: "center",
1027
- justifyContent: "center",
1028
- width: "100%",
1029
- height: "100%"
986
+ letterSpacing: "0.5px"
1030
987
  };
1031
988
  return /* @__PURE__ */ jsx5(
1032
989
  "div",
1033
990
  {
991
+ ref: containerRef,
1034
992
  className,
1035
993
  style: containerStyle,
1036
- onMouseEnter: () => setIsHovered(true),
1037
- onMouseLeave: () => setIsHovered(false),
1038
- children: /* @__PURE__ */ jsxs3("div", { style: wrapperStyle, children: [
1039
- /* @__PURE__ */ jsx5("svg", { style: iconStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
1040
- showExtension && /* @__PURE__ */ jsx5("div", { style: badgeStyle, children: /* @__PURE__ */ jsx5("span", { style: extensionStyle, children: extension }) })
1041
- ] })
994
+ children: /* @__PURE__ */ jsx5("span", { style: extensionStyle, children: extension })
1042
995
  }
1043
996
  );
1044
997
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plugable-io/react",
3
- "version": "0.0.8",
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",