@uploadista/vue 0.0.20-beta.9 → 0.1.0-beta.5

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.
Files changed (77) hide show
  1. package/dist/components/index.d.mts +3 -3
  2. package/dist/components/index.mjs +1 -1
  3. package/dist/{components-CskPs6sR.css → components-B_L33hsM.css} +33 -33
  4. package/dist/{components-CskPs6sR.css.map → components-B_L33hsM.css.map} +1 -1
  5. package/dist/components-MZ9ETx9c.mjs +2 -0
  6. package/dist/components-MZ9ETx9c.mjs.map +1 -0
  7. package/dist/composables/index.d.mts +1 -1
  8. package/dist/composables/index.mjs +1 -1
  9. package/dist/composables-Dny_9Zrg.mjs +2 -0
  10. package/dist/composables-Dny_9Zrg.mjs.map +1 -0
  11. package/dist/index-6Scxoy1b.d.mts +1289 -0
  12. package/dist/index-6Scxoy1b.d.mts.map +1 -0
  13. package/dist/{index-B2fUTjNP.d.mts → index-BpCRFLJ5.d.mts} +4 -4
  14. package/dist/index-BpCRFLJ5.d.mts.map +1 -0
  15. package/dist/{index-DiRR_Ua6.d.mts → index-RY4FPqAk.d.mts} +431 -432
  16. package/dist/index-RY4FPqAk.d.mts.map +1 -0
  17. package/dist/index.d.mts +5 -5
  18. package/dist/index.mjs +1 -1
  19. package/dist/providers/index.d.mts +1 -1
  20. package/dist/providers/index.mjs +1 -1
  21. package/dist/{providers-fqmOwF71.mjs → providers-CjhEBaQV.mjs} +2 -2
  22. package/dist/providers-CjhEBaQV.mjs.map +1 -0
  23. package/dist/useUploadistaClient-WVuo8jYH.mjs.map +1 -1
  24. package/dist/utils/index.d.mts +62 -2
  25. package/dist/utils/index.d.mts.map +1 -0
  26. package/package.json +11 -9
  27. package/src/__tests__/setup.ts +154 -0
  28. package/src/components/FlowUploadList.vue +25 -24
  29. package/src/components/UploadList.vue +3 -6
  30. package/src/components/UploadZone.vue +2 -5
  31. package/src/components/flow/Flow.vue +16 -4
  32. package/src/components/flow/FlowDropZone.vue +4 -2
  33. package/src/components/flow/FlowInput.vue +14 -8
  34. package/src/components/flow/FlowInputDropZone.vue +4 -2
  35. package/src/components/flow/FlowInputPreview.vue +3 -1
  36. package/src/components/flow/FlowProgress.vue +1 -1
  37. package/src/components/flow/FlowStatus.vue +1 -1
  38. package/src/components/flow/useFlowContext.ts +7 -5
  39. package/src/components/index.ts +4 -2
  40. package/src/components/upload/Upload.vue +146 -0
  41. package/src/components/upload/UploadCancel.vue +22 -0
  42. package/src/components/upload/UploadClearCompleted.vue +24 -0
  43. package/src/components/upload/UploadDropZone.vue +96 -0
  44. package/src/components/upload/UploadError.vue +42 -0
  45. package/src/components/upload/UploadItem.vue +54 -0
  46. package/src/components/upload/UploadItems.vue +33 -0
  47. package/src/components/upload/UploadProgress.vue +35 -0
  48. package/src/components/upload/UploadReset.vue +20 -0
  49. package/src/components/upload/UploadRetry.vue +22 -0
  50. package/src/components/upload/UploadStartAll.vue +30 -0
  51. package/src/components/upload/UploadStatus.vue +65 -0
  52. package/src/components/upload/index.ts +98 -0
  53. package/src/components/upload/useUploadContext.ts +67 -0
  54. package/src/composables/eventUtils.test.ts +267 -0
  55. package/src/composables/eventUtils.ts +5 -4
  56. package/src/composables/index.ts +1 -1
  57. package/src/composables/useDragDrop.test.ts +304 -0
  58. package/src/composables/useFlow.ts +6 -2
  59. package/src/composables/useFlowManagerContext.ts +5 -1
  60. package/src/composables/useUploadEvents.ts +1 -4
  61. package/src/composables/useUploadistaClient.test.ts +152 -0
  62. package/src/index.ts +65 -4
  63. package/src/providers/FlowManagerProvider.vue +5 -2
  64. package/src/utils/index.test.ts +396 -0
  65. package/src/utils/is-browser-file.test.ts +45 -0
  66. package/vitest.config.ts +25 -0
  67. package/dist/components-BxBz_7tS.mjs +0 -2
  68. package/dist/components-BxBz_7tS.mjs.map +0 -1
  69. package/dist/composables-BZ2c_WgI.mjs +0 -2
  70. package/dist/composables-BZ2c_WgI.mjs.map +0 -1
  71. package/dist/index-B2fUTjNP.d.mts.map +0 -1
  72. package/dist/index-BLNNvTVx.d.mts +0 -62
  73. package/dist/index-BLNNvTVx.d.mts.map +0 -1
  74. package/dist/index-D3PNaPGh.d.mts +0 -787
  75. package/dist/index-D3PNaPGh.d.mts.map +0 -1
  76. package/dist/index-DiRR_Ua6.d.mts.map +0 -1
  77. package/dist/providers-fqmOwF71.mjs.map +0 -1
