@geekapps/silo-elements-nextjs 0.0.8 → 0.0.9

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
@@ -1,6 +1,6 @@
1
1
  import React, { useState, useRef, useCallback, useMemo, useEffect } from 'react';
2
- import { useUpload } from '@geekapps/silo-nextjs';
3
- export { SiloProvider, useFileStatus, useSignedUrl, useSiloClient, useUpload } from '@geekapps/silo-nextjs';
2
+ import { useMultipartUpload, useBatchUpload, useSignedUrl } from '@geekapps/silo-nextjs';
3
+ export { SiloProvider, useBatchUpload, useFileStatus, useMultipartUpload, useSignedUrl, useSiloClient } from '@geekapps/silo-nextjs';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import gsap from 'gsap';
6
6
  import { Play, Pause, FastForward, VolumeX, Volume2, AudioLines, Captions, Settings, Minimize, Maximize } from 'lucide-react';
@@ -177,10 +177,21 @@ function formatBytes(bytes) {
177
177
  if (bytes < 1024 ** 3) return `${(bytes / 1024 ** 2).toFixed(1)} MB`;
178
178
  return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
179
179
  }
180
+ function getFileIcon(mimeType) {
181
+ if (mimeType.startsWith("image/")) return "\u{1F5BC}\uFE0F";
182
+ if (mimeType.startsWith("video/")) return "\u{1F3AC}";
183
+ if (mimeType.startsWith("audio/")) return "\u{1F3B5}";
184
+ if (mimeType === "application/pdf") return "\u{1F4C4}";
185
+ if (mimeType.includes("spreadsheet") || mimeType.includes("excel")) return "\u{1F4CA}";
186
+ if (mimeType.includes("presentation") || mimeType.includes("powerpoint")) return "\u{1F4D1}";
187
+ if (mimeType.includes("word") || mimeType.includes("document")) return "\u{1F4DD}";
188
+ if (mimeType.includes("zip") || mimeType.includes("tar") || mimeType.includes("gzip")) return "\u{1F4E6}";
189
+ return "\u{1F4CE}";
190
+ }
180
191
  function ImageUploader({
181
192
  bucket,
182
193
  expiresIn,
183
- private: isPrivate = true,
194
+ visibility = "private",
184
195
  onUpload,
185
196
  onError,
186
197
  className = "",
@@ -189,6 +200,7 @@ function ImageUploader({
189
200
  maxSize,
190
201
  accept = "image/*",
191
202
  showPreview = true,
203
+ image,
192
204
  theme,
193
205
  renderIcon,
194
206
  renderProgress,
@@ -196,28 +208,25 @@ function ImageUploader({
196
208
  renderError,
197
209
  children
198
210
  }) {
199
- const uploadOpts = { private: isPrivate, ...bucket !== void 0 && { bucket }, ...expiresIn !== void 0 && { expiresIn } };
200
- const { state, upload, reset } = useUpload(uploadOpts);
211
+ const { state, upload, pause, resume, abort, reset } = useMultipartUpload(bucket);
201
212
  const [preview, setPreview] = useState(null);
202
213
  const t = resolveTheme(theme);
203
214
  const vars = themeToVars(t);
204
- const handleFiles = useCallback(
205
- async (files) => {
206
- const file = files[0];
207
- if (!file) return;
208
- if (showPreview) {
209
- const url = URL.createObjectURL(file);
210
- setPreview(url);
211
- }
212
- try {
213
- const result = await upload(file);
214
- onUpload?.(result);
215
- } catch (err) {
216
- onError?.(err instanceof Error ? err : new Error(String(err)));
217
- }
218
- },
219
- [upload, onUpload, onError, showPreview]
220
- );
215
+ const handleFiles = useCallback(async (files) => {
216
+ const file = files[0];
217
+ if (!file) return;
218
+ if (showPreview) setPreview(URL.createObjectURL(file));
219
+ try {
220
+ const result = await upload(file, {
221
+ ...bucket !== void 0 && { bucket },
222
+ visibility,
223
+ ...image && { image }
224
+ });
225
+ if (result) onUpload?.(result);
226
+ } catch (err) {
227
+ onError?.(err instanceof Error ? err : new Error(String(err)));
228
+ }
229
+ }, [upload, bucket, visibility, image, onUpload, onError, showPreview]);
221
230
  const containerStyle = {
222
231
  ...vars,
223
232
  display: "flex",
@@ -227,12 +236,11 @@ function ImageUploader({
227
236
  fontFamily: "var(--silo-font)",
228
237
  ...style
229
238
  };
230
- if (state.status === "error" && renderError) {
231
- return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderError(state.error, reset) });
232
- }
233
- if (state.status === "done" && renderSuccess) {
234
- return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderSuccess(state.result) });
235
- }
239
+ const isUploading = state.status === "uploading" || state.status === "preparing" || state.status === "completing";
240
+ const progress = state.status === "uploading" ? state.progress : state.status === "completing" ? 99 : 0;
241
+ const isPaused = state.status === "idle" && preview !== null;
242
+ if (state.status === "error" && renderError) return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderError(state.error, reset) });
243
+ if (state.status === "done" && renderSuccess) return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderSuccess(state.result) });
236
244
  return /* @__PURE__ */ jsxs("div", { className: `silo-image-uploader${className ? ` ${className}` : ""}`, style: containerStyle, children: [
237
245
  /* @__PURE__ */ jsx(
238
246
  DropZone,
@@ -241,102 +249,69 @@ function ImageUploader({
241
249
  ...maxSize !== void 0 && { maxSize },
242
250
  ...onError !== void 0 && { onError },
243
251
  ...theme !== void 0 && { theme },
244
- disabled: disabled || state.status === "uploading",
252
+ disabled: disabled || isUploading,
245
253
  onFiles: handleFiles,
246
254
  style: { padding: "32px 24px", textAlign: "center" },
247
- children: preview && state.status !== "uploading" ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }, children: [
248
- /* @__PURE__ */ jsx(
249
- "img",
250
- {
251
- src: preview,
252
- alt: "Preview",
253
- style: {
254
- maxWidth: "100%",
255
- maxHeight: "200px",
256
- borderRadius: "8px",
257
- objectFit: "contain"
258
- }
259
- }
260
- ),
261
- /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Click or drag to replace" })
255
+ children: preview && !isUploading ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }, children: [
256
+ /* @__PURE__ */ jsx("img", { src: preview, alt: "Preview", style: { maxWidth: "100%", maxHeight: "200px", borderRadius: "8px", objectFit: "contain" } }),
257
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Clique ou arraste para substituir" })
262
258
  ] }) : /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }, children: [
263
259
  renderIcon ? renderIcon() : /* @__PURE__ */ jsx("svg", { width: "40", height: "40", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", style: { color: "var(--silo-text-muted)", opacity: 0.6 }, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
264
260
  children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
265
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "var(--silo-text)" }, children: "Drop image here" }),
266
- /* @__PURE__ */ jsx("span", { style: { fontSize: "13px", color: "var(--silo-text-muted)" }, children: "or click to browse" }),
261
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "var(--silo-text)" }, children: "Arraste a imagem aqui" }),
262
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "13px", color: "var(--silo-text-muted)" }, children: "ou clique para selecionar" }),
267
263
  maxSize && /* @__PURE__ */ jsxs("span", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: [
268
- "Max ",
264
+ "M\xE1x ",
269
265
  formatBytes(maxSize)
270
266
  ] })
271
267
  ] })
272
268
  ] })
273
269
  }
274
270
  ),
275
- state.status === "uploading" && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: renderProgress ? renderProgress(state.progress) : /* @__PURE__ */ jsxs(Fragment, { children: [
276
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", fontSize: "13px", color: "var(--silo-text-muted)" }, children: [
277
- /* @__PURE__ */ jsx("span", { children: "Uploading\u2026" }),
278
- /* @__PURE__ */ jsxs("span", { children: [
279
- state.progress,
280
- "%"
271
+ isUploading && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: renderProgress ? renderProgress(progress) : /* @__PURE__ */ jsxs(Fragment, { children: [
272
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: "13px", color: "var(--silo-text-muted)" }, children: [
273
+ /* @__PURE__ */ jsx("span", { children: state.status === "completing" ? "Finalizando\u2026" : state.status === "preparing" ? "Preparando\u2026" : `Parte ${state.part} de ${state.totalParts}` }),
274
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
275
+ /* @__PURE__ */ jsxs("span", { children: [
276
+ progress,
277
+ "%"
278
+ ] }),
279
+ /* @__PURE__ */ jsx("button", { onClick: pause, style: { background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Pausar" })
281
280
  ] })
282
281
  ] }),
283
- /* @__PURE__ */ jsx(ProgressBar, { progress: state.progress })
282
+ /* @__PURE__ */ jsx(ProgressBar, { progress })
284
283
  ] }) }),
285
- state.status === "done" && !renderSuccess && /* @__PURE__ */ jsxs("div", { style: {
286
- display: "flex",
287
- alignItems: "center",
288
- gap: "8px",
289
- padding: "10px 14px",
290
- borderRadius: "8px",
291
- backgroundColor: "rgba(34,197,94,0.1)",
292
- color: "var(--silo-success, #22c55e)",
293
- fontSize: "14px"
294
- }, children: [
295
- /* @__PURE__ */ jsx("svg", { width: "18", height: "18", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
296
- /* @__PURE__ */ jsx("span", { children: "Upload complete" }),
297
- /* @__PURE__ */ jsx(
298
- "button",
299
- {
300
- onClick: (e) => {
301
- e.stopPropagation();
302
- reset();
303
- setPreview(null);
304
- },
305
- style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)" },
306
- children: "Upload another"
307
- }
308
- )
284
+ isPaused && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
285
+ /* @__PURE__ */ jsx("button", { onClick: () => resume({ ...bucket !== void 0 && { bucket }, visibility, ...image && { image } }), style: { flex: 1, padding: "8px", borderRadius: "6px", border: "none", backgroundColor: "#10b981", color: "#fff", fontSize: "13px", fontWeight: 600, cursor: "pointer" }, children: "Retomar upload" }),
286
+ /* @__PURE__ */ jsx("button", { onClick: () => {
287
+ abort();
288
+ setPreview(null);
289
+ }, style: { padding: "8px 12px", borderRadius: "6px", border: "1px solid #e2e8f0", background: "#f8fafc", fontSize: "13px", cursor: "pointer", color: "var(--silo-text-muted)" }, children: "Cancelar" })
309
290
  ] }),
310
- state.status === "error" && !renderError && /* @__PURE__ */ jsxs("div", { style: {
311
- display: "flex",
312
- alignItems: "center",
313
- gap: "8px",
314
- padding: "10px 14px",
315
- borderRadius: "8px",
316
- backgroundColor: "rgba(239,68,68,0.1)",
317
- color: "var(--silo-error, #ef4444)",
318
- fontSize: "14px"
319
- }, children: [
320
- /* @__PURE__ */ jsx("svg", { width: "18", height: "18", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
291
+ state.status === "done" && !renderSuccess && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "10px", padding: "10px 14px", borderRadius: "8px", backgroundColor: "rgba(34,197,94,0.08)", border: "1px solid rgba(34,197,94,0.2)", fontSize: "14px" }, children: [
292
+ /* @__PURE__ */ jsx("svg", { width: "18", height: "18", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", style: { color: "#22c55e", flexShrink: 0 }, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
293
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
294
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, color: "var(--silo-text)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: state.result.key }),
295
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: formatBytes(state.result.size) })
296
+ ] }),
297
+ /* @__PURE__ */ jsx("button", { onClick: () => {
298
+ reset();
299
+ setPreview(null);
300
+ }, style: { background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)", flexShrink: 0 }, children: "Enviar outro" })
301
+ ] }),
302
+ state.status === "error" && !renderError && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", padding: "10px 14px", borderRadius: "8px", backgroundColor: "rgba(239,68,68,0.1)", color: "var(--silo-error, #ef4444)", fontSize: "14px" }, children: [
321
303
  /* @__PURE__ */ jsx("span", { children: state.error.message }),
322
- /* @__PURE__ */ jsx(
323
- "button",
324
- {
325
- onClick: (e) => {
326
- e.stopPropagation();
327
- reset();
328
- },
329
- style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)" },
330
- children: "Retry"
331
- }
332
- )
304
+ /* @__PURE__ */ jsx("button", { onClick: () => {
305
+ reset();
306
+ setPreview(null);
307
+ }, style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", fontSize: "12px" }, children: "Tentar novamente" })
333
308
  ] })
334
309
  ] });
335
310
  }
336
311
  function VideoUploader({
337
312
  bucket,
338
313
  expiresIn,
339
- private: isPrivate = true,
314
+ visibility = "private",
340
315
  onUpload,
341
316
  onError,
342
317
  className = "",
@@ -345,6 +320,7 @@ function VideoUploader({
345
320
  maxSize,
346
321
  accept = "video/*",
347
322
  showPreview = true,
323
+ video,
348
324
  theme,
349
325
  renderIcon,
350
326
  renderProgress,
@@ -352,28 +328,25 @@ function VideoUploader({
352
328
  renderError,
353
329
  children
354
330
  }) {
355
- const uploadOpts = { private: isPrivate, ...bucket !== void 0 && { bucket }, ...expiresIn !== void 0 && { expiresIn } };
356
- const { state, upload, reset } = useUpload(uploadOpts);
331
+ const { state, upload, pause, resume, abort, reset } = useMultipartUpload(bucket);
357
332
  const [preview, setPreview] = useState(null);
358
333
  const t = resolveTheme(theme);
359
334
  const vars = themeToVars(t);
360
- const handleFiles = useCallback(
361
- async (files) => {
362
- const file = files[0];
363
- if (!file) return;
364
- if (showPreview) {
365
- const url = URL.createObjectURL(file);
366
- setPreview(url);
367
- }
368
- try {
369
- const result = await upload(file);
370
- onUpload?.(result);
371
- } catch (err) {
372
- onError?.(err instanceof Error ? err : new Error(String(err)));
373
- }
374
- },
375
- [upload, onUpload, onError, showPreview]
376
- );
335
+ const handleFiles = useCallback(async (files) => {
336
+ const file = files[0];
337
+ if (!file) return;
338
+ if (showPreview) setPreview(URL.createObjectURL(file));
339
+ try {
340
+ const result = await upload(file, {
341
+ ...bucket !== void 0 && { bucket },
342
+ visibility,
343
+ ...video && { video }
344
+ });
345
+ if (result) onUpload?.(result);
346
+ } catch (err) {
347
+ onError?.(err instanceof Error ? err : new Error(String(err)));
348
+ }
349
+ }, [upload, bucket, visibility, video, onUpload, onError, showPreview]);
377
350
  const containerStyle = {
378
351
  ...vars,
379
352
  display: "flex",
@@ -383,12 +356,11 @@ function VideoUploader({
383
356
  fontFamily: "var(--silo-font)",
384
357
  ...style
385
358
  };
386
- if (state.status === "error" && renderError) {
387
- return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderError(state.error, reset) });
388
- }
389
- if (state.status === "done" && renderSuccess) {
390
- return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderSuccess(state.result) });
391
- }
359
+ const isUploading = state.status === "uploading" || state.status === "preparing" || state.status === "completing";
360
+ const progress = state.status === "uploading" ? state.progress : state.status === "completing" ? 99 : 0;
361
+ const isPaused = state.status === "idle" && preview !== null;
362
+ if (state.status === "error" && renderError) return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderError(state.error, reset) });
363
+ if (state.status === "done" && renderSuccess) return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderSuccess(state.result) });
392
364
  return /* @__PURE__ */ jsxs("div", { className: `silo-video-uploader${className ? ` ${className}` : ""}`, style: containerStyle, children: [
393
365
  /* @__PURE__ */ jsx(
394
366
  DropZone,
@@ -397,69 +369,68 @@ function VideoUploader({
397
369
  ...maxSize !== void 0 && { maxSize },
398
370
  ...onError !== void 0 && { onError },
399
371
  ...theme !== void 0 && { theme },
400
- disabled: disabled || state.status === "uploading",
372
+ disabled: disabled || isUploading,
401
373
  onFiles: handleFiles,
402
374
  style: { padding: "32px 24px", textAlign: "center" },
403
- children: preview && state.status !== "uploading" ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }, children: [
404
- /* @__PURE__ */ jsx(
405
- "video",
406
- {
407
- src: preview,
408
- style: { maxWidth: "100%", maxHeight: "180px", borderRadius: "8px" },
409
- controls: false,
410
- muted: true,
411
- playsInline: true
412
- }
413
- ),
414
- /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Click or drag to replace" })
375
+ children: preview && !isUploading ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }, children: [
376
+ /* @__PURE__ */ jsx("video", { src: preview, style: { maxWidth: "100%", maxHeight: "180px", borderRadius: "8px" }, controls: false, muted: true, playsInline: true }),
377
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Clique ou arraste para substituir" })
415
378
  ] }) : /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }, children: [
416
379
  renderIcon ? renderIcon() : /* @__PURE__ */ jsx("svg", { width: "40", height: "40", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", style: { color: "var(--silo-text-muted)", opacity: 0.6 }, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.069A1 1 0 0121 8.878v6.244a1 1 0 01-1.447.894L15 14M3 8a2 2 0 012-2h8a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2V8z" }) }),
417
380
  children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
418
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "var(--silo-text)" }, children: "Drop video here" }),
419
- /* @__PURE__ */ jsx("span", { style: { fontSize: "13px", color: "var(--silo-text-muted)" }, children: "or click to browse" }),
381
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "var(--silo-text)" }, children: "Arraste o v\xEDdeo aqui" }),
382
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "13px", color: "var(--silo-text-muted)" }, children: "ou clique para selecionar" }),
420
383
  /* @__PURE__ */ jsxs("span", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: [
421
384
  "MP4, MOV, MKV, WebM",
422
- maxSize ? ` \xB7 Max ${formatBytes(maxSize)}` : ""
385
+ maxSize ? ` \xB7 M\xE1x ${formatBytes(maxSize)}` : ""
423
386
  ] })
424
387
  ] })
425
388
  ] })
426
389
  }
427
390
  ),
428
- state.status === "uploading" && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: renderProgress ? renderProgress(state.progress) : /* @__PURE__ */ jsxs(Fragment, { children: [
429
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", fontSize: "13px", color: "var(--silo-text-muted)" }, children: [
430
- /* @__PURE__ */ jsx("span", { children: "Uploading video\u2026" }),
431
- /* @__PURE__ */ jsxs("span", { children: [
432
- state.progress,
433
- "%"
391
+ isUploading && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: renderProgress ? renderProgress(progress) : /* @__PURE__ */ jsxs(Fragment, { children: [
392
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: "13px", color: "var(--silo-text-muted)" }, children: [
393
+ /* @__PURE__ */ jsx("span", { children: state.status === "completing" ? "Finalizando\u2026" : state.status === "preparing" ? "Preparando\u2026" : `Parte ${state.part} de ${state.totalParts}` }),
394
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
395
+ /* @__PURE__ */ jsxs("span", { children: [
396
+ progress,
397
+ "%"
398
+ ] }),
399
+ /* @__PURE__ */ jsx("button", { onClick: pause, style: { background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Pausar" })
434
400
  ] })
435
401
  ] }),
436
- /* @__PURE__ */ jsx(ProgressBar, { progress: state.progress }),
437
- /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Processing will start after upload completes" })
402
+ /* @__PURE__ */ jsx(ProgressBar, { progress }),
403
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: "O processamento inicia ap\xF3s o upload" })
438
404
  ] }) }),
405
+ isPaused && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
406
+ /* @__PURE__ */ jsx("button", { onClick: () => resume({ ...bucket !== void 0 && { bucket }, visibility, ...video && { video } }), style: { flex: 1, padding: "8px", borderRadius: "6px", border: "none", backgroundColor: "#10b981", color: "#fff", fontSize: "13px", fontWeight: 600, cursor: "pointer" }, children: "Retomar upload" }),
407
+ /* @__PURE__ */ jsx("button", { onClick: () => {
408
+ abort();
409
+ setPreview(null);
410
+ }, style: { padding: "8px 12px", borderRadius: "6px", border: "1px solid #e2e8f0", background: "#f8fafc", fontSize: "13px", cursor: "pointer", color: "var(--silo-text-muted)" }, children: "Cancelar" })
411
+ ] }),
439
412
  state.status === "done" && !renderSuccess && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", padding: "10px 14px", borderRadius: "8px", backgroundColor: "rgba(34,197,94,0.1)", color: "var(--silo-success, #22c55e)", fontSize: "14px" }, children: [
440
413
  /* @__PURE__ */ jsx("svg", { width: "18", height: "18", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
441
- /* @__PURE__ */ jsx("span", { children: "Video uploaded \u2014 processing in background" }),
442
- /* @__PURE__ */ jsx("button", { onClick: (e) => {
443
- e.stopPropagation();
414
+ /* @__PURE__ */ jsx("span", { children: "V\xEDdeo enviado \u2014 processando em segundo plano" }),
415
+ /* @__PURE__ */ jsx("button", { onClick: () => {
444
416
  reset();
445
417
  setPreview(null);
446
- }, style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Upload another" })
418
+ }, style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Enviar outro" })
447
419
  ] }),
448
420
  state.status === "error" && !renderError && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", padding: "10px 14px", borderRadius: "8px", backgroundColor: "rgba(239,68,68,0.1)", color: "var(--silo-error, #ef4444)", fontSize: "14px" }, children: [
449
- /* @__PURE__ */ jsx("svg", { width: "18", height: "18", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
450
421
  /* @__PURE__ */ jsx("span", { children: state.error.message }),
451
- /* @__PURE__ */ jsx("button", { onClick: (e) => {
452
- e.stopPropagation();
422
+ /* @__PURE__ */ jsx("button", { onClick: () => {
453
423
  reset();
454
- }, style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)" }, children: "Retry" })
424
+ setPreview(null);
425
+ }, style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", fontSize: "12px" }, children: "Tentar novamente" })
455
426
  ] })
456
427
  ] });
457
428
  }
458
429
  function FileUploader({
459
430
  bucket,
460
- expiresIn,
461
- private: isPrivate = true,
431
+ visibility = "private",
462
432
  onUpload,
433
+ onBatchUpload,
463
434
  onError,
464
435
  className = "",
465
436
  style,
@@ -467,6 +438,8 @@ function FileUploader({
467
438
  maxSize,
468
439
  accept,
469
440
  multiple = false,
441
+ image,
442
+ video,
470
443
  theme,
471
444
  renderIcon,
472
445
  renderProgress,
@@ -474,23 +447,8 @@ function FileUploader({
474
447
  renderError,
475
448
  children
476
449
  }) {
477
- const uploadOpts = { private: isPrivate, ...bucket !== void 0 && { bucket }, ...expiresIn !== void 0 && { expiresIn } };
478
- const { state, upload, reset } = useUpload(uploadOpts);
479
450
  const t = resolveTheme(theme);
480
451
  const vars = themeToVars(t);
481
- const handleFiles = useCallback(
482
- async (files) => {
483
- const file = files[0];
484
- if (!file) return;
485
- try {
486
- const result = await upload(file);
487
- onUpload?.(result);
488
- } catch (err) {
489
- onError?.(err instanceof Error ? err : new Error(String(err)));
490
- }
491
- },
492
- [upload, onUpload, onError]
493
- );
494
452
  const containerStyle = {
495
453
  ...vars,
496
454
  display: "flex",
@@ -500,14 +458,39 @@ function FileUploader({
500
458
  fontFamily: "var(--silo-font)",
501
459
  ...style
502
460
  };
503
- if (state.status === "error" && renderError) {
504
- return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderError(state.error, reset) });
505
- }
506
- if (state.status === "done" && renderSuccess) {
507
- return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderSuccess(state.result) });
508
- }
461
+ const single = useMultipartUpload(bucket);
462
+ const batch = useBatchUpload();
463
+ const handleFiles = useCallback(async (files) => {
464
+ if (multiple && files.length > 1) {
465
+ try {
466
+ const opts = { ...bucket !== void 0 && { bucket }, visibility, ...image && { image }, ...video && { video } };
467
+ const results = await batch.upload(files, opts);
468
+ onBatchUpload?.(results);
469
+ results.forEach((r) => onUpload?.(r));
470
+ } catch (err) {
471
+ onError?.(err instanceof Error ? err : new Error(String(err)));
472
+ }
473
+ } else {
474
+ const file = files[0];
475
+ if (!file) return;
476
+ try {
477
+ const opts = { ...bucket !== void 0 && { bucket }, visibility, ...image && { image }, ...video && { video } };
478
+ const result = await single.upload(file, opts);
479
+ if (result) onUpload?.(result);
480
+ } catch (err) {
481
+ onError?.(err instanceof Error ? err : new Error(String(err)));
482
+ }
483
+ }
484
+ }, [single, batch, multiple, bucket, visibility, image, video, onUpload, onBatchUpload, onError]);
485
+ const isBatch = batch.state.files.length > 0;
486
+ const isSingleUploading = single.state.status === "uploading" || single.state.status === "preparing" || single.state.status === "completing";
487
+ const isBatchUploading = batch.state.status === "uploading" || batch.state.status === "preparing";
488
+ const isUploading = isSingleUploading || isBatchUploading;
489
+ const singleProgress = single.state.status === "uploading" ? single.state.progress : single.state.status === "completing" ? 99 : 0;
490
+ if (single.state.status === "error" && renderError) return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderError(single.state.error, single.reset) });
491
+ if (single.state.status === "done" && renderSuccess) return /* @__PURE__ */ jsx("div", { style: containerStyle, children: renderSuccess(single.state.result) });
509
492
  return /* @__PURE__ */ jsxs("div", { className: `silo-file-uploader${className ? ` ${className}` : ""}`, style: containerStyle, children: [
510
- /* @__PURE__ */ jsx(
493
+ !isBatch && /* @__PURE__ */ jsx(
511
494
  DropZone,
512
495
  {
513
496
  ...accept !== void 0 && { accept },
@@ -515,56 +498,89 @@ function FileUploader({
515
498
  ...onError !== void 0 && { onError },
516
499
  ...theme !== void 0 && { theme },
517
500
  multiple,
518
- disabled: disabled || state.status === "uploading",
501
+ disabled: disabled || isUploading,
519
502
  onFiles: handleFiles,
520
503
  style: { padding: "28px 24px", textAlign: "center" },
521
504
  children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }, children: [
522
505
  renderIcon ? renderIcon() : /* @__PURE__ */ jsx("svg", { width: "40", height: "40", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", style: { color: "var(--silo-text-muted)", opacity: 0.6 }, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M9 13h6m-3-3v6m5 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }),
523
506
  children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
524
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "var(--silo-text)" }, children: multiple ? "Drop files here" : "Drop a file here" }),
525
- /* @__PURE__ */ jsx("span", { style: { fontSize: "13px", color: "var(--silo-text-muted)" }, children: "or click to browse" }),
507
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "var(--silo-text)" }, children: multiple ? "Arraste arquivos aqui" : "Arraste o arquivo aqui" }),
508
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "13px", color: "var(--silo-text-muted)" }, children: "ou clique para selecionar" }),
526
509
  maxSize && /* @__PURE__ */ jsxs("span", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: [
527
- "Max ",
510
+ "M\xE1x ",
528
511
  formatBytes(maxSize)
529
512
  ] })
530
513
  ] })
531
514
  ] })
532
515
  }
533
516
  ),
534
- state.status === "uploading" && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: renderProgress ? renderProgress(state.progress) : /* @__PURE__ */ jsxs(Fragment, { children: [
517
+ isSingleUploading && !isBatch && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: renderProgress ? renderProgress(singleProgress) : /* @__PURE__ */ jsxs(Fragment, { children: [
535
518
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", fontSize: "13px", color: "var(--silo-text-muted)" }, children: [
536
- /* @__PURE__ */ jsx("span", { children: "Uploading\u2026" }),
519
+ /* @__PURE__ */ jsx("span", { children: single.state.status === "completing" ? "Finalizando\u2026" : single.state.status === "preparing" ? "Preparando\u2026" : `Parte ${single.state.part} de ${single.state.totalParts}` }),
537
520
  /* @__PURE__ */ jsxs("span", { children: [
538
- state.progress,
521
+ singleProgress,
539
522
  "%"
540
523
  ] })
541
524
  ] }),
542
- /* @__PURE__ */ jsx(ProgressBar, { progress: state.progress })
525
+ /* @__PURE__ */ jsx(ProgressBar, { progress: singleProgress })
543
526
  ] }) }),
544
- state.status === "done" && !renderSuccess && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "10px", padding: "10px 14px", borderRadius: "8px", backgroundColor: "rgba(34,197,94,0.08)", border: "1px solid rgba(34,197,94,0.2)", fontSize: "14px" }, children: [
527
+ isBatch && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
528
+ batch.state.files.map((f, i) => {
529
+ const st = f.status;
530
+ const p = st.status === "uploading" ? st.progress : st.status === "paused" ? st.progress : st.status === "done" ? 100 : st.status === "completing" ? 99 : 0;
531
+ const isPaused = st.status === "paused";
532
+ const isDone = st.status === "done";
533
+ const isErr = st.status === "error";
534
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "10px 12px", backgroundColor: "var(--silo-bg)", borderRadius: "8px", border: "1px solid var(--silo-border)" }, children: [
535
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: isDone || isErr ? 0 : "6px" }, children: [
536
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "16px" }, children: getFileIcon(f.file.type) }),
537
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
538
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "13px", fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: f.file.name }),
539
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "11px", color: "var(--silo-text-muted)" }, children: formatBytes(f.file.size) })
540
+ ] }),
541
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", fontWeight: 600, color: isDone ? "#16a34a" : isErr ? "#ef4444" : isPaused ? "#f59e0b" : "var(--silo-accent)", flexShrink: 0 }, children: isDone ? "\u2713" : isErr ? "Erro" : isPaused ? `Pausado ${p}%` : `${p}%` }),
542
+ !isDone && !isErr && f.fileId && (isPaused ? /* @__PURE__ */ jsx("button", { onClick: () => batch.resumeFile(f.fileId), style: { fontSize: "11px", padding: "2px 8px", borderRadius: "4px", border: "none", backgroundColor: "#10b981", color: "#fff", cursor: "pointer" }, children: "Retomar" }) : st.status === "uploading" ? /* @__PURE__ */ jsx("button", { onClick: () => batch.pauseFile(f.fileId), style: { fontSize: "11px", padding: "2px 8px", borderRadius: "4px", border: "none", backgroundColor: "#f59e0b", color: "#fff", cursor: "pointer" }, children: "Pausar" }) : null)
543
+ ] }),
544
+ !isDone && !isErr && /* @__PURE__ */ jsx(ProgressBar, { progress: p })
545
+ ] }, i);
546
+ }),
547
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", marginTop: "4px" }, children: [
548
+ batch.state.status !== "done" && /* @__PURE__ */ jsx(
549
+ "button",
550
+ {
551
+ onClick: isBatchUploading ? batch.pauseAll : batch.resumeAll,
552
+ style: { flex: 1, padding: "8px", borderRadius: "6px", border: "none", backgroundColor: isBatchUploading ? "#f59e0b" : "#10b981", color: "#fff", fontSize: "13px", fontWeight: 600, cursor: "pointer" },
553
+ children: isBatchUploading ? "Pausar tudo" : "Retomar tudo"
554
+ }
555
+ ),
556
+ /* @__PURE__ */ jsx(
557
+ "button",
558
+ {
559
+ onClick: batch.state.status === "done" ? batch.reset : batch.abortAll,
560
+ style: { padding: "8px 14px", borderRadius: "6px", border: "none", backgroundColor: batch.state.status === "done" ? "var(--silo-accent)" : "rgba(239,68,68,0.1)", color: batch.state.status === "done" ? "#fff" : "#ef4444", fontSize: "13px", fontWeight: 600, cursor: "pointer" },
561
+ children: batch.state.status === "done" ? "Novo upload" : "Cancelar"
562
+ }
563
+ )
564
+ ] })
565
+ ] }),
566
+ single.state.status === "done" && !renderSuccess && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "10px", padding: "10px 14px", borderRadius: "8px", backgroundColor: "rgba(34,197,94,0.08)", border: "1px solid rgba(34,197,94,0.2)", fontSize: "14px" }, children: [
545
567
  /* @__PURE__ */ jsx("svg", { width: "18", height: "18", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", style: { color: "#22c55e", flexShrink: 0 }, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
546
568
  /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
547
- /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, color: "var(--silo-text)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: state.result.key }),
548
- /* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: formatBytes(state.result.size) })
569
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, color: "var(--silo-text)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: single.state.result.key }),
570
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "var(--silo-text-muted)" }, children: formatBytes(single.state.result.size) })
549
571
  ] }),
550
- /* @__PURE__ */ jsx("button", { onClick: (e) => {
551
- e.stopPropagation();
552
- reset();
553
- }, style: { background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)", flexShrink: 0 }, children: "Replace" })
572
+ /* @__PURE__ */ jsx("button", { onClick: single.reset, style: { background: "none", border: "none", cursor: "pointer", fontSize: "12px", color: "var(--silo-text-muted)", flexShrink: 0 }, children: "Enviar outro" })
554
573
  ] }),
555
- state.status === "error" && !renderError && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", padding: "10px 14px", borderRadius: "8px", backgroundColor: "rgba(239,68,68,0.1)", color: "var(--silo-error, #ef4444)", fontSize: "14px" }, children: [
556
- /* @__PURE__ */ jsx("span", { children: state.error.message }),
557
- /* @__PURE__ */ jsx("button", { onClick: (e) => {
558
- e.stopPropagation();
559
- reset();
560
- }, style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", fontSize: "12px" }, children: "Retry" })
574
+ single.state.status === "error" && !renderError && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", padding: "10px 14px", borderRadius: "8px", backgroundColor: "rgba(239,68,68,0.1)", color: "var(--silo-error, #ef4444)", fontSize: "14px" }, children: [
575
+ /* @__PURE__ */ jsx("span", { children: single.state.error.message }),
576
+ /* @__PURE__ */ jsx("button", { onClick: single.reset, style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", fontSize: "12px" }, children: "Tentar novamente" })
561
577
  ] })
562
578
  ] });
563
579
  }
564
580
  var TAB_LABELS = {
565
- image: { label: "Image", icon: "\u{1F5BC}\uFE0F" },
566
- video: { label: "Video", icon: "\u{1F3AC}" },
567
- file: { label: "File", icon: "\u{1F4CE}" }
581
+ image: { label: "Imagem", icon: "\u{1F5BC}\uFE0F" },
582
+ video: { label: "V\xEDdeo", icon: "\u{1F3AC}" },
583
+ file: { label: "Arquivo", icon: "\u{1F4CE}" }
568
584
  };
569
585
  function MediaUploader({
570
586
  tabs = ["image", "video", "file"],
@@ -576,6 +592,7 @@ function MediaUploader({
576
592
  style,
577
593
  theme,
578
594
  onUpload,
595
+ onBatchUpload,
579
596
  onError,
580
597
  ...shared
581
598
  }) {
@@ -649,8 +666,10 @@ function MediaUploader({
649
666
  {
650
667
  ...shared,
651
668
  ...fileProps,
669
+ multiple: true,
652
670
  ...theme !== void 0 && { theme },
653
671
  ...onUpload !== void 0 && { onUpload },
672
+ ...onBatchUpload !== void 0 && { onBatchUpload },
654
673
  ...onError !== void 0 && { onError }
655
674
  }
656
675
  )
@@ -1643,7 +1662,218 @@ function formatTime(seconds) {
1643
1662
  }
1644
1663
  return `${String(minutes).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
1645
1664
  }
1665
+ var RADIUS = { full: "50%", md: "12px", sm: "6px" };
1666
+ function Avatar({
1667
+ fileKey,
1668
+ bucket,
1669
+ initials,
1670
+ size = 40,
1671
+ shape = "full",
1672
+ className = "",
1673
+ style,
1674
+ alt = "avatar"
1675
+ }) {
1676
+ const { url } = useSignedUrl(fileKey ?? null);
1677
+ const [error, setError] = useState(false);
1678
+ const radius = RADIUS[shape];
1679
+ const base = {
1680
+ width: size,
1681
+ height: size,
1682
+ borderRadius: radius,
1683
+ overflow: "hidden",
1684
+ display: "inline-flex",
1685
+ alignItems: "center",
1686
+ justifyContent: "center",
1687
+ flexShrink: 0,
1688
+ fontSize: size * 0.38,
1689
+ fontWeight: 600,
1690
+ userSelect: "none",
1691
+ background: "var(--silo-bg, #e2e8f0)",
1692
+ color: "var(--silo-text-muted, #64748b)",
1693
+ ...style
1694
+ };
1695
+ if (url && !error) {
1696
+ return /* @__PURE__ */ jsx("span", { className, style: base, children: /* @__PURE__ */ jsx(
1697
+ "img",
1698
+ {
1699
+ src: url,
1700
+ alt,
1701
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" },
1702
+ onError: () => setError(true)
1703
+ }
1704
+ ) });
1705
+ }
1706
+ return /* @__PURE__ */ jsx("span", { className, style: base, "aria-label": alt, children: initials ? initials.slice(0, 2).toUpperCase() : "?" });
1707
+ }
1708
+ function Thumbnail({
1709
+ fileKey,
1710
+ bucket,
1711
+ mimeType,
1712
+ width = "100%",
1713
+ height = 160,
1714
+ fit = "cover",
1715
+ borderRadius = "var(--silo-radius, 12px)",
1716
+ placeholder,
1717
+ className = "",
1718
+ style,
1719
+ alt = "thumbnail"
1720
+ }) {
1721
+ const { url, loading } = useSignedUrl(fileKey);
1722
+ const [error, setError] = useState(false);
1723
+ const isVideo = mimeType?.startsWith("video/");
1724
+ const wrapper = {
1725
+ width,
1726
+ height,
1727
+ borderRadius,
1728
+ overflow: "hidden",
1729
+ display: "flex",
1730
+ alignItems: "center",
1731
+ justifyContent: "center",
1732
+ background: "var(--silo-bg, #f1f5f9)",
1733
+ position: "relative",
1734
+ flexShrink: 0,
1735
+ ...style
1736
+ };
1737
+ if (loading) {
1738
+ return /* @__PURE__ */ jsx("span", { className, style: wrapper, children: placeholder ?? /* @__PURE__ */ jsx("span", { style: { color: "var(--silo-text-muted, #94a3b8)", fontSize: 12 }, children: "..." }) });
1739
+ }
1740
+ if (error || !url) {
1741
+ return /* @__PURE__ */ jsx("span", { className, style: wrapper, children: /* @__PURE__ */ jsx("span", { style: { fontSize: 28 }, children: isVideo ? "\u{1F3AC}" : "\u{1F5BC}\uFE0F" }) });
1742
+ }
1743
+ if (isVideo) {
1744
+ return /* @__PURE__ */ jsxs("span", { className, style: wrapper, children: [
1745
+ /* @__PURE__ */ jsx(
1746
+ "video",
1747
+ {
1748
+ src: url,
1749
+ style: { width: "100%", height: "100%", objectFit: fit, display: "block" },
1750
+ muted: true,
1751
+ preload: "metadata",
1752
+ onError: () => setError(true)
1753
+ }
1754
+ ),
1755
+ /* @__PURE__ */ jsx(
1756
+ "span",
1757
+ {
1758
+ style: {
1759
+ position: "absolute",
1760
+ inset: 0,
1761
+ display: "flex",
1762
+ alignItems: "center",
1763
+ justifyContent: "center",
1764
+ pointerEvents: "none"
1765
+ },
1766
+ children: /* @__PURE__ */ jsx("span", { style: { fontSize: 24, opacity: 0.85 }, children: "\u25B6" })
1767
+ }
1768
+ )
1769
+ ] });
1770
+ }
1771
+ return /* @__PURE__ */ jsx("span", { className, style: wrapper, children: /* @__PURE__ */ jsx(
1772
+ "img",
1773
+ {
1774
+ src: url,
1775
+ alt,
1776
+ style: { width: "100%", height: "100%", objectFit: fit, display: "block" },
1777
+ onError: () => setError(true)
1778
+ }
1779
+ ) });
1780
+ }
1781
+ function Background({
1782
+ fileKey,
1783
+ bucket,
1784
+ size = "cover",
1785
+ position = "center",
1786
+ overlay,
1787
+ children,
1788
+ className = "",
1789
+ style
1790
+ }) {
1791
+ const { url } = useSignedUrl(fileKey);
1792
+ const wrapper = {
1793
+ position: "relative",
1794
+ backgroundImage: url ? `url(${url})` : void 0,
1795
+ backgroundSize: size,
1796
+ backgroundPosition: position,
1797
+ backgroundRepeat: "no-repeat",
1798
+ ...style
1799
+ };
1800
+ return /* @__PURE__ */ jsxs("div", { className, style: wrapper, children: [
1801
+ overlay && /* @__PURE__ */ jsx(
1802
+ "div",
1803
+ {
1804
+ "aria-hidden": true,
1805
+ style: {
1806
+ position: "absolute",
1807
+ inset: 0,
1808
+ background: overlay,
1809
+ pointerEvents: "none"
1810
+ }
1811
+ }
1812
+ ),
1813
+ children && /* @__PURE__ */ jsx("div", { style: { position: "relative", zIndex: 1 }, children })
1814
+ ] });
1815
+ }
1816
+ function FileIcon({
1817
+ mimeType,
1818
+ name,
1819
+ size,
1820
+ iconSize = 40,
1821
+ showName = false,
1822
+ showSize = false,
1823
+ className = "",
1824
+ style
1825
+ }) {
1826
+ const icon = getFileIcon(mimeType);
1827
+ const ext = name?.split(".").pop()?.toUpperCase();
1828
+ return /* @__PURE__ */ jsxs(
1829
+ "span",
1830
+ {
1831
+ className,
1832
+ style: {
1833
+ display: "inline-flex",
1834
+ flexDirection: "column",
1835
+ alignItems: "center",
1836
+ gap: 4,
1837
+ fontFamily: "var(--silo-font, inherit)",
1838
+ ...style
1839
+ },
1840
+ children: [
1841
+ /* @__PURE__ */ jsx("span", { style: { fontSize: iconSize, lineHeight: 1 }, children: icon }),
1842
+ ext && /* @__PURE__ */ jsx(
1843
+ "span",
1844
+ {
1845
+ style: {
1846
+ fontSize: iconSize * 0.22,
1847
+ fontWeight: 700,
1848
+ color: "var(--silo-text-muted, #64748b)",
1849
+ letterSpacing: "0.04em",
1850
+ textTransform: "uppercase"
1851
+ },
1852
+ children: ext
1853
+ }
1854
+ ),
1855
+ showName && name && /* @__PURE__ */ jsx(
1856
+ "span",
1857
+ {
1858
+ style: {
1859
+ fontSize: 12,
1860
+ color: "var(--silo-text, #0f172a)",
1861
+ maxWidth: iconSize * 3,
1862
+ overflow: "hidden",
1863
+ textOverflow: "ellipsis",
1864
+ whiteSpace: "nowrap",
1865
+ textAlign: "center"
1866
+ },
1867
+ title: name,
1868
+ children: name
1869
+ }
1870
+ ),
1871
+ showSize && size !== void 0 && /* @__PURE__ */ jsx("span", { style: { fontSize: 11, color: "var(--silo-text-muted, #64748b)" }, children: formatBytes(size) })
1872
+ ]
1873
+ }
1874
+ );
1875
+ }
1646
1876
 
1647
- export { DropZone, FileUploader, ImageUploader, MediaUploader, ProgressBar, Source, Sources, Storyboard, StoryboardFrame, Subtitle, Subtitles, Video, VideoPlayer, VideoUploader, defaultTheme, resolveTheme };
1877
+ export { Avatar, Background, DropZone, FileIcon, FileUploader, ImageUploader, MediaUploader, ProgressBar, Source, Sources, Storyboard, StoryboardFrame, Subtitle, Subtitles, Thumbnail, Video, VideoPlayer, VideoUploader, defaultTheme, resolveTheme };
1648
1878
  //# sourceMappingURL=index.js.map
1649
1879
  //# sourceMappingURL=index.js.map