@thetechfossil/upfiles 1.0.2 → 1.0.4

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.js CHANGED
@@ -952,9 +952,12 @@ async function fetchProjectImagesWithThumbs(clientOptions, opts) {
952
952
  const limit = Math.max(1, Math.min(opts?.limitConcurrent ?? 6, 12));
953
953
  const queue = [...files];
954
954
  const results = [];
955
+ const processed = /* @__PURE__ */ new Set();
955
956
  async function worker() {
956
957
  while (queue.length) {
957
958
  const f2 = queue.shift();
959
+ if (!f2 || processed.has(f2.key)) continue;
960
+ processed.add(f2.key);
958
961
  try {
959
962
  const thumbs = await fetchFileThumbnails(clientOptions, f2.key).catch(() => void 0);
960
963
  results.push({ ...f2, thumbnails: thumbs });
@@ -963,7 +966,10 @@ async function fetchProjectImagesWithThumbs(clientOptions, opts) {
963
966
  }
964
967
  }
965
968
  }
966
- await Promise.all(Array.from({ length: Math.min(limit, files.length || 1) }, () => worker()));
969
+ const workers = Math.min(limit, files.length || 1);
970
+ await Promise.all(Array.from({ length: workers }, () => worker()));
971
+ const keyToIndex = new Map(files.map((f2, i) => [f2.key, i]));
972
+ results.sort((a, b) => (keyToIndex.get(a.key) ?? 0) - (keyToIndex.get(b.key) ?? 0));
967
973
  return results;
968
974
  }
969
975
 
@@ -1011,7 +1017,12 @@ function ImageManager(props) {
1011
1017
  }
1012
1018
  }, [clientOptions, folderPath]);
1013
1019
  React4.useEffect(() => {
1014
- if (!open) return;
1020
+ if (!open) {
1021
+ setItems([]);
1022
+ setQuery("");
1023
+ setError(null);
1024
+ return;
1025
+ }
1015
1026
  if (mode !== "upload" && tab === "browse") {
1016
1027
  load();
1017
1028
  }
@@ -1060,21 +1071,21 @@ function ImageManager(props) {
1060
1071
  [clientOptions, deleteUrl, onDelete]
1061
1072
  );
1062
1073
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog2.Root, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Dialog2.Portal, { children: [
1063
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40" }),
1074
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40 dark:bg-black/60" }),
1064
1075
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1065
1076
  Dialog2.Content,
1066
1077
  {
1067
- className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[95vw] max-w-4xl rounded-lg border bg-white p-4 shadow-lg max-h-[90vh] overflow-auto ${className ?? ""}`,
1078
+ className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[95vw] max-w-4xl rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-4 shadow-lg max-h-[90vh] overflow-auto ${className ?? ""}`,
1068
1079
  children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "space-y-3", children: [
1069
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog2.Title, { className: "text-lg font-semibold", children: title ?? "Image Manager" }),
1070
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog2.Description, { className: "text-sm text-muted-foreground", children: description ?? "Upload new images or select from existing ones." }),
1071
- mode === "full" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex gap-2 border-b", children: [
1080
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog2.Title, { className: "text-lg font-semibold text-gray-900 dark:text-white", children: title ?? "Image Manager" }),
1081
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog2.Description, { className: "text-sm text-gray-600 dark:text-gray-400", children: description ?? "Upload new images or select from existing ones." }),
1082
+ mode === "full" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex gap-2 border-b border-gray-200 dark:border-gray-700", children: [
1072
1083
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1073
1084
  "button",
1074
1085
  {
1075
1086
  type: "button",
1076
1087
  onClick: () => setTab("browse"),
1077
- className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === "browse" ? "border-blue-600 text-blue-600" : "border-transparent text-gray-600 hover:text-gray-900"}`,
1088
+ className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === "browse" ? "border-blue-600 text-blue-600 dark:text-blue-400" : "border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"}`,
1078
1089
  children: "Browse"
1079
1090
  }
1080
1091
  ),
@@ -1083,7 +1094,7 @@ function ImageManager(props) {
1083
1094
  {
1084
1095
  type: "button",
1085
1096
  onClick: () => setTab("upload"),
1086
- className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === "upload" ? "border-blue-600 text-blue-600" : "border-transparent text-gray-600 hover:text-gray-900"}`,
1097
+ className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === "upload" ? "border-blue-600 text-blue-600 dark:text-blue-400" : "border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"}`,
1087
1098
  children: "Upload"
1088
1099
  }
1089
1100
  )
@@ -1093,19 +1104,19 @@ function ImageManager(props) {
1093
1104
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1094
1105
  "input",
1095
1106
  {
1096
- className: "w-full rounded border px-3 py-2 text-sm",
1107
+ className: "w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-400",
1097
1108
  placeholder: "Search by filename...",
1098
1109
  value: query,
1099
1110
  onChange: (e) => setQuery(e.target.value)
1100
1111
  }
1101
1112
  ),
1102
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "px-3 py-2 text-sm rounded border", onClick: load, disabled: loading, children: loading ? "Loading\u2026" : "Refresh" })
1113
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "px-3 py-2 text-sm rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-gray-50 dark:hover:bg-gray-600 disabled:opacity-50", onClick: load, disabled: loading, children: loading ? "Loading\u2026" : "Refresh" })
1103
1114
  ] }),
1104
- error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "rounded border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700", children: error }),
1115
+ error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "rounded border border-red-200 dark:border-red-800 bg-red-50 dark:bg-red-900/20 px-3 py-2 text-sm text-red-700 dark:text-red-400", children: error }),
1105
1116
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: gridClassName ?? "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 max-h-[50vh] overflow-auto", children: [
1106
1117
  !loading && visible.map((f2) => {
1107
1118
  const thumbUrl = f2.thumbnails?.[0]?.url || f2.url;
1108
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "group relative aspect-square overflow-hidden rounded border", children: [
1119
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "group relative aspect-square overflow-hidden rounded border border-gray-200 dark:border-gray-700", children: [
1109
1120
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { src: thumbUrl, alt: f2.originalName, className: "h-full w-full object-cover" }),
1110
1121
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "absolute inset-0 bg-black/0 group-hover:bg-black/40 transition-colors flex items-center justify-center gap-2", children: [
1111
1122
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -1123,7 +1134,7 @@ function ImageManager(props) {
1123
1134
  });
1124
1135
  onOpenChange(false);
1125
1136
  },
1126
- className: "opacity-0 group-hover:opacity-100 px-3 py-1 text-xs bg-blue-600 text-white rounded",
1137
+ className: "opacity-0 group-hover:opacity-100 px-3 py-1 text-xs bg-blue-600 hover:bg-blue-700 text-white rounded",
1127
1138
  children: "Select"
1128
1139
  }
1129
1140
  ),
@@ -1133,7 +1144,7 @@ function ImageManager(props) {
1133
1144
  type: "button",
1134
1145
  onClick: () => handleDelete(f2.key),
1135
1146
  disabled: deleting === f2.key,
1136
- className: "opacity-0 group-hover:opacity-100 px-3 py-1 text-xs bg-red-600 text-white rounded disabled:opacity-50",
1147
+ className: "opacity-0 group-hover:opacity-100 px-3 py-1 text-xs bg-red-600 hover:bg-red-700 text-white rounded disabled:opacity-50",
1137
1148
  children: deleting === f2.key ? "..." : "Delete"
1138
1149
  }
1139
1150
  )
@@ -1141,8 +1152,8 @@ function ImageManager(props) {
1141
1152
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 bg-black/50 p-1 text-[10px] text-white truncate", children: f2.originalName })
1142
1153
  ] }, f2.key);
1143
1154
  }),
1144
- loading && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "col-span-full text-sm text-muted-foreground", children: "Loading\u2026" }),
1145
- !loading && visible.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "col-span-full text-sm text-muted-foreground", children: "No images found" })
1155
+ loading && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "col-span-full text-sm text-gray-600 dark:text-gray-400", children: "Loading\u2026" }),
1156
+ !loading && visible.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "col-span-full text-sm text-gray-600 dark:text-gray-400", children: "No images found" })
1146
1157
  ] })
1147
1158
  ] }),
1148
1159
  (mode === "upload" || mode === "full" && tab === "upload") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -1156,18 +1167,33 @@ function ImageManager(props) {
1156
1167
  maxFiles,
1157
1168
  autoRecordToDb,
1158
1169
  fetchThumbnails,
1170
+ onClientUploadComplete: (file) => {
1171
+ if (file.status === "success" && file.publicUrl && file.fileKey) {
1172
+ const newItem = {
1173
+ key: file.fileKey,
1174
+ originalName: file.name,
1175
+ size: file.size,
1176
+ contentType: file.type,
1177
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
1178
+ url: file.publicUrl,
1179
+ thumbnails: file.thumbnails
1180
+ };
1181
+ setItems((prev) => [newItem, ...prev]);
1182
+ }
1183
+ },
1159
1184
  onComplete: (files) => {
1160
1185
  if (mode === "full") {
1161
- load();
1162
- setTab("browse");
1163
- } else {
1186
+ setTimeout(() => {
1187
+ load();
1188
+ setTab("browse");
1189
+ }, 500);
1164
1190
  }
1165
1191
  },
1166
- dropzoneClassName: "border-2 border-dashed border-gray-300 rounded-lg p-8 text-center cursor-pointer hover:border-blue-500 transition-colors",
1167
- buttonClassName: "px-4 py-2 text-sm rounded border bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50"
1192
+ dropzoneClassName: "border-2 border-dashed border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-700/50 rounded-lg p-8 text-center cursor-pointer hover:border-blue-500 dark:hover:border-blue-400 transition-colors text-gray-700 dark:text-gray-300",
1193
+ buttonClassName: "px-4 py-2 text-sm rounded border border-gray-300 dark:border-gray-600 bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50"
1168
1194
  }
1169
1195
  ),
1170
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex justify-end gap-2 pt-2 border-t", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "px-4 py-2 text-sm rounded border", children: "Close" }) }) })
1196
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex justify-end gap-2 pt-2 border-t border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "px-4 py-2 text-sm rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-gray-50 dark:hover:bg-gray-600", children: "Close" }) }) })
1171
1197
  ] })
1172
1198
  }
1173
1199
  )
package/dist/index.mjs CHANGED
@@ -903,9 +903,12 @@ async function fetchProjectImagesWithThumbs(clientOptions, opts) {
903
903
  const limit = Math.max(1, Math.min(opts?.limitConcurrent ?? 6, 12));
904
904
  const queue = [...files];
905
905
  const results = [];
906
+ const processed = /* @__PURE__ */ new Set();
906
907
  async function worker() {
907
908
  while (queue.length) {
908
909
  const f2 = queue.shift();
910
+ if (!f2 || processed.has(f2.key)) continue;
911
+ processed.add(f2.key);
909
912
  try {
910
913
  const thumbs = await fetchFileThumbnails(clientOptions, f2.key).catch(() => void 0);
911
914
  results.push({ ...f2, thumbnails: thumbs });
@@ -914,7 +917,10 @@ async function fetchProjectImagesWithThumbs(clientOptions, opts) {
914
917
  }
915
918
  }
916
919
  }
917
- await Promise.all(Array.from({ length: Math.min(limit, files.length || 1) }, () => worker()));
920
+ const workers = Math.min(limit, files.length || 1);
921
+ await Promise.all(Array.from({ length: workers }, () => worker()));
922
+ const keyToIndex = new Map(files.map((f2, i) => [f2.key, i]));
923
+ results.sort((a, b) => (keyToIndex.get(a.key) ?? 0) - (keyToIndex.get(b.key) ?? 0));
918
924
  return results;
919
925
  }
920
926
 
@@ -962,7 +968,12 @@ function ImageManager(props) {
962
968
  }
963
969
  }, [clientOptions, folderPath]);
964
970
  React4.useEffect(() => {
965
- if (!open) return;
971
+ if (!open) {
972
+ setItems([]);
973
+ setQuery("");
974
+ setError(null);
975
+ return;
976
+ }
966
977
  if (mode !== "upload" && tab === "browse") {
967
978
  load();
968
979
  }
@@ -1011,21 +1022,21 @@ function ImageManager(props) {
1011
1022
  [clientOptions, deleteUrl, onDelete]
1012
1023
  );
1013
1024
  return /* @__PURE__ */ jsx4(Dialog2.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs4(Dialog2.Portal, { children: [
1014
- /* @__PURE__ */ jsx4(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40" }),
1025
+ /* @__PURE__ */ jsx4(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40 dark:bg-black/60" }),
1015
1026
  /* @__PURE__ */ jsx4(
1016
1027
  Dialog2.Content,
1017
1028
  {
1018
- className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[95vw] max-w-4xl rounded-lg border bg-white p-4 shadow-lg max-h-[90vh] overflow-auto ${className ?? ""}`,
1029
+ className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[95vw] max-w-4xl rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-4 shadow-lg max-h-[90vh] overflow-auto ${className ?? ""}`,
1019
1030
  children: /* @__PURE__ */ jsxs4("div", { className: "space-y-3", children: [
1020
- /* @__PURE__ */ jsx4(Dialog2.Title, { className: "text-lg font-semibold", children: title ?? "Image Manager" }),
1021
- /* @__PURE__ */ jsx4(Dialog2.Description, { className: "text-sm text-muted-foreground", children: description ?? "Upload new images or select from existing ones." }),
1022
- mode === "full" && /* @__PURE__ */ jsxs4("div", { className: "flex gap-2 border-b", children: [
1031
+ /* @__PURE__ */ jsx4(Dialog2.Title, { className: "text-lg font-semibold text-gray-900 dark:text-white", children: title ?? "Image Manager" }),
1032
+ /* @__PURE__ */ jsx4(Dialog2.Description, { className: "text-sm text-gray-600 dark:text-gray-400", children: description ?? "Upload new images or select from existing ones." }),
1033
+ mode === "full" && /* @__PURE__ */ jsxs4("div", { className: "flex gap-2 border-b border-gray-200 dark:border-gray-700", children: [
1023
1034
  /* @__PURE__ */ jsx4(
1024
1035
  "button",
1025
1036
  {
1026
1037
  type: "button",
1027
1038
  onClick: () => setTab("browse"),
1028
- className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === "browse" ? "border-blue-600 text-blue-600" : "border-transparent text-gray-600 hover:text-gray-900"}`,
1039
+ className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === "browse" ? "border-blue-600 text-blue-600 dark:text-blue-400" : "border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"}`,
1029
1040
  children: "Browse"
1030
1041
  }
1031
1042
  ),
@@ -1034,7 +1045,7 @@ function ImageManager(props) {
1034
1045
  {
1035
1046
  type: "button",
1036
1047
  onClick: () => setTab("upload"),
1037
- className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === "upload" ? "border-blue-600 text-blue-600" : "border-transparent text-gray-600 hover:text-gray-900"}`,
1048
+ className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === "upload" ? "border-blue-600 text-blue-600 dark:text-blue-400" : "border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"}`,
1038
1049
  children: "Upload"
1039
1050
  }
1040
1051
  )
@@ -1044,19 +1055,19 @@ function ImageManager(props) {
1044
1055
  /* @__PURE__ */ jsx4(
1045
1056
  "input",
1046
1057
  {
1047
- className: "w-full rounded border px-3 py-2 text-sm",
1058
+ className: "w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-400",
1048
1059
  placeholder: "Search by filename...",
1049
1060
  value: query,
1050
1061
  onChange: (e) => setQuery(e.target.value)
1051
1062
  }
1052
1063
  ),
1053
- /* @__PURE__ */ jsx4("button", { type: "button", className: "px-3 py-2 text-sm rounded border", onClick: load, disabled: loading, children: loading ? "Loading\u2026" : "Refresh" })
1064
+ /* @__PURE__ */ jsx4("button", { type: "button", className: "px-3 py-2 text-sm rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-gray-50 dark:hover:bg-gray-600 disabled:opacity-50", onClick: load, disabled: loading, children: loading ? "Loading\u2026" : "Refresh" })
1054
1065
  ] }),
1055
- error && /* @__PURE__ */ jsx4("div", { className: "rounded border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700", children: error }),
1066
+ error && /* @__PURE__ */ jsx4("div", { className: "rounded border border-red-200 dark:border-red-800 bg-red-50 dark:bg-red-900/20 px-3 py-2 text-sm text-red-700 dark:text-red-400", children: error }),
1056
1067
  /* @__PURE__ */ jsxs4("div", { className: gridClassName ?? "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 max-h-[50vh] overflow-auto", children: [
1057
1068
  !loading && visible.map((f2) => {
1058
1069
  const thumbUrl = f2.thumbnails?.[0]?.url || f2.url;
1059
- return /* @__PURE__ */ jsxs4("div", { className: "group relative aspect-square overflow-hidden rounded border", children: [
1070
+ return /* @__PURE__ */ jsxs4("div", { className: "group relative aspect-square overflow-hidden rounded border border-gray-200 dark:border-gray-700", children: [
1060
1071
  /* @__PURE__ */ jsx4("img", { src: thumbUrl, alt: f2.originalName, className: "h-full w-full object-cover" }),
1061
1072
  /* @__PURE__ */ jsxs4("div", { className: "absolute inset-0 bg-black/0 group-hover:bg-black/40 transition-colors flex items-center justify-center gap-2", children: [
1062
1073
  /* @__PURE__ */ jsx4(
@@ -1074,7 +1085,7 @@ function ImageManager(props) {
1074
1085
  });
1075
1086
  onOpenChange(false);
1076
1087
  },
1077
- className: "opacity-0 group-hover:opacity-100 px-3 py-1 text-xs bg-blue-600 text-white rounded",
1088
+ className: "opacity-0 group-hover:opacity-100 px-3 py-1 text-xs bg-blue-600 hover:bg-blue-700 text-white rounded",
1078
1089
  children: "Select"
1079
1090
  }
1080
1091
  ),
@@ -1084,7 +1095,7 @@ function ImageManager(props) {
1084
1095
  type: "button",
1085
1096
  onClick: () => handleDelete(f2.key),
1086
1097
  disabled: deleting === f2.key,
1087
- className: "opacity-0 group-hover:opacity-100 px-3 py-1 text-xs bg-red-600 text-white rounded disabled:opacity-50",
1098
+ className: "opacity-0 group-hover:opacity-100 px-3 py-1 text-xs bg-red-600 hover:bg-red-700 text-white rounded disabled:opacity-50",
1088
1099
  children: deleting === f2.key ? "..." : "Delete"
1089
1100
  }
1090
1101
  )
@@ -1092,8 +1103,8 @@ function ImageManager(props) {
1092
1103
  /* @__PURE__ */ jsx4("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 bg-black/50 p-1 text-[10px] text-white truncate", children: f2.originalName })
1093
1104
  ] }, f2.key);
1094
1105
  }),
1095
- loading && /* @__PURE__ */ jsx4("div", { className: "col-span-full text-sm text-muted-foreground", children: "Loading\u2026" }),
1096
- !loading && visible.length === 0 && /* @__PURE__ */ jsx4("div", { className: "col-span-full text-sm text-muted-foreground", children: "No images found" })
1106
+ loading && /* @__PURE__ */ jsx4("div", { className: "col-span-full text-sm text-gray-600 dark:text-gray-400", children: "Loading\u2026" }),
1107
+ !loading && visible.length === 0 && /* @__PURE__ */ jsx4("div", { className: "col-span-full text-sm text-gray-600 dark:text-gray-400", children: "No images found" })
1097
1108
  ] })
1098
1109
  ] }),
1099
1110
  (mode === "upload" || mode === "full" && tab === "upload") && /* @__PURE__ */ jsx4(
@@ -1107,18 +1118,33 @@ function ImageManager(props) {
1107
1118
  maxFiles,
1108
1119
  autoRecordToDb,
1109
1120
  fetchThumbnails,
1121
+ onClientUploadComplete: (file) => {
1122
+ if (file.status === "success" && file.publicUrl && file.fileKey) {
1123
+ const newItem = {
1124
+ key: file.fileKey,
1125
+ originalName: file.name,
1126
+ size: file.size,
1127
+ contentType: file.type,
1128
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
1129
+ url: file.publicUrl,
1130
+ thumbnails: file.thumbnails
1131
+ };
1132
+ setItems((prev) => [newItem, ...prev]);
1133
+ }
1134
+ },
1110
1135
  onComplete: (files) => {
1111
1136
  if (mode === "full") {
1112
- load();
1113
- setTab("browse");
1114
- } else {
1137
+ setTimeout(() => {
1138
+ load();
1139
+ setTab("browse");
1140
+ }, 500);
1115
1141
  }
1116
1142
  },
1117
- dropzoneClassName: "border-2 border-dashed border-gray-300 rounded-lg p-8 text-center cursor-pointer hover:border-blue-500 transition-colors",
1118
- buttonClassName: "px-4 py-2 text-sm rounded border bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50"
1143
+ dropzoneClassName: "border-2 border-dashed border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-700/50 rounded-lg p-8 text-center cursor-pointer hover:border-blue-500 dark:hover:border-blue-400 transition-colors text-gray-700 dark:text-gray-300",
1144
+ buttonClassName: "px-4 py-2 text-sm rounded border border-gray-300 dark:border-gray-600 bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50"
1119
1145
  }
1120
1146
  ),
1121
- /* @__PURE__ */ jsx4("div", { className: "flex justify-end gap-2 pt-2 border-t", children: /* @__PURE__ */ jsx4(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx4("button", { type: "button", className: "px-4 py-2 text-sm rounded border", children: "Close" }) }) })
1147
+ /* @__PURE__ */ jsx4("div", { className: "flex justify-end gap-2 pt-2 border-t border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx4(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx4("button", { type: "button", className: "px-4 py-2 text-sm rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-gray-50 dark:hover:bg-gray-600", children: "Close" }) }) })
1122
1148
  ] })
1123
1149
  }
1124
1150
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thetechfossil/upfiles",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Lightweight client and React components for Upfiles Plugin API (presigned S3)",
5
5
  "license": "MIT",
6
6
  "author": "UpFiles",