@@ -0,0 +1,396 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ createMockFile,
4
+ mockCreateObjectURL,
5
+ mockRevokeObjectURL,
6
+ } from "../__tests__/setup";
7
+ import {
8
+ calculateProgress,
9
+ createFilePreview,
10
+ formatDuration,
11
+ formatFileSize,
12
+ formatSpeed,
13
+ generateUploadId,
14
+ getFileExtension,
15
+ isAudioFile,
16
+ isDocumentFile,
17
+ isImageFile,
18
+ isVideoFile,
19
+ revokeFilePreview,
20
+ validateFileType,
21
+ } from "./index";
22
+
23
+ describe("formatFileSize", () => {
24
+ it("should format 0 bytes", () => {
25
+ expect(formatFileSize(0)).toBe("0 Bytes");
26
+ });
27
+
28
+ it("should format bytes", () => {
29
+ expect(formatFileSize(500)).toBe("500 Bytes");
30
+ });
31
+
32
+ it("should format kilobytes", () => {
33
+ expect(formatFileSize(1024)).toBe("1 KB");
34
+ expect(formatFileSize(1536)).toBe("1.5 KB");
35
+ });
36
+
37
+ it("should format megabytes", () => {
38
+ expect(formatFileSize(1024 * 1024)).toBe("1 MB");
39
+ expect(formatFileSize(5.5 * 1024 * 1024)).toBe("5.5 MB");
40
+ });
41
+
42
+ it("should format gigabytes", () => {
43
+ expect(formatFileSize(1024 * 1024 * 1024)).toBe("1 GB");
44
+ });
45
+
46
+ it("should format terabytes", () => {
47
+ expect(formatFileSize(1024 * 1024 * 1024 * 1024)).toBe("1 TB");
48
+ });
49
+ });
50
+
51
+ describe("formatSpeed", () => {
52
+ it("should format 0 B/s", () => {
53
+ expect(formatSpeed(0)).toBe("0 B/s");
54
+ });
55
+
56
+ it("should format bytes per second", () => {
57
+ expect(formatSpeed(500)).toBe("500 B/s");
58
+ });
59
+
60
+ it("should format kilobytes per second", () => {
61
+ expect(formatSpeed(1024)).toBe("1 KB/s");
62
+ });
63
+
64
+ it("should format megabytes per second", () => {
65
+ expect(formatSpeed(1024 * 1024)).toBe("1 MB/s");
66
+ });
67
+
68
+ it("should format gigabytes per second", () => {
69
+ expect(formatSpeed(1024 * 1024 * 1024)).toBe("1 GB/s");
70
+ });
71
+ });
72
+
73
+ describe("formatDuration", () => {
74
+ it("should format milliseconds", () => {
75
+ expect(formatDuration(500)).toBe("500ms");
76
+ expect(formatDuration(999)).toBe("999ms");
77
+ });
78
+
79
+ it("should format seconds", () => {
80
+ expect(formatDuration(1000)).toBe("1s");
81
+ expect(formatDuration(30000)).toBe("30s");
82
+ expect(formatDuration(59999)).toBe("60s");
83
+ });
84
+
85
+ it("should format minutes", () => {
86
+ expect(formatDuration(60000)).toBe("1m");
87
+ expect(formatDuration(90000)).toBe("1m 30s");
88
+ expect(formatDuration(120000)).toBe("2m");
89
+ });
90
+
91
+ it("should format hours", () => {
92
+ expect(formatDuration(3600000)).toBe("1h");
93
+ expect(formatDuration(3600000 + 1800000)).toBe("1h 30m");
94
+ expect(formatDuration(7200000)).toBe("2h");
95
+ });
96
+ });
97
+
98
+ describe("validateFileType", () => {
99
+ it("should return true when accept is empty", () => {
100
+ const file = createMockFile("test.txt", 100, "text/plain");
101
+ expect(validateFileType(file, [])).toBe(true);
102
+ });
103
+
104
+ it("should validate by file extension", () => {
105
+ const txtFile = createMockFile("test.txt", 100, "text/plain");
106
+ const pdfFile = createMockFile("doc.pdf", 100, "application/pdf");
107
+
108
+ expect(validateFileType(txtFile, [".txt"])).toBe(true);
109
+ expect(validateFileType(txtFile, [".pdf"])).toBe(false);
110
+ expect(validateFileType(pdfFile, [".pdf", ".doc"])).toBe(true);
111
+ });
112
+
113
+ it("should validate by exact MIME type", () => {
114
+ const file = createMockFile("test.txt", 100, "text/plain");
115
+
116
+ expect(validateFileType(file, ["text/plain"])).toBe(true);
117
+ expect(validateFileType(file, ["application/json"])).toBe(false);
118
+ });
119
+
120
+ it("should validate by wildcard MIME type", () => {
121
+ const imageFile = createMockFile("photo.jpg", 100, "image/jpeg");
122
+ const videoFile = createMockFile("video.mp4", 100, "video/mp4");
123
+
124
+ expect(validateFileType(imageFile, ["image/*"])).toBe(true);
125
+ expect(validateFileType(imageFile, ["video/*"])).toBe(false);
126
+ expect(validateFileType(videoFile, ["video/*"])).toBe(true);
127
+ });
128
+
129
+ it("should validate with mixed accept types", () => {
130
+ const imageFile = createMockFile("photo.jpg", 100, "image/jpeg");
131
+ const pdfFile = createMockFile("doc.pdf", 100, "application/pdf");
132
+
133
+ expect(validateFileType(imageFile, ["image/*", ".pdf"])).toBe(true);
134
+ expect(validateFileType(pdfFile, ["image/*", ".pdf"])).toBe(true);
135
+ });
136
+
137
+ it("should be case-insensitive for file extensions", () => {
138
+ const file = createMockFile("TEST.TXT", 100, "text/plain");
139
+ expect(validateFileType(file, [".txt"])).toBe(true);
140
+ });
141
+ });
142
+
143
+ describe("generateUploadId", () => {
144
+ it("should generate unique IDs", () => {
145
+ const id1 = generateUploadId();
146
+ const id2 = generateUploadId();
147
+
148
+ expect(id1).not.toBe(id2);
149
+ });
150
+
151
+ it("should start with 'upload-'", () => {
152
+ const id = generateUploadId();
153
+ expect(id).toMatch(/^upload-/);
154
+ });
155
+
156
+ it("should contain timestamp and random string", () => {
157
+ const id = generateUploadId();
158
+ expect(id).toMatch(/^upload-\d+-[a-z0-9]+$/);
159
+ });
160
+ });
161
+
162
+ describe("getFileExtension", () => {
163
+ it("should extract file extension", () => {
164
+ expect(getFileExtension("file.txt")).toBe("txt");
165
+ expect(getFileExtension("image.jpeg")).toBe("jpeg");
166
+ expect(getFileExtension("document.pdf")).toBe("pdf");
167
+ });
168
+
169
+ it("should return lowercase extension", () => {
170
+ expect(getFileExtension("FILE.TXT")).toBe("txt");
171
+ expect(getFileExtension("Image.JPEG")).toBe("jpeg");
172
+ });
173
+
174
+ it("should handle files with multiple dots", () => {
175
+ expect(getFileExtension("archive.tar.gz")).toBe("gz");
176
+ expect(getFileExtension("my.file.name.txt")).toBe("txt");
177
+ });
178
+
179
+ it("should return empty string for files without extension", () => {
180
+ expect(getFileExtension("noextension")).toBe("");
181
+ expect(getFileExtension("Makefile")).toBe("");
182
+ });
183
+ });
184
+
185
+ describe("isImageFile", () => {
186
+ it("should identify image files", () => {
187
+ expect(isImageFile(createMockFile("photo.jpg", 100, "image/jpeg"))).toBe(
188
+ true,
189
+ );
190
+ expect(isImageFile(createMockFile("photo.png", 100, "image/png"))).toBe(
191
+ true,
192
+ );
193
+ expect(isImageFile(createMockFile("photo.gif", 100, "image/gif"))).toBe(
194
+ true,
195
+ );
196
+ expect(isImageFile(createMockFile("photo.webp", 100, "image/webp"))).toBe(
197
+ true,
198
+ );
199
+ });
200
+
201
+ it("should reject non-image files", () => {
202
+ expect(isImageFile(createMockFile("video.mp4", 100, "video/mp4"))).toBe(
203
+ false,
204
+ );
205
+ expect(isImageFile(createMockFile("doc.pdf", 100, "application/pdf"))).toBe(
206
+ false,
207
+ );
208
+ });
209
+ });
210
+
211
+ describe("isVideoFile", () => {
212
+ it("should identify video files", () => {
213
+ expect(isVideoFile(createMockFile("video.mp4", 100, "video/mp4"))).toBe(
214
+ true,
215
+ );
216
+ expect(isVideoFile(createMockFile("video.webm", 100, "video/webm"))).toBe(
217
+ true,
218
+ );
219
+ expect(isVideoFile(createMockFile("video.avi", 100, "video/avi"))).toBe(
220
+ true,
221
+ );
222
+ });
223
+
224
+ it("should reject non-video files", () => {
225
+ expect(isVideoFile(createMockFile("photo.jpg", 100, "image/jpeg"))).toBe(
226
+ false,
227
+ );
228
+ expect(isVideoFile(createMockFile("audio.mp3", 100, "audio/mpeg"))).toBe(
229
+ false,
230
+ );
231
+ });
232
+ });
233
+
234
+ describe("isAudioFile", () => {
235
+ it("should identify audio files", () => {
236
+ expect(isAudioFile(createMockFile("song.mp3", 100, "audio/mpeg"))).toBe(
237
+ true,
238
+ );
239
+ expect(isAudioFile(createMockFile("song.wav", 100, "audio/wav"))).toBe(
240
+ true,
241
+ );
242
+ expect(isAudioFile(createMockFile("song.ogg", 100, "audio/ogg"))).toBe(
243
+ true,
244
+ );
245
+ });
246
+
247
+ it("should reject non-audio files", () => {
248
+ expect(isAudioFile(createMockFile("video.mp4", 100, "video/mp4"))).toBe(
249
+ false,
250
+ );
251
+ expect(isAudioFile(createMockFile("photo.jpg", 100, "image/jpeg"))).toBe(
252
+ false,
253
+ );
254
+ });
255
+ });
256
+
257
+ describe("isDocumentFile", () => {
258
+ it("should identify PDF files", () => {
259
+ expect(
260
+ isDocumentFile(createMockFile("doc.pdf", 100, "application/pdf")),
261
+ ).toBe(true);
262
+ });
263
+
264
+ it("should identify Word documents", () => {
265
+ expect(
266
+ isDocumentFile(createMockFile("doc.doc", 100, "application/msword")),
267
+ ).toBe(true);
268
+ expect(
269
+ isDocumentFile(
270
+ createMockFile(
271
+ "doc.docx",
272
+ 100,
273
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
274
+ ),
275
+ ),
276
+ ).toBe(true);
277
+ });
278
+
279
+ it("should identify Excel files", () => {
280
+ expect(
281
+ isDocumentFile(createMockFile("sheet.xls", 100, "application/vnd.ms-excel")),
282
+ ).toBe(true);
283
+ expect(
284
+ isDocumentFile(
285
+ createMockFile(
286
+ "sheet.xlsx",
287
+ 100,
288
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
289
+ ),
290
+ ),
291
+ ).toBe(true);
292
+ });
293
+
294
+ it("should identify PowerPoint files", () => {
295
+ expect(
296
+ isDocumentFile(
297
+ createMockFile("pres.ppt", 100, "application/vnd.ms-powerpoint"),
298
+ ),
299
+ ).toBe(true);
300
+ expect(
301
+ isDocumentFile(
302
+ createMockFile(
303
+ "pres.pptx",
304
+ 100,
305
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
306
+ ),
307
+ ),
308
+ ).toBe(true);
309
+ });
310
+
311
+ it("should identify text files", () => {
312
+ expect(
313
+ isDocumentFile(createMockFile("readme.txt", 100, "text/plain")),
314
+ ).toBe(true);
315
+ expect(isDocumentFile(createMockFile("data.csv", 100, "text/csv"))).toBe(
316
+ true,
317
+ );
318
+ });
319
+
320
+ it("should identify RTF files", () => {
321
+ expect(
322
+ isDocumentFile(createMockFile("doc.rtf", 100, "application/rtf")),
323
+ ).toBe(true);
324
+ });
325
+
326
+ it("should reject non-document files", () => {
327
+ expect(
328
+ isDocumentFile(createMockFile("photo.jpg", 100, "image/jpeg")),
329
+ ).toBe(false);
330
+ expect(
331
+ isDocumentFile(createMockFile("video.mp4", 100, "video/mp4")),
332
+ ).toBe(false);
333
+ });
334
+ });
335
+
336
+ describe("createFilePreview", () => {
337
+ it("should create preview URL for image files", () => {
338
+ const file = createMockFile("photo.jpg", 100, "image/jpeg");
339
+ const preview = createFilePreview(file);
340
+ expect(preview).toBe("blob:mock-url");
341
+ expect(mockCreateObjectURL).toHaveBeenCalledWith(file);
342
+ });
343
+
344
+ it("should create preview URL for video files", () => {
345
+ const file = createMockFile("video.mp4", 100, "video/mp4");
346
+ const preview = createFilePreview(file);
347
+ expect(preview).toBe("blob:mock-url");
348
+ expect(mockCreateObjectURL).toHaveBeenCalledWith(file);
349
+ });
350
+
351
+ it("should create preview URL for audio files", () => {
352
+ const file = createMockFile("audio.mp3", 100, "audio/mpeg");
353
+ const preview = createFilePreview(file);
354
+ expect(preview).toBe("blob:mock-url");
355
+ expect(mockCreateObjectURL).toHaveBeenCalledWith(file);
356
+ });
357
+
358
+ it("should return null for unsupported file types", () => {
359
+ const file = createMockFile("doc.pdf", 100, "application/pdf");
360
+ const preview = createFilePreview(file);
361
+ expect(preview).toBeNull();
362
+ });
363
+ });
364
+
365
+ describe("revokeFilePreview", () => {
366
+ it("should call URL.revokeObjectURL", () => {
367
+ const mockUrl = "blob:test-url";
368
+ revokeFilePreview(mockUrl);
369
+ expect(mockRevokeObjectURL).toHaveBeenCalledWith(mockUrl);
370
+ });
371
+ });
372
+
373
+ describe("calculateProgress", () => {
374
+ it("should return 0 when total is 0", () => {
375
+ expect(calculateProgress(50, 0)).toBe(0);
376
+ });
377
+
378
+ it("should calculate correct percentage", () => {
379
+ expect(calculateProgress(50, 100)).toBe(50);
380
+ expect(calculateProgress(25, 100)).toBe(25);
381
+ expect(calculateProgress(75, 100)).toBe(75);
382
+ });
383
+
384
+ it("should round to nearest integer", () => {
385
+ expect(calculateProgress(33, 100)).toBe(33);
386
+ expect(calculateProgress(1, 3)).toBe(33);
387
+ });
388
+
389
+ it("should cap at 100%", () => {
390
+ expect(calculateProgress(150, 100)).toBe(100);
391
+ });
392
+
393
+ it("should not go below 0%", () => {
394
+ expect(calculateProgress(-10, 100)).toBe(0);
395
+ });
396
+ });
@@ -0,0 +1,45 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockFile } from "../__tests__/setup";
3
+ import { isBrowserFile } from "./is-browser-file";
4
+
5
+ describe("isBrowserFile", () => {
6
+ it("should return true for File instances", () => {
7
+ const file = createMockFile("test.txt", 100, "text/plain");
8
+ expect(isBrowserFile(file)).toBe(true);
9
+ });
10
+
11
+ it("should return false for null", () => {
12
+ expect(isBrowserFile(null)).toBe(false);
13
+ });
14
+
15
+ it("should return false for undefined", () => {
16
+ expect(isBrowserFile(undefined)).toBe(false);
17
+ });
18
+
19
+ it("should return false for strings", () => {
20
+ expect(isBrowserFile("file.txt")).toBe(false);
21
+ });
22
+
23
+ it("should return false for numbers", () => {
24
+ expect(isBrowserFile(123)).toBe(false);
25
+ });
26
+
27
+ it("should return false for plain objects", () => {
28
+ expect(isBrowserFile({ name: "file.txt", size: 100 })).toBe(false);
29
+ });
30
+
31
+ it("should return false for arrays", () => {
32
+ expect(isBrowserFile([])).toBe(false);
33
+ });
34
+
35
+ it("should return false for Blob instances that are not Files", () => {
36
+ const blob = new Blob(["content"], { type: "text/plain" });
37
+ expect(isBrowserFile(blob)).toBe(false);
38
+ });
39
+
40
+ it("should return true for File created from Blob", () => {
41
+ const blob = new Blob(["content"], { type: "text/plain" });
42
+ const file = new File([blob], "test.txt", { type: "text/plain" });
43
+ expect(isBrowserFile(file)).toBe(true);
44
+ });
45
+ });
@@ -0,0 +1,25 @@
1
+ import vue from "@vitejs/plugin-vue";
2
+ import { defineConfig } from "vitest/config";
3
+
4
+ export default defineConfig({
5
+ plugins: [vue()],
6
+ test: {
7
+ globals: true,
8
+ environment: "happy-dom",
9
+ include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
10
+ exclude: ["node_modules", "dist"],
11
+ setupFiles: ["./src/__tests__/setup.ts"],
12
+ coverage: {
13
+ provider: "v8",
14
+ reporter: ["text", "json", "html"],
15
+ exclude: [
16
+ "node_modules/",
17
+ "dist/",
18
+ "**/*.d.ts",
19
+ "**/*.test.ts",
20
+ "**/*.spec.ts",
21
+ "**/__tests__/**",
22
+ ],
23
+ },
24
+ },
25
+ });
@@ -1,2 +0,0 @@
1
- import{m as e}from"./utils-B_r6xppE.mjs";import{a as t,n,o as r,r as i}from"./composables-BZ2c_WgI.mjs";import{Fragment as a,computed as o,createCommentVNode as s,createElementBlock as c,createElementVNode as l,createTextVNode as u,defineComponent as d,guardReactiveProps as f,inject as p,mergeProps as m,normalizeClass as h,normalizeProps as g,normalizeStyle as _,openBlock as v,provide as y,ref as b,renderList as x,renderSlot as S,toDisplayString as C,unref as w,withKeys as T,withModifiers as ee}from"vue";var E=(e,t)=>{let n=e.__vccOpts||e;for(let[e,r]of t)n[e]=r;return n};const te={class:`flow-upload-list`},ne={class:`flow-upload-list__item-header`},re={class:`flow-upload-list__item-icon`},ie={class:`flow-upload-list__item-name`},ae={class:`flow-upload-list__item-details`},D={class:`flow-upload-list__item-size`},O={key:0,class:`flow-upload-list__item-job`},k={key:0,class:`flow-upload-list__item-progress`},A={class:`flow-upload-list__progress-bar`},j={class:`flow-upload-list__progress-text`},M={key:1,class:`flow-upload-list__item-error`},N={key:2,class:`flow-upload-list__item-success`};var P=E(d({__name:`FlowUploadList`,props:{uploads:{},filter:{type:Function},sortBy:{type:Function}},setup(t){let n=t,r=o(()=>{let e=n.uploads;return n.filter&&(e=e.filter(n.filter)),n.sortBy&&(e=[...e].sort(n.sortBy)),e}),i=o(()=>({pending:r.value.filter(e=>e.status===`pending`),uploading:r.value.filter(e=>e.status===`uploading`),success:r.value.filter(e=>e.status===`success`),error:r.value.filter(e=>e.status===`error`),aborted:r.value.filter(e=>e.status===`aborted`)})),u=e=>{if(e===0)return`0 Bytes`;let t=1024,n=[`Bytes`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return`${parseFloat((e/t**r).toFixed(2))} ${n[r]}`},d=e=>{switch(e){case`pending`:return`⏳`;case`uploading`:return`📤`;case`success`:return`✅`;case`error`:return`❌`;case`aborted`:return`⏹️`;default:return`❓`}},f=e=>{switch(e){case`pending`:return`#6c757d`;case`uploading`:return`#007bff`;case`success`:return`#28a745`;case`error`:return`#dc3545`;case`aborted`:return`#6c757d`;default:return`#6c757d`}};return(t,n)=>(v(),c(`div`,te,[S(t.$slots,`default`,{items:r.value,itemsByStatus:i.value},()=>[s(` Default rendering: simple list of flow upload items `),(v(!0),c(a,null,x(r.value,(n,r)=>(v(),c(`div`,{key:n.id,class:h([`flow-upload-list__item`,`flow-upload-list__item--${n.status}`])},[S(t.$slots,`item`,{item:n,index:r,isPending:n.status===`pending`,isUploading:n.status===`uploading`,isSuccess:n.status===`success`,isError:n.status===`error`,isAborted:n.status===`aborted`,formatFileSize:u},()=>[s(` Default item template `),l(`div`,ne,[l(`span`,re,C(d(n.status)),1),l(`span`,ie,C(w(e)(n.file)?n.file.name:`File`),1),l(`span`,{class:`flow-upload-list__item-status`,style:_({color:f(n.status)})},C(n.status.toUpperCase()),5)]),l(`div`,ae,[l(`span`,D,C(u(n.totalBytes)),1),n.jobId?(v(),c(`span`,O,` Job: `+C(n.jobId.slice(0,8))+`... `,1)):s(`v-if`,!0)]),n.status===`uploading`?(v(),c(`div`,k,[l(`div`,A,[l(`div`,{class:`flow-upload-list__progress-fill`,style:_({width:`${n.progress}%`})},null,4)]),l(`span`,j,C(n.progress)+`% • `+C(u(n.bytesUploaded))+` / `+C(u(n.totalBytes)),1)])):s(`v-if`,!0),n.status===`error`&&n.error?(v(),c(`div`,M,C(n.error.message),1)):s(`v-if`,!0),n.status===`success`?(v(),c(`div`,N,` Upload complete `)):s(`v-if`,!0)],!0)],2))),128))],!0)]))}}),[[`__scopeId`,`data-v-eabb787d`]]);const F={class:`upload-list`},I={class:`upload-list__item-header`},L={class:`upload-list__item-icon`},R={class:`upload-list__item-name`},z={key:0,class:`upload-list__item-size`},B={key:1,class:`upload-list__item-progress`},V={class:`upload-list__progress-bar`},H={class:`upload-list__progress-text`},U={key:2,class:`upload-list__item-error`};var W=E(d({__name:`UploadList`,props:{uploads:{},filter:{type:Function},sortBy:{type:Function}},setup(t){let n=t,r=o(()=>{let e=n.uploads;return n.filter&&(e=e.filter(n.filter)),n.sortBy&&(e=[...e].sort(n.sortBy)),e}),i=o(()=>({idle:r.value.filter(e=>e.state.status===`idle`),uploading:r.value.filter(e=>e.state.status===`uploading`),success:r.value.filter(e=>e.state.status===`success`),error:r.value.filter(e=>e.state.status===`error`),aborted:r.value.filter(e=>e.state.status===`aborted`)})),u=e=>{if(e===0)return`0 Bytes`;let t=1024,n=[`Bytes`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return`${parseFloat((e/t**r).toFixed(2))} ${n[r]}`},d=e=>{switch(e){case`idle`:return`⏳`;case`uploading`:return`📤`;case`success`:return`✅`;case`error`:return`❌`;case`aborted`:return`⏹️`;default:return`❓`}},f=e=>{switch(e){case`idle`:return`#6c757d`;case`uploading`:return`#007bff`;case`success`:return`#28a745`;case`error`:return`#dc3545`;case`aborted`:return`#6c757d`;default:return`#6c757d`}};return(t,n)=>(v(),c(`div`,F,[S(t.$slots,`default`,{items:r.value,itemsByStatus:i.value},()=>[s(` Default rendering: simple list of upload items `),(v(!0),c(a,null,x(r.value,(n,r)=>(v(),c(`div`,{key:n.id,class:h([`upload-list__item`,`upload-list__item--${n.state.status}`])},[S(t.$slots,`item`,{item:n,index:r,isUploading:n.state.status===`uploading`,isSuccess:n.state.status===`success`,isError:n.state.status===`error`,formatFileSize:u},()=>[s(` Default item template `),l(`div`,I,[l(`span`,L,C(d(n.state.status)),1),l(`span`,R,C(w(e)(n.file)?n.file.name:`File`),1),l(`span`,{class:`upload-list__item-status`,style:_({color:f(n.state.status)})},C(n.state.status.toUpperCase()),5)]),n.state.totalBytes?(v(),c(`div`,z,C(u(n.state.totalBytes)),1)):s(`v-if`,!0),n.state.status===`uploading`?(v(),c(`div`,B,[l(`div`,V,[l(`div`,{class:`upload-list__progress-fill`,style:_({width:`${n.state.progress}%`})},null,4)]),l(`span`,H,C(n.state.progress)+`%`,1)])):s(`v-if`,!0),n.state.status===`error`&&n.state.error?(v(),c(`div`,U,C(n.state.error.message),1)):s(`v-if`,!0)],!0)],2))),128))],!0)]))}}),[[`__scopeId`,`data-v-70c8fe1a`]]);const G=[`tabindex`,`aria-disabled`,`aria-label`,`onKeydown`],K={class:`upload-zone__content`},q={key:0},J={key:1},oe={key:2,class:`upload-zone__errors`},se=[`multiple`,`accept`,`disabled`];var ce=E(d({__name:`UploadZone`,props:{accept:{},multiple:{type:Boolean,default:!0},disabled:{type:Boolean,default:!1},maxFileSize:{},validator:{},multiUploadOptions:{},uploadOptions:{}},emits:[`file-select`,`upload-start`,`validation-error`],setup(e,{emit:t}){let u=e,d=t,f=u.multiple?null:n(u.uploadOptions||{}),p=u.multiple?i(u.multiUploadOptions||{}):null,m=r({accept:u.accept,multiple:u.multiple,maxFileSize:u.maxFileSize,validator:u.validator,onFilesReceived:e=>{d(`file-select`,e),d(`upload-start`,e),u.multiple&&p?(p.addFiles(e),setTimeout(()=>p.startAll(),0)):!u.multiple&&f&&e[0]&&f.upload(e[0])},onValidationError:e=>{d(`validation-error`,e)}}),g=b(),_=()=>{u.disabled||g.value?.click()},y=o(()=>m.state.value.isDragging||m.state.value.isOver),E=o(()=>u.multiple&&p?p.state.value.isUploading:!u.multiple&&f?f.state.value.status===`uploading`:!1);return(t,n)=>(v(),c(`div`,{class:h([`upload-zone`,{"upload-zone--active":y.value,"upload-zone--disabled":e.disabled}]),onDragenter:n[1]||=t=>!e.disabled&&w(m).onDragEnter,onDragover:n[2]||=t=>!e.disabled&&w(m).onDragOver,onDragleave:n[3]||=t=>!e.disabled&&w(m).onDragLeave,onDrop:n[4]||=t=>!e.disabled&&w(m).onDrop,onClick:_,role:`button`,tabindex:e.disabled?-1:0,"aria-disabled":e.disabled,"aria-label":e.multiple?`Upload multiple files`:`Upload a file`,onKeydown:[T(_,[`enter`]),T(ee(_,[`prevent`]),[`space`])]},[S(t.$slots,`default`,{isDragging:w(m).state.value.isDragging,isOver:w(m).state.value.isOver,isUploading:E.value,errors:[...w(m).state.value.errors],openFilePicker:_},()=>[s(` Default slot content `),l(`div`,K,[w(m).state.value.isDragging?(v(),c(`p`,q,C(e.multiple?`Drop files here...`:`Drop file here...`),1)):(v(),c(`p`,J,C(e.multiple?`Drag files here or click to select`:`Drag a file here or click to select`),1)),w(m).state.value.errors.length>0?(v(),c(`div`,oe,[(v(!0),c(a,null,x(w(m).state.value.errors,(e,t)=>(v(),c(`p`,{key:t},C(e),1))),128))])):s(`v-if`,!0)])],!0),l(`input`,{ref_key:`fileInputRef`,ref:g,type:`file`,multiple:w(m).inputProps.value.multiple,accept:w(m).inputProps.value.accept,disabled:e.disabled,onChange:n[0]||=(...e)=>w(m).onInputChange&&w(m).onInputChange(...e),style:{display:`none`},"aria-hidden":`true`},null,40,se)],42,G))}}),[[`__scopeId`,`data-v-8b709bef`]]),le=d({__name:`Flow`,props:{flowId:{},storageId:{},outputNodeId:{},metadata:{}},emits:[`success`,`error`,`progress`,`flowComplete`,`abort`],setup(e,{expose:n,emit:r}){let i=e,a=r,o=t({flowConfig:{flowId:i.flowId,storageId:i.storageId,outputNodeId:i.outputNodeId,metadata:i.metadata},onSuccess:e=>a(`success`,e),onError:e=>a(`error`,e),onProgress:(e,t,n)=>a(`progress`,e,t,n),onFlowComplete:e=>a(`flowComplete`,e),onAbort:()=>a(`abort`)}),s={state:o.state,inputMetadata:o.inputMetadata,inputs:o.inputs,inputStates:o.inputStates,setInput:o.setInput,execute:o.execute,upload:o.upload,abort:o.abort,pause:o.pause,reset:o.reset,isUploading:o.isUploading,isUploadingFile:o.isUploadingFile,isProcessing:o.isProcessing,isDiscoveringInputs:o.isDiscoveringInputs};return y(`flowContext`,s),n(s),(e,t)=>S(e.$slots,`default`)}});const Y=`flowContext`,X=`flowInputContext`;function Z(){let e=p(Y);if(!e)throw Error(`useFlowContext must be used within a <Flow> component. Wrap your component tree with <Flow flowId="..." storageId="...">`);return e}function Q(){let e=p(X);if(!e)throw Error(`useFlowInputContext must be used within a <FlowInput> component. Wrap your component with <FlowInput nodeId="...">`);return e}var ue=d({inheritAttrs:!1,__name:`FlowCancel`,setup(e){let t=Z(),n=()=>{t.abort()};return(e,t)=>(v(),c(`button`,m({type:`button`,onClick:n},e.$attrs),[S(e.$slots,`default`,{},()=>[t[0]||=u(`Cancel`,-1)])],16))}});const de={key:0},fe={key:1},pe={key:2},me=[`multiple`,`accept`];var he=d({__name:`FlowDropZone`,props:{accept:{default:void 0},maxFileSize:{default:void 0}},setup(e){let t=e,n=Z(),i=b(null),a=r({onFilesReceived:e=>{let t=e[0];t&&n.upload(t)},accept:t.accept?t.accept.split(`,`).map(e=>e.trim()):void 0,maxFileSize:t.maxFileSize,multiple:!1}),u=()=>{i.value?.click()},d=o(()=>({isDragging:a.state.value.isDragging,isOver:a.state.value.isOver,progress:n.state.value.progress,status:n.state.value.status,dragDropState:a.state.value,openFilePicker:u,dragHandlers:{onDragenter:a.onDragEnter,onDragover:a.onDragOver,onDragleave:a.onDragLeave,onDrop:a.onDrop},inputProps:a.inputProps.value,onInputChange:a.onInputChange,inputRef:i}));return(e,t)=>S(e.$slots,`default`,g(f(d.value)),()=>[s(` Default content if no slot provided `),l(`div`,m(d.value.dragHandlers,{onClick:u,style:{border:d.value.isDragging?`2px dashed #3b82f6`:`2px dashed #d1d5db`,borderRadius:`0.5rem`,padding:`2rem`,textAlign:`center`,cursor:w(n).isUploading.value?`not-allowed`:`pointer`,opacity:w(n).isUploading.value?.5:1,backgroundColor:d.value.isOver?`#eff6ff`:`transparent`,transition:`all 0.2s ease`}}),[d.value.isDragging?(v(),c(`p`,de,`Drop file here...`)):w(n).isUploading.value?(v(),c(`p`,fe,`Uploading... `+C(d.value.progress)+`%`,1)):(v(),c(`p`,pe,`Drag and drop a file here, or click to select`))],16),l(`input`,{ref_key:`inputRef`,ref:i,type:`file`,multiple:d.value.inputProps.multiple,accept:d.value.inputProps.accept,onChange:t[0]||=(...e)=>d.value.onInputChange&&d.value.onInputChange(...e),style:{display:`none`}},null,40,me)])}});const ge={key:0,style:{padding:`1rem`,background:`#fef2f2`,border:`1px solid #fecaca`,"border-radius":`0.5rem`,color:`#dc2626`}},_e={style:{margin:`0.25rem 0 0`,"font-size":`0.875rem`}};var ve=d({__name:`FlowError`,setup(e){let t=Z(),n=o(()=>({error:t.state.value.error,hasError:t.state.value.status===`error`,message:t.state.value.error?.message??null,reset:t.reset}));return(e,t)=>S(e.$slots,`default`,g(f(n.value)),()=>[s(` Default error display `),n.value.hasError?(v(),c(`div`,ge,[t[1]||=l(`p`,{style:{margin:`0`,"font-weight":`600`}},`Error`,-1),l(`p`,_e,C(n.value.message),1),l(`button`,{type:`button`,onClick:t[0]||=(...e)=>n.value.reset&&n.value.reset(...e),style:{"margin-top":`0.75rem`,padding:`0.5rem 1rem`,background:`#dc2626`,color:`white`,border:`none`,"border-radius":`0.375rem`,cursor:`pointer`}},` Try Again `)])):s(`v-if`,!0)])}}),ye=d({__name:`FlowInput`,props:{nodeId:{}},setup(e){let t=e,n=Z(),r=o(()=>n.inputMetadata.value?.find(e=>e.nodeId===t.nodeId)),i=o(()=>n.inputs.value[t.nodeId]),l=o(()=>n.inputStates.value.get(t.nodeId)),u=e=>{n.setInput(t.nodeId,e)};y(X,{get nodeId(){return t.nodeId},get metadata(){return r.value??{nodeId:t.nodeId,nodeName:``,nodeDescription:``,required:!1}},get value(){return i.value},setValue:u,get state(){return l.value}});let d=o(()=>({nodeId:t.nodeId,metadata:r.value,value:i.value,setValue:u,state:l.value}));return(e,t)=>(v(),c(a,null,[s(` Only render if metadata is found `),r.value?S(e.$slots,`default`,g(m({key:0},d.value))):s(`v-if`,!0)],2112))}});const be={key:0},xe={key:1},Se={key:2},Ce=[`multiple`,`accept`];var we=d({__name:`FlowInputDropZone`,props:{accept:{default:void 0},maxFileSize:{default:void 0}},setup(e){let t=e=>e instanceof File,n=e,i=Q(),a=b(null),u=r({onFilesReceived:e=>{let t=e[0];t&&i.setValue(t)},accept:n.accept?n.accept.split(`,`).map(e=>e.trim()):void 0,maxFileSize:n.maxFileSize,multiple:!1}),d=()=>{a.value?.click()},p=o(()=>({isDragging:u.state.value.isDragging,isOver:u.state.value.isOver,value:i.value,progress:i.state?.progress??0,status:i.state?.status??`idle`,dragDropState:u.state.value,openFilePicker:d,dragHandlers:{onDragenter:u.onDragEnter,onDragover:u.onDragOver,onDragleave:u.onDragLeave,onDrop:u.onDrop},inputProps:u.inputProps.value,onInputChange:u.onInputChange,inputRef:a}));return(e,n)=>S(e.$slots,`default`,g(f(p.value)),()=>[s(` Default content if no slot provided `),l(`div`,m(p.value.dragHandlers,{onClick:d,style:{border:p.value.isDragging?`2px dashed #3b82f6`:`2px dashed #d1d5db`,borderRadius:`0.5rem`,padding:`2rem`,textAlign:`center`,cursor:`pointer`,backgroundColor:p.value.isOver?`#eff6ff`:`transparent`,transition:`all 0.2s ease`}}),[p.value.isDragging?(v(),c(`p`,be,`Drop file here...`)):t(p.value.value)?(v(),c(`p`,xe,` Selected: `+C(p.value.value.name),1)):(v(),c(`p`,Se,`Drag and drop a file here, or click to select`))],16),l(`input`,{ref_key:`inputRef`,ref:a,type:`file`,multiple:p.value.inputProps.multiple,accept:p.value.inputProps.accept,onChange:n[0]||=(...e)=>p.value.onInputChange&&p.value.onInputChange(...e),style:{display:`none`}},null,40,Ce)])}});const Te={key:0,style:{display:`flex`,"align-items":`center`,gap:`0.5rem`,padding:`0.5rem`,background:`#f3f4f6`,"border-radius":`0.375rem`}},Ee={style:{flex:`1`,"min-width":`0`}},De={key:0,style:{margin:`0`,"font-size":`0.875rem`,overflow:`hidden`,"text-overflow":`ellipsis`,"white-space":`nowrap`}},Oe={key:0,style:{color:`#6b7280`,"margin-left":`0.25rem`}},ke={key:1,style:{margin:`0`,"font-size":`0.875rem`,overflow:`hidden`,"text-overflow":`ellipsis`,"white-space":`nowrap`}};var Ae=d({__name:`FlowInputPreview`,setup(e){let t=Q(),n=o(()=>t.value instanceof File),r=o(()=>typeof t.value==`string`&&t.value.length>0),i=()=>{t.setValue(void 0)},a=o(()=>({value:t.value,isFile:n.value,isUrl:r.value,fileName:n.value?t.value.name:null,fileSize:n.value?t.value.size:null,clear:i}));return(e,t)=>S(e.$slots,`default`,g(f(a.value)),()=>[s(` Default preview content - only render for File or URL values `),a.value.isFile||a.value.isUrl?(v(),c(`div`,Te,[l(`div`,Ee,[a.value.isFile?(v(),c(`p`,De,[u(C(a.value.fileName)+` `,1),a.value.fileSize?(v(),c(`span`,Oe,` (`+C((a.value.fileSize/1024).toFixed(1))+` KB) `,1)):s(`v-if`,!0)])):a.value.isUrl?(v(),c(`p`,ke,C(a.value.value),1)):s(`v-if`,!0)]),l(`button`,{type:`button`,onClick:i,style:{padding:`0.25rem 0.5rem`,background:`transparent`,border:`none`,cursor:`pointer`,color:`#6b7280`},"aria-label":`Clear`},` × `)])):s(`v-if`,!0)])}});const je={key:0,style:{padding:`1rem`,"text-align":`center`}},Me={key:1,style:{padding:`1rem`,"text-align":`center`,color:`#6b7280`}};var Ne=d({__name:`FlowInputs`,setup(e){let t=Z(),n=o(()=>({inputs:t.inputMetadata.value??[],isLoading:t.isDiscoveringInputs.value}));return(e,t)=>S(e.$slots,`default`,g(f(n.value)),()=>[s(` Default loading state if no slot provided `),n.value.isLoading?(v(),c(`div`,je,` Discovering flow inputs... `)):n.value.inputs.length===0?(v(),c(`div`,Me,` No inputs found for this flow. `)):s(`v-if`,!0)])}});const Pe=[`value`,`placeholder`];var $=d({inheritAttrs:!1,__name:`FlowInputUrlField`,props:{placeholder:{default:`https://example.com/file`}},setup(e){let t=Q(),n=o(()=>typeof t.value==`string`),r=o(()=>n.value?t.value:``),i=e=>{let n=e.target;t.setValue(n.value)};return(t,n)=>(v(),c(`input`,m({type:`url`,value:r.value,onInput:i,placeholder:e.placeholder},t.$attrs),null,16,Pe))}});const Fe={key:0,style:{width:`100%`}},Ie={style:{display:`flex`,"justify-content":`space-between`,"margin-bottom":`0.25rem`,"font-size":`0.875rem`}},Le={style:{width:`100%`,height:`0.5rem`,background:`#e5e7eb`,"border-radius":`0.25rem`,overflow:`hidden`}},Re={key:0,style:{"margin-top":`0.25rem`,"font-size":`0.75rem`,color:`#6b7280`}};var ze=d({__name:`FlowProgress`,setup(e){let t=Z(),n=o(()=>({progress:t.state.value.progress,bytesUploaded:t.state.value.bytesUploaded,totalBytes:t.state.value.totalBytes,status:t.state.value.status}));return(e,t)=>S(e.$slots,`default`,g(f(n.value)),()=>[s(` Default progress display `),n.value.status===`uploading`||n.value.status===`processing`?(v(),c(`div`,Fe,[l(`div`,Ie,[l(`span`,null,C(n.value.status===`uploading`?`Uploading`:`Processing`),1),l(`span`,null,C(n.value.progress.toFixed(1))+`%`,1)]),l(`div`,Le,[l(`div`,{style:_({width:`${n.value.progress}%`,height:`100%`,background:`#3b82f6`,transition:`width 0.2s ease`})},null,4)]),n.value.totalBytes?(v(),c(`div`,Re,C((n.value.bytesUploaded/1024).toFixed(0))+` KB / `+C((n.value.totalBytes/1024).toFixed(0))+` KB `,1)):s(`v-if`,!0)])):s(`v-if`,!0)])}}),Be=d({inheritAttrs:!1,__name:`FlowReset`,setup(e){let t=Z(),n=()=>{t.reset()};return(e,t)=>(v(),c(`button`,m({type:`button`,onClick:n},e.$attrs),[S(e.$slots,`default`,{},()=>[t[0]||=u(`Reset`,-1)])],16))}});const Ve={key:0,style:{padding:`0.5rem`}},He={style:{margin:`0`,"font-size":`0.875rem`,color:`#6b7280`}},Ue={key:0,style:{margin:`0.25rem 0 0`,"font-size":`0.75rem`,color:`#9ca3af`}},We={key:1,style:{margin:`0.25rem 0 0`,"font-size":`0.75rem`,color:`#9ca3af`}};var Ge=d({__name:`FlowStatus`,setup(e){let t=Z(),n=o(()=>({status:t.state.value.status,currentNodeName:t.state.value.currentNodeName,currentNodeType:t.state.value.currentNodeType,error:t.state.value.error,jobId:t.state.value.jobId,flowStarted:t.state.value.flowStarted,flowOutputs:t.state.value.flowOutputs}));return(e,t)=>S(e.$slots,`default`,g(f(n.value)),()=>[s(` Default status display - only show when not idle `),n.value.status===`idle`?s(`v-if`,!0):(v(),c(`div`,Ve,[l(`p`,He,[t[0]||=u(` Status: `,-1),l(`strong`,null,C(n.value.status),1)]),n.value.currentNodeName?(v(),c(`p`,Ue,` Processing: `+C(n.value.currentNodeName),1)):s(`v-if`,!0),n.value.jobId?(v(),c(`p`,We,` Job ID: `+C(n.value.jobId),1)):s(`v-if`,!0)]))])}});const Ke=[`disabled`];var qe=d({inheritAttrs:!1,__name:`FlowSubmit`,setup(e){let t=Z(),n=()=>{t.execute()};return(e,r)=>(v(),c(`button`,m({type:`button`,onClick:n,disabled:w(t).isUploading.value},e.$attrs),[S(e.$slots,`default`,{},()=>[r[0]||=u(`Execute`,-1)])],16,Ke))}});export{le as _,$ as a,P as b,we as c,he as d,ue as f,Q as g,Z as h,ze as i,ye as l,X as m,Ge as n,Ne as o,Y as p,Be as r,Ae as s,qe as t,ve as u,ce as v,W as y};
2
- //# sourceMappingURL=components-BxBz_7tS.mjs.map