@uploadista/vue 0.0.20-beta.6 → 0.0.20-beta.7

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 (55) hide show
  1. package/dist/components/index.d.mts +3 -3
  2. package/dist/components/index.mjs +1 -1
  3. package/dist/components-Dk25ojCY.mjs +2 -0
  4. package/dist/components-Dk25ojCY.mjs.map +1 -0
  5. package/dist/composables/index.d.mts +1 -1
  6. package/dist/composables/index.mjs +1 -1
  7. package/dist/composables-BZ2c_WgI.mjs +2 -0
  8. package/dist/composables-BZ2c_WgI.mjs.map +1 -0
  9. package/dist/index-CDJUpsAf.d.mts +49 -0
  10. package/dist/index-CDJUpsAf.d.mts.map +1 -0
  11. package/dist/index-Ci1I0jRB.d.mts +787 -0
  12. package/dist/index-Ci1I0jRB.d.mts.map +1 -0
  13. package/dist/{index-Bemg9qdC.d.mts → index-qvkAz1kU.d.mts} +30 -30
  14. package/dist/index-qvkAz1kU.d.mts.map +1 -0
  15. package/dist/index.d.mts +4 -4
  16. package/dist/index.mjs +1 -1
  17. package/dist/providers/index.d.mts +2 -2
  18. package/dist/providers/index.mjs +1 -1
  19. package/dist/providers-DL9Qq-3z.mjs +2 -0
  20. package/dist/providers-DL9Qq-3z.mjs.map +1 -0
  21. package/dist/useUploadistaClient-WVuo8jYH.mjs +2 -0
  22. package/dist/useUploadistaClient-WVuo8jYH.mjs.map +1 -0
  23. package/package.json +5 -5
  24. package/src/components/flow/Flow.vue +127 -0
  25. package/src/components/flow/FlowCancel.vue +26 -0
  26. package/src/components/flow/FlowDropZone.vue +124 -0
  27. package/src/components/flow/FlowError.vue +47 -0
  28. package/src/components/flow/FlowInput.vue +86 -0
  29. package/src/components/flow/FlowInputDropZone.vue +129 -0
  30. package/src/components/flow/FlowInputPreview.vue +67 -0
  31. package/src/components/flow/FlowInputUrlField.vue +44 -0
  32. package/src/components/flow/FlowInputs.vue +34 -0
  33. package/src/components/flow/FlowProgress.vue +53 -0
  34. package/src/components/flow/FlowReset.vue +26 -0
  35. package/src/components/flow/FlowStatus.vue +55 -0
  36. package/src/components/flow/FlowSubmit.vue +27 -0
  37. package/src/components/flow/index.ts +101 -0
  38. package/src/components/flow/useFlowContext.ts +68 -0
  39. package/src/components/index.ts +3 -0
  40. package/src/providers/FlowManagerProvider.vue +4 -4
  41. package/src/providers/UploadistaProvider.vue +4 -1
  42. package/src/providers/index.ts +1 -0
  43. package/dist/components-Bhroc6MN.mjs +0 -2
  44. package/dist/components-Bhroc6MN.mjs.map +0 -1
  45. package/dist/composables-7rR8DrBp.mjs +0 -2
  46. package/dist/composables-7rR8DrBp.mjs.map +0 -1
  47. package/dist/index-Bemg9qdC.d.mts.map +0 -1
  48. package/dist/index-C9s0EqbD.d.mts +0 -183
  49. package/dist/index-C9s0EqbD.d.mts.map +0 -1
  50. package/dist/index-cDdde3bt.d.mts +0 -33
  51. package/dist/index-cDdde3bt.d.mts.map +0 -1
  52. package/dist/plugin-BC-8nlFO.mjs +0 -2
  53. package/dist/plugin-BC-8nlFO.mjs.map +0 -1
  54. package/dist/providers-kZkr_iMD.mjs +0 -2
  55. package/dist/providers-kZkr_iMD.mjs.map +0 -1
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ import { useFlowContext } from "./useFlowContext";
3
+
4
+ const flow = useFlowContext();
5
+
6
+ const handleClick = () => {
7
+ flow.execute();
8
+ };
9
+ </script>
10
+
11
+ <template>
12
+ <button
13
+ type="button"
14
+ @click="handleClick"
15
+ :disabled="flow.isUploading.value"
16
+ v-bind="$attrs"
17
+ >
18
+ <slot>Execute</slot>
19
+ </button>
20
+ </template>
21
+
22
+ <script lang="ts">
23
+ // Disable attribute inheritance so we can spread them manually
24
+ export default {
25
+ inheritAttrs: false,
26
+ };
27
+ </script>
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Vue 3 Flow Compound Components for Uploadista
3
+ *
4
+ * These components provide a composable, headless API for building flow upload interfaces.
5
+ * They use Vue's provide/inject for context and scoped slots for complete UI control.
6
+ *
7
+ * @example Simple Drop Zone
8
+ * ```vue
9
+ * <template>
10
+ * <Flow flowId="image-optimizer" storageId="s3" @success="handleSuccess">
11
+ * <FlowDropZone accept="image/*" v-slot="{ isDragging, progress, dragHandlers, inputProps, onInputChange, openFilePicker }">
12
+ * <div v-bind="dragHandlers" @click="openFilePicker">
13
+ * <input type="file" v-bind="inputProps" @change="onInputChange" style="display: none" />
14
+ * {{ isDragging ? 'Drop here' : 'Drag or click' }}
15
+ * <progress v-if="progress > 0" :value="progress" max="100" />
16
+ * </div>
17
+ * </FlowDropZone>
18
+ * </Flow>
19
+ * </template>
20
+ *
21
+ * <script setup>
22
+ * import { Flow, FlowDropZone } from '@uploadista/vue'
23
+ *
24
+ * const handleSuccess = (outputs) => {
25
+ * console.log('Upload complete:', outputs)
26
+ * }
27
+ * </script>
28
+ * ```
29
+ *
30
+ * @example Multi-Input Flow
31
+ * ```vue
32
+ * <template>
33
+ * <Flow flowId="video-processor" storageId="s3">
34
+ * <FlowInputs v-slot="{ inputs, isLoading }">
35
+ * <div v-if="isLoading">Loading...</div>
36
+ * <div v-else v-for="input in inputs" :key="input.nodeId">
37
+ * <FlowInput :nodeId="input.nodeId" v-slot="{ metadata }">
38
+ * <label>{{ metadata.nodeName }}</label>
39
+ * <FlowInputDropZone accept="video/*" v-slot="{ dragHandlers, openFilePicker }">
40
+ * <div v-bind="dragHandlers" @click="openFilePicker">
41
+ * Drop video here
42
+ * </div>
43
+ * </FlowInputDropZone>
44
+ * </FlowInput>
45
+ * </div>
46
+ * </FlowInputs>
47
+ * <FlowSubmit>Process</FlowSubmit>
48
+ * </Flow>
49
+ * </template>
50
+ * ```
51
+ */
52
+
53
+ // Root component
54
+ export { default as Flow } from "./Flow.vue";
55
+ export type { FlowProps, FlowContextValue } from "./Flow.vue";
56
+
57
+ // Context hooks
58
+ export {
59
+ useFlowContext,
60
+ useFlowInputContext,
61
+ FLOW_CONTEXT_KEY,
62
+ FLOW_INPUT_CONTEXT_KEY,
63
+ type FlowInputContextValue,
64
+ } from "./useFlowContext";
65
+
66
+ // Drop zone
67
+ export { default as FlowDropZone } from "./FlowDropZone.vue";
68
+ export type { FlowDropZoneProps, FlowDropZoneSlotProps } from "./FlowDropZone.vue";
69
+
70
+ // Input discovery
71
+ export { default as FlowInputs } from "./FlowInputs.vue";
72
+ export type { FlowInputsSlotProps } from "./FlowInputs.vue";
73
+
74
+ // Input context
75
+ export { default as FlowInput } from "./FlowInput.vue";
76
+ export type { FlowInputProps, FlowInputSlotProps } from "./FlowInput.vue";
77
+
78
+ // Input primitives
79
+ export { default as FlowInputDropZone } from "./FlowInputDropZone.vue";
80
+ export type { FlowInputDropZoneProps, FlowInputDropZoneSlotProps } from "./FlowInputDropZone.vue";
81
+
82
+ export { default as FlowInputUrlField } from "./FlowInputUrlField.vue";
83
+ export type { FlowInputUrlFieldProps } from "./FlowInputUrlField.vue";
84
+
85
+ export { default as FlowInputPreview } from "./FlowInputPreview.vue";
86
+ export type { FlowInputPreviewSlotProps } from "./FlowInputPreview.vue";
87
+
88
+ // Status primitives
89
+ export { default as FlowProgress } from "./FlowProgress.vue";
90
+ export type { FlowProgressSlotProps } from "./FlowProgress.vue";
91
+
92
+ export { default as FlowStatus } from "./FlowStatus.vue";
93
+ export type { FlowStatusSlotProps } from "./FlowStatus.vue";
94
+
95
+ export { default as FlowError } from "./FlowError.vue";
96
+ export type { FlowErrorSlotProps } from "./FlowError.vue";
97
+
98
+ // Action primitives
99
+ export { default as FlowSubmit } from "./FlowSubmit.vue";
100
+ export { default as FlowCancel } from "./FlowCancel.vue";
101
+ export { default as FlowReset } from "./FlowReset.vue";
@@ -0,0 +1,68 @@
1
+ import { inject } from "vue";
2
+ import type { FlowContextValue } from "./Flow.vue";
3
+
4
+ /**
5
+ * Injection key for the Flow context
6
+ */
7
+ export const FLOW_CONTEXT_KEY = "flowContext";
8
+
9
+ /**
10
+ * Injection key for the FlowInput context
11
+ */
12
+ export const FLOW_INPUT_CONTEXT_KEY = "flowInputContext";
13
+
14
+ /**
15
+ * Context value for a specific input node within a Flow.
16
+ */
17
+ export interface FlowInputContextValue {
18
+ /** Input node ID */
19
+ nodeId: string;
20
+ /** Input metadata from flow discovery */
21
+ metadata: {
22
+ nodeId: string;
23
+ nodeName: string;
24
+ nodeDescription: string;
25
+ inputTypeId?: string;
26
+ required: boolean;
27
+ };
28
+ /** Current value for this input */
29
+ value: unknown;
30
+ /** Set the value for this input */
31
+ setValue: (value: unknown) => void;
32
+ /** Per-input execution state (if available) */
33
+ state: {
34
+ status: string;
35
+ progress: number;
36
+ error: Error | null;
37
+ } | undefined;
38
+ }
39
+
40
+ /**
41
+ * Hook to access flow context from within a Flow component.
42
+ * @throws Error if used outside of a Flow component
43
+ */
44
+ export function useFlowContext(): FlowContextValue {
45
+ const context = inject<FlowContextValue>(FLOW_CONTEXT_KEY);
46
+ if (!context) {
47
+ throw new Error(
48
+ "useFlowContext must be used within a <Flow> component. " +
49
+ 'Wrap your component tree with <Flow flowId="..." storageId="...">',
50
+ );
51
+ }
52
+ return context;
53
+ }
54
+
55
+ /**
56
+ * Hook to access flow input context from within a FlowInput component.
57
+ * @throws Error if used outside of a FlowInput component
58
+ */
59
+ export function useFlowInputContext(): FlowInputContextValue {
60
+ const context = inject<FlowInputContextValue>(FLOW_INPUT_CONTEXT_KEY);
61
+ if (!context) {
62
+ throw new Error(
63
+ "useFlowInputContext must be used within a <FlowInput> component. " +
64
+ 'Wrap your component with <FlowInput nodeId="...">',
65
+ );
66
+ }
67
+ return context;
68
+ }
@@ -8,3 +8,6 @@
8
8
  export { default as FlowUploadList } from "./FlowUploadList.vue";
9
9
  export { default as UploadList } from "./UploadList.vue";
10
10
  export { default as UploadZone } from "./UploadZone.vue";
11
+
12
+ // Flow compound components
13
+ export * from "./flow";
@@ -12,7 +12,7 @@ import {
12
12
  import { EventType, type FlowEvent } from "@uploadista/core/flow";
13
13
  import { UploadEventType } from "@uploadista/core/types";
14
14
  import { onMounted, onBeforeUnmount, provide } from "vue";
15
- import { useUploadistaContext } from "../composables/useUploadistaContext";
15
+ import { useUploadistaClient } from "../composables/useUploadistaClient";
16
16
 
17
17
  /**
18
18
  * Type guard to check if an event is a flow event
@@ -52,7 +52,7 @@ interface FlowManagerContextValue {
52
52
  releaseManager: (flowId: string) => void;
53
53
  }
54
54
 
55
- const { client, subscribeToEvents } = useUploadistaContext();
55
+ const { client, subscribeToEvents } = useUploadistaClient();
56
56
  const managers = new Map<string, ManagerEntry>();
57
57
  let unsubscribe: (() => void) | null = null;
58
58
 
@@ -118,7 +118,7 @@ const getManager = (
118
118
  flowConfig: FlowUploadOptions["flowConfig"],
119
119
  internalOptions: unknown,
120
120
  ) => {
121
- return client.value.uploadWithFlow(input, flowConfig, internalOptions);
121
+ return client.uploadWithFlow(input, flowConfig, internalOptions);
122
122
  };
123
123
 
124
124
  const multiInputUploadFn = (
@@ -126,7 +126,7 @@ const getManager = (
126
126
  flowConfig: FlowUploadOptions["flowConfig"],
127
127
  internalOptions: unknown,
128
128
  ) => {
129
- return client.value.multiInputFlowUpload(inputs, flowConfig, internalOptions);
129
+ return client.multiInputFlowUpload(inputs, flowConfig, internalOptions);
130
130
  };
131
131
 
132
132
  const manager = new FlowManager<unknown>(flowUploadFn, callbacks, options, multiInputUploadFn);
@@ -8,6 +8,7 @@ import {
8
8
  UPLOADISTA_CLIENT_KEY,
9
9
  UPLOADISTA_EVENT_SUBSCRIBERS_KEY,
10
10
  } from "../composables/plugin";
11
+ import FlowManagerProvider from "./FlowManagerProvider.vue";
11
12
 
12
13
  const props = withDefaults(
13
14
  defineProps<{
@@ -58,5 +59,7 @@ onBeforeUnmount(() => {
58
59
  </script>
59
60
 
60
61
  <template>
61
- <slot />
62
+ <FlowManagerProvider>
63
+ <slot />
64
+ </FlowManagerProvider>
62
65
  </template>
@@ -1 +1,2 @@
1
+ export { default as FlowManagerProvider } from "./FlowManagerProvider.vue";
1
2
  export { default as UploadistaProvider } from "./UploadistaProvider.vue";
@@ -1,2 +0,0 @@
1
- import{m as e}from"./utils-B_r6xppE.mjs";import{n as t,o as n,r}from"./composables-7rR8DrBp.mjs";import{Fragment as i,computed as a,createCommentVNode as o,createElementBlock as s,createElementVNode as c,defineComponent as l,normalizeClass as u,normalizeStyle as d,openBlock as f,ref as p,renderList as m,renderSlot as h,toDisplayString as g,unref as _,withKeys as v,withModifiers as y}from"vue";var b=(e,t)=>{let n=e.__vccOpts||e;for(let[e,r]of t)n[e]=r;return n};const x={class:`flow-upload-list`},S={class:`flow-upload-list__item-header`},C={class:`flow-upload-list__item-icon`},w={class:`flow-upload-list__item-name`},T={class:`flow-upload-list__item-details`},E={class:`flow-upload-list__item-size`},D={key:0,class:`flow-upload-list__item-job`},O={key:0,class:`flow-upload-list__item-progress`},k={class:`flow-upload-list__progress-bar`},A={class:`flow-upload-list__progress-text`},j={key:1,class:`flow-upload-list__item-error`},M={key:2,class:`flow-upload-list__item-success`};var N=b(l({__name:`FlowUploadList`,props:{uploads:{},filter:{type:Function},sortBy:{type:Function}},setup(t){let n=t,r=a(()=>{let e=n.uploads;return n.filter&&(e=e.filter(n.filter)),n.sortBy&&(e=[...e].sort(n.sortBy)),e}),l=a(()=>({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`)})),p=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]}`},v=e=>{switch(e){case`pending`:return`⏳`;case`uploading`:return`📤`;case`success`:return`✅`;case`error`:return`❌`;case`aborted`:return`⏹️`;default:return`❓`}},y=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)=>(f(),s(`div`,x,[h(t.$slots,`default`,{items:r.value,itemsByStatus:l.value},()=>[o(` Default rendering: simple list of flow upload items `),(f(!0),s(i,null,m(r.value,(n,r)=>(f(),s(`div`,{key:n.id,class:u([`flow-upload-list__item`,`flow-upload-list__item--${n.status}`])},[h(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:p},()=>[o(` Default item template `),c(`div`,S,[c(`span`,C,g(v(n.status)),1),c(`span`,w,g(_(e)(n.file)?n.file.name:`File`),1),c(`span`,{class:`flow-upload-list__item-status`,style:d({color:y(n.status)})},g(n.status.toUpperCase()),5)]),c(`div`,T,[c(`span`,E,g(p(n.totalBytes)),1),n.jobId?(f(),s(`span`,D,` Job: `+g(n.jobId.slice(0,8))+`... `,1)):o(`v-if`,!0)]),n.status===`uploading`?(f(),s(`div`,O,[c(`div`,k,[c(`div`,{class:`flow-upload-list__progress-fill`,style:d({width:`${n.progress}%`})},null,4)]),c(`span`,A,g(n.progress)+`% • `+g(p(n.bytesUploaded))+` / `+g(p(n.totalBytes)),1)])):o(`v-if`,!0),n.status===`error`&&n.error?(f(),s(`div`,j,g(n.error.message),1)):o(`v-if`,!0),n.status===`success`?(f(),s(`div`,M,` Upload complete `)):o(`v-if`,!0)],!0)],2))),128))],!0)]))}}),[[`__scopeId`,`data-v-eabb787d`]]);const P={class:`upload-list`},F={class:`upload-list__item-header`},I={class:`upload-list__item-icon`},L={class:`upload-list__item-name`},R={key:0,class:`upload-list__item-size`},z={key:1,class:`upload-list__item-progress`},B={class:`upload-list__progress-bar`},V={class:`upload-list__progress-text`},H={key:2,class:`upload-list__item-error`};var U=b(l({__name:`UploadList`,props:{uploads:{},filter:{type:Function},sortBy:{type:Function}},setup(t){let n=t,r=a(()=>{let e=n.uploads;return n.filter&&(e=e.filter(n.filter)),n.sortBy&&(e=[...e].sort(n.sortBy)),e}),l=a(()=>({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`)})),p=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]}`},v=e=>{switch(e){case`idle`:return`⏳`;case`uploading`:return`📤`;case`success`:return`✅`;case`error`:return`❌`;case`aborted`:return`⏹️`;default:return`❓`}},y=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)=>(f(),s(`div`,P,[h(t.$slots,`default`,{items:r.value,itemsByStatus:l.value},()=>[o(` Default rendering: simple list of upload items `),(f(!0),s(i,null,m(r.value,(n,r)=>(f(),s(`div`,{key:n.id,class:u([`upload-list__item`,`upload-list__item--${n.state.status}`])},[h(t.$slots,`item`,{item:n,index:r,isUploading:n.state.status===`uploading`,isSuccess:n.state.status===`success`,isError:n.state.status===`error`,formatFileSize:p},()=>[o(` Default item template `),c(`div`,F,[c(`span`,I,g(v(n.state.status)),1),c(`span`,L,g(_(e)(n.file)?n.file.name:`File`),1),c(`span`,{class:`upload-list__item-status`,style:d({color:y(n.state.status)})},g(n.state.status.toUpperCase()),5)]),n.state.totalBytes?(f(),s(`div`,R,g(p(n.state.totalBytes)),1)):o(`v-if`,!0),n.state.status===`uploading`?(f(),s(`div`,z,[c(`div`,B,[c(`div`,{class:`upload-list__progress-fill`,style:d({width:`${n.state.progress}%`})},null,4)]),c(`span`,V,g(n.state.progress)+`%`,1)])):o(`v-if`,!0),n.state.status===`error`&&n.state.error?(f(),s(`div`,H,g(n.state.error.message),1)):o(`v-if`,!0)],!0)],2))),128))],!0)]))}}),[[`__scopeId`,`data-v-70c8fe1a`]]);const W=[`tabindex`,`aria-disabled`,`aria-label`,`onKeydown`],G={class:`upload-zone__content`},K={key:0},q={key:1},J={key:2,class:`upload-zone__errors`},Y=[`multiple`,`accept`,`disabled`];var X=b(l({__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:l}){let d=e,b=l,x=d.multiple?null:t(d.uploadOptions||{}),S=d.multiple?r(d.multiUploadOptions||{}):null,C=n({accept:d.accept,multiple:d.multiple,maxFileSize:d.maxFileSize,validator:d.validator,onFilesReceived:e=>{b(`file-select`,e),b(`upload-start`,e),d.multiple&&S?(S.addFiles(e),setTimeout(()=>S.startAll(),0)):!d.multiple&&x&&e[0]&&x.upload(e[0])},onValidationError:e=>{b(`validation-error`,e)}}),w=p(),T=()=>{d.disabled||w.value?.click()},E=a(()=>C.state.value.isDragging||C.state.value.isOver),D=a(()=>d.multiple&&S?S.state.value.isUploading:!d.multiple&&x?x.state.value.status===`uploading`:!1);return(t,n)=>(f(),s(`div`,{class:u([`upload-zone`,{"upload-zone--active":E.value,"upload-zone--disabled":e.disabled}]),onDragenter:n[1]||=t=>!e.disabled&&_(C).onDragEnter,onDragover:n[2]||=t=>!e.disabled&&_(C).onDragOver,onDragleave:n[3]||=t=>!e.disabled&&_(C).onDragLeave,onDrop:n[4]||=t=>!e.disabled&&_(C).onDrop,onClick:T,role:`button`,tabindex:e.disabled?-1:0,"aria-disabled":e.disabled,"aria-label":e.multiple?`Upload multiple files`:`Upload a file`,onKeydown:[v(T,[`enter`]),v(y(T,[`prevent`]),[`space`])]},[h(t.$slots,`default`,{isDragging:_(C).state.value.isDragging,isOver:_(C).state.value.isOver,isUploading:D.value,errors:[..._(C).state.value.errors],openFilePicker:T},()=>[o(` Default slot content `),c(`div`,G,[_(C).state.value.isDragging?(f(),s(`p`,K,g(e.multiple?`Drop files here...`:`Drop file here...`),1)):(f(),s(`p`,q,g(e.multiple?`Drag files here or click to select`:`Drag a file here or click to select`),1)),_(C).state.value.errors.length>0?(f(),s(`div`,J,[(f(!0),s(i,null,m(_(C).state.value.errors,(e,t)=>(f(),s(`p`,{key:t},g(e),1))),128))])):o(`v-if`,!0)])],!0),c(`input`,{ref_key:`fileInputRef`,ref:w,type:`file`,multiple:_(C).inputProps.value.multiple,accept:_(C).inputProps.value.accept,disabled:e.disabled,onChange:n[0]||=(...e)=>_(C).onInputChange&&_(C).onInputChange(...e),style:{display:`none`},"aria-hidden":`true`},null,40,Y)],42,W))}}),[[`__scopeId`,`data-v-8b709bef`]]);export{U as n,N as r,X as t};
2
- //# sourceMappingURL=components-Bhroc6MN.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"components-Bhroc6MN.mjs","names":[],"sources":["../src/components/FlowUploadList.vue","../src/components/UploadList.vue","../src/components/UploadZone.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * FlowUploadList - Display list of flow uploads with processing status\n *\n * Shows the progress and processing status of files being uploaded through flow pipelines.\n * Supports filtering, sorting, and status-based grouping. Provides flexible slot-based\n * customization for rendering each flow upload item.\n *\n * @component\n * @example\n * // Basic flow upload list\n * <FlowUploadList :uploads=\"flowUploads\" />\n *\n * @example\n * // Custom item rendering with flow status\n * <FlowUploadList :uploads=\"flowUploads\">\n * <template #item=\"{ item, isSuccess, isError, isUploading }\">\n * <div class=\"flow-item\">\n * <span>{{ item.filename }}</span>\n * <progress :value=\"item.uploadProgress\" max=\"100\"></progress>\n * <span v-if=\"isUploading\">Processing...</span>\n * <span v-else-if=\"isSuccess\">Complete</span>\n * <span v-else-if=\"isError\">Failed</span>\n * </div>\n * </template>\n * </FlowUploadList>\n *\n * @example\n * // With status grouping\n * <FlowUploadList :uploads=\"flowUploads\">\n * <template #default=\"{ itemsByStatus }\">\n * <div v-if=\"itemsByStatus.uploading.length\">\n * <h3>Uploading...</h3>\n * <div v-for=\"item of itemsByStatus.uploading\" :key=\"item.id\">\n * {{ item.filename }}\n * </div>\n * </div>\n * </template>\n * </FlowUploadList>\n */\nimport type {\n BrowserUploadInput,\n FlowUploadItem,\n} from \"@uploadista/client-browser\";\nimport { computed } from \"vue\";\nimport { isBrowserFile } from \"../utils\";\n\n/**\n * Props for the FlowUploadList component\n * @property {FlowUploadItem[]} uploads - Array of flow upload items to display\n * @property {Function} filter - Optional filter for which items to display\n * @property {Function} sortBy - Optional sorting function for items (a, b) => number\n */\nexport interface FlowUploadListProps {\n /**\n * Array of flow upload items to display\n */\n uploads: FlowUploadItem<BrowserUploadInput>[];\n\n /**\n * Optional filter for which items to display\n */\n filter?: (item: FlowUploadItem<BrowserUploadInput>) => boolean;\n\n /**\n * Optional sorting function for items\n */\n sortBy?: (\n a: FlowUploadItem<BrowserUploadInput>,\n b: FlowUploadItem<BrowserUploadInput>,\n ) => number;\n}\n\nconst props = defineProps<FlowUploadListProps>();\n\ndefineSlots<{\n item(props: {\n item: FlowUploadItem<BrowserUploadInput>;\n index: number;\n isPending: boolean;\n isUploading: boolean;\n isSuccess: boolean;\n isError: boolean;\n isAborted: boolean;\n formatFileSize: (bytes: number) => string;\n }): any;\n default?(props: {\n items: FlowUploadItem<BrowserUploadInput>[];\n itemsByStatus: {\n pending: FlowUploadItem<BrowserUploadInput>[];\n uploading: FlowUploadItem<BrowserUploadInput>[];\n success: FlowUploadItem<BrowserUploadInput>[];\n error: FlowUploadItem<BrowserUploadInput>[];\n aborted: FlowUploadItem<BrowserUploadInput>[];\n };\n }): any;\n}>();\n\n// Apply filtering and sorting\nconst filteredItems = computed(() => {\n let items = props.uploads;\n\n if (props.filter) {\n items = items.filter(props.filter);\n }\n\n if (props.sortBy) {\n items = [...items].sort(props.sortBy);\n }\n\n return items;\n});\n\n// Group items by status\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst itemsByStatus = computed(() => ({\n pending: filteredItems.value.filter((item) => item.status === \"pending\"),\n uploading: filteredItems.value.filter((item) => item.status === \"uploading\"),\n success: filteredItems.value.filter((item) => item.status === \"success\"),\n error: filteredItems.value.filter((item) => item.status === \"error\"),\n aborted: filteredItems.value.filter((item) => item.status === \"aborted\"),\n}));\n\n// Helper function to format file sizes\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst formatFileSize = (bytes: number): string => {\n if (bytes === 0) return \"0 Bytes\";\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;\n};\n\n// Helper function to get status icon\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst getStatusIcon = (status: string): string => {\n switch (status) {\n case \"pending\":\n return \"⏳\";\n case \"uploading\":\n return \"📤\";\n case \"success\":\n return \"✅\";\n case \"error\":\n return \"❌\";\n case \"aborted\":\n return \"⏹️\";\n default:\n return \"❓\";\n }\n};\n\n// Helper function to get status color\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst getStatusColor = (status: string): string => {\n switch (status) {\n case \"pending\":\n return \"#6c757d\";\n case \"uploading\":\n return \"#007bff\";\n case \"success\":\n return \"#28a745\";\n case \"error\":\n return \"#dc3545\";\n case \"aborted\":\n return \"#6c757d\";\n default:\n return \"#6c757d\";\n }\n};\n</script>\n\n<template>\n <div class=\"flow-upload-list\">\n <slot :items=\"filteredItems\" :items-by-status=\"itemsByStatus\">\n <!-- Default rendering: simple list of flow upload items -->\n <div\n v-for=\"(item, index) in filteredItems\"\n :key=\"item.id\"\n class=\"flow-upload-list__item\"\n :class=\"`flow-upload-list__item--${item.status}`\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n :is-pending=\"item.status === 'pending'\"\n :is-uploading=\"item.status === 'uploading'\"\n :is-success=\"item.status === 'success'\"\n :is-error=\"item.status === 'error'\"\n :is-aborted=\"item.status === 'aborted'\"\n :format-file-size=\"formatFileSize\"\n >\n <!-- Default item template -->\n <div class=\"flow-upload-list__item-header\">\n <span class=\"flow-upload-list__item-icon\">\n {{ getStatusIcon(item.status) }}\n </span>\n <span class=\"flow-upload-list__item-name\">\n {{ isBrowserFile(item.file) ? item.file.name : 'File' }}\n </span>\n <span\n class=\"flow-upload-list__item-status\"\n :style=\"{ color: getStatusColor(item.status) }\"\n >\n {{ item.status.toUpperCase() }}\n </span>\n </div>\n\n <div class=\"flow-upload-list__item-details\">\n <span class=\"flow-upload-list__item-size\">\n {{ formatFileSize(item.totalBytes) }}\n </span>\n <span v-if=\"item.jobId\" class=\"flow-upload-list__item-job\">\n Job: {{ item.jobId.slice(0, 8) }}...\n </span>\n </div>\n\n <div v-if=\"item.status === 'uploading'\" class=\"flow-upload-list__item-progress\">\n <div class=\"flow-upload-list__progress-bar\">\n <div\n class=\"flow-upload-list__progress-fill\"\n :style=\"{ width: `${item.progress}%` }\"\n />\n </div>\n <span class=\"flow-upload-list__progress-text\">\n {{ item.progress }}% • {{ formatFileSize(item.bytesUploaded) }} / {{ formatFileSize(item.totalBytes) }}\n </span>\n </div>\n\n <div v-if=\"item.status === 'error' && item.error\" class=\"flow-upload-list__item-error\">\n {{ item.error.message }}\n </div>\n\n <div v-if=\"item.status === 'success'\" class=\"flow-upload-list__item-success\">\n Upload complete\n </div>\n </slot>\n </div>\n </slot>\n </div>\n</template>\n\n<style scoped>\n.flow-upload-list {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.flow-upload-list__item {\n padding: 0.75rem;\n border: 1px solid #e0e0e0;\n border-radius: 0.375rem;\n background-color: #fff;\n}\n\n.flow-upload-list__item-header {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-bottom: 0.5rem;\n}\n\n.flow-upload-list__item-icon {\n font-size: 1rem;\n}\n\n.flow-upload-list__item-name {\n flex: 1;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.flow-upload-list__item-status {\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.flow-upload-list__item-details {\n display: flex;\n gap: 1rem;\n font-size: 0.75rem;\n color: #666;\n margin-bottom: 0.5rem;\n}\n\n.flow-upload-list__item-size {\n font-weight: 500;\n}\n\n.flow-upload-list__item-job {\n color: #999;\n font-family: monospace;\n}\n\n.flow-upload-list__item-progress {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.flow-upload-list__progress-bar {\n width: 100%;\n height: 0.375rem;\n background-color: #e0e0e0;\n border-radius: 0.1875rem;\n overflow: hidden;\n}\n\n.flow-upload-list__progress-fill {\n height: 100%;\n background-color: #007bff;\n transition: width 0.2s ease;\n}\n\n.flow-upload-list__progress-text {\n font-size: 0.75rem;\n color: #666;\n}\n\n.flow-upload-list__item-error {\n margin-top: 0.5rem;\n padding: 0.5rem;\n background-color: #f8d7da;\n color: #721c24;\n font-size: 0.75rem;\n border-radius: 0.25rem;\n}\n\n.flow-upload-list__item-success {\n margin-top: 0.5rem;\n padding: 0.5rem;\n background-color: #d4edda;\n color: #155724;\n font-size: 0.75rem;\n border-radius: 0.25rem;\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * UploadList - Display a list of uploads with customizable status grouping and sorting\n *\n * Shows the progress and status of multiple file uploads. Supports filtering, sorting,\n * and status-based grouping. Provides flexible slot-based customization for rendering each item.\n *\n * @component\n * @example\n * // Basic upload list\n * <UploadList :uploads=\"uploads\" />\n *\n * @example\n * // Custom item rendering with status indicators\n * <UploadList :uploads=\"uploads\">\n * <template #item=\"{ item, isSuccess, isError }\">\n * <div class=\"upload-item\">\n * <span>{{ item.filename }}</span>\n * <progress :value=\"item.progress\" max=\"100\"></progress>\n * <span :class=\"{ success: isSuccess, error: isError }\">\n * {{ item.state.status }}\n * </span>\n * </div>\n * </template>\n * </UploadList>\n *\n * @example\n * // With filtering and sorting\n * <UploadList\n * :uploads=\"uploads\"\n * :filter=\"item => item.state.status === 'success'\"\n * :sort-by=\"(a, b) => a.uploadedAt - b.uploadedAt\"\n * />\n */\nimport { computed } from \"vue\";\nimport type { UploadItem } from \"../composables\";\nimport { isBrowserFile } from \"../utils\";\n\n/**\n * Props for the UploadList component\n * @property {UploadItem[]} uploads - Array of upload items to display\n * @property {Function} filter - Optional filter for which items to display\n * @property {Function} sortBy - Optional sorting function for items (a, b) => number\n */\nexport interface UploadListProps {\n /**\n * Array of upload items to display\n */\n uploads: UploadItem[];\n\n /**\n * Optional filter for which items to display\n */\n filter?: (item: UploadItem) => boolean;\n\n /**\n * Optional sorting function for items\n */\n sortBy?: (a: UploadItem, b: UploadItem) => number;\n}\n\nconst props = defineProps<UploadListProps>();\n\ndefineSlots<{\n item(props: {\n item: UploadItem;\n index: number;\n isUploading: boolean;\n isSuccess: boolean;\n isError: boolean;\n formatFileSize: (bytes: number) => string;\n }): any;\n default?(props: {\n items: UploadItem[];\n itemsByStatus: {\n idle: UploadItem[];\n uploading: UploadItem[];\n success: UploadItem[];\n error: UploadItem[];\n aborted: UploadItem[];\n };\n }): any;\n}>();\n\n// Apply filtering and sorting\nconst filteredItems = computed(() => {\n let items = props.uploads;\n\n if (props.filter) {\n items = items.filter(props.filter);\n }\n\n if (props.sortBy) {\n items = [...items].sort(props.sortBy);\n }\n\n return items;\n});\n\n// Group items by status\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst itemsByStatus = computed(() => ({\n idle: filteredItems.value.filter((item) => item.state.status === \"idle\"),\n uploading: filteredItems.value.filter(\n (item) => item.state.status === \"uploading\",\n ),\n success: filteredItems.value.filter(\n (item) => item.state.status === \"success\",\n ),\n error: filteredItems.value.filter((item) => item.state.status === \"error\"),\n aborted: filteredItems.value.filter(\n (item) => item.state.status === \"aborted\",\n ),\n}));\n\n// Helper function to format file sizes\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst formatFileSize = (bytes: number): string => {\n if (bytes === 0) return \"0 Bytes\";\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;\n};\n\n// Helper function to get status icon\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst getStatusIcon = (status: string): string => {\n switch (status) {\n case \"idle\":\n return \"⏳\";\n case \"uploading\":\n return \"📤\";\n case \"success\":\n return \"✅\";\n case \"error\":\n return \"❌\";\n case \"aborted\":\n return \"⏹️\";\n default:\n return \"❓\";\n }\n};\n\n// Helper function to get status color\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst getStatusColor = (status: string): string => {\n switch (status) {\n case \"idle\":\n return \"#6c757d\";\n case \"uploading\":\n return \"#007bff\";\n case \"success\":\n return \"#28a745\";\n case \"error\":\n return \"#dc3545\";\n case \"aborted\":\n return \"#6c757d\";\n default:\n return \"#6c757d\";\n }\n};\n</script>\n\n<template>\n <div class=\"upload-list\">\n <slot :items=\"filteredItems\" :items-by-status=\"itemsByStatus\">\n <!-- Default rendering: simple list of upload items -->\n <div\n v-for=\"(item, index) in filteredItems\"\n :key=\"item.id\"\n class=\"upload-list__item\"\n :class=\"`upload-list__item--${item.state.status}`\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n :is-uploading=\"item.state.status === 'uploading'\"\n :is-success=\"item.state.status === 'success'\"\n :is-error=\"item.state.status === 'error'\"\n :format-file-size=\"formatFileSize\"\n >\n <!-- Default item template -->\n <div class=\"upload-list__item-header\">\n <span class=\"upload-list__item-icon\">\n {{ getStatusIcon(item.state.status) }}\n </span>\n <span class=\"upload-list__item-name\">\n {{ isBrowserFile(item.file) ? item.file.name : 'File' }}\n </span>\n <span\n class=\"upload-list__item-status\"\n :style=\"{ color: getStatusColor(item.state.status) }\"\n >\n {{ item.state.status.toUpperCase() }}\n </span>\n </div>\n\n <div v-if=\"item.state.totalBytes\" class=\"upload-list__item-size\">\n {{ formatFileSize(item.state.totalBytes) }}\n </div>\n\n <div v-if=\"item.state.status === 'uploading'\" class=\"upload-list__item-progress\">\n <div class=\"upload-list__progress-bar\">\n <div\n class=\"upload-list__progress-fill\"\n :style=\"{ width: `${item.state.progress}%` }\"\n />\n </div>\n <span class=\"upload-list__progress-text\">{{ item.state.progress }}%</span>\n </div>\n\n <div v-if=\"item.state.status === 'error' && item.state.error\" class=\"upload-list__item-error\">\n {{ item.state.error.message }}\n </div>\n </slot>\n </div>\n </slot>\n </div>\n</template>\n\n<style scoped>\n.upload-list {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.upload-list__item {\n padding: 0.75rem;\n border: 1px solid #e0e0e0;\n border-radius: 0.375rem;\n background-color: #fff;\n}\n\n.upload-list__item-header {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-bottom: 0.5rem;\n}\n\n.upload-list__item-icon {\n font-size: 1rem;\n}\n\n.upload-list__item-name {\n flex: 1;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.upload-list__item-status {\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.upload-list__item-size {\n font-size: 0.75rem;\n color: #666;\n margin-bottom: 0.5rem;\n}\n\n.upload-list__item-progress {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.upload-list__progress-bar {\n flex: 1;\n height: 0.375rem;\n background-color: #e0e0e0;\n border-radius: 0.1875rem;\n overflow: hidden;\n}\n\n.upload-list__progress-fill {\n height: 100%;\n background-color: #007bff;\n transition: width 0.2s ease;\n}\n\n.upload-list__progress-text {\n font-size: 0.75rem;\n color: #666;\n min-width: 3rem;\n text-align: right;\n}\n\n.upload-list__item-error {\n margin-top: 0.5rem;\n padding: 0.5rem;\n background-color: #f8d7da;\n color: #721c24;\n font-size: 0.75rem;\n border-radius: 0.25rem;\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * UploadZone - A flexible file upload component with drag-and-drop support\n *\n * Provides a drag-and-drop zone and file picker for uploading files. Supports both single\n * and multiple file uploads with validation. Emits events for file selection and upload events.\n *\n * @component\n * @example\n * // Basic single file upload\n * <UploadZone @file-select=\"handleFiles\" />\n *\n * @example\n * // Multiple files with validation\n * <UploadZone\n * multiple\n * accept={[\"image/*\"]}\n * :max-file-size=\"10 * 1024 * 1024\"\n * @file-select=\"handleFiles\"\n * @validation-error=\"handleErrors\"\n * >\n * <template #default=\"{ isDragging, errors, openFilePicker }\">\n * <div :class=\"{ dragging: isDragging }\" @click=\"openFilePicker\">\n * <p>{{ isDragging ? 'Drop files here' : 'Click or drag files here' }}</p>\n * <div v-if=\"errors.length\">\n * <p v-for=\"error in errors\" :key=\"error\">{{ error }}</p>\n * </div>\n * </div>\n * </template>\n * </UploadZone>\n *\n * @emits file-select - When files are selected/dropped\n * @emits upload-start - When upload begins\n * @emits validation-error - When validation fails\n */\nimport type { UploadOptions } from \"@uploadista/client-browser\";\nimport { computed, ref } from \"vue\";\nimport type { MultiUploadOptions } from \"../composables\";\nimport { useDragDrop, useMultiUpload, useUpload } from \"../composables\";\n\n/**\n * Props for the UploadZone component\n * @property {string[]} accept - Accepted file types (MIME types or file extensions)\n * @property {boolean} multiple - Whether to allow multiple files (default: true)\n * @property {boolean} disabled - Whether the upload zone is disabled (default: false)\n * @property {number} maxFileSize - Maximum file size in bytes\n * @property {Function} validator - Custom validation function for files\n * @property {MultiUploadOptions} multiUploadOptions - Multi-upload options (only used when multiple=true)\n * @property {UploadOptions} uploadOptions - Single upload options (only used when multiple=false)\n */\nexport interface UploadZoneProps {\n /**\n * Accepted file types (MIME types or file extensions)\n */\n accept?: string[];\n\n /**\n * Whether to allow multiple files\n */\n multiple?: boolean;\n\n /**\n * Whether the upload zone is disabled\n */\n disabled?: boolean;\n\n /**\n * Maximum file size in bytes\n */\n maxFileSize?: number;\n\n /**\n * Custom validation function for files\n */\n validator?: (files: File[]) => string[] | null;\n\n /**\n * Multi-upload options (only used when multiple=true)\n */\n multiUploadOptions?: MultiUploadOptions;\n\n /**\n * Single upload options (only used when multiple=false)\n */\n uploadOptions?: UploadOptions;\n}\n\nconst props = withDefaults(defineProps<UploadZoneProps>(), {\n multiple: true,\n disabled: false,\n});\n\nconst emit = defineEmits<{\n \"file-select\": [files: File[]];\n \"upload-start\": [files: File[]];\n \"validation-error\": [errors: string[]];\n}>();\n\ndefineSlots<{\n // biome-ignore lint/suspicious/noExplicitAny: Vue slot definition requires any\n default(props: {\n isDragging: boolean;\n isOver: boolean;\n isUploading: boolean;\n errors: string[];\n openFilePicker: () => void;\n }): any;\n}>();\n\n// Initialize upload composables\nconst singleUpload = props.multiple\n ? null\n : useUpload(props.uploadOptions || {});\nconst multiUpload = props.multiple\n ? useMultiUpload(props.multiUploadOptions || {})\n : null;\n\n// Handle files received from drag-drop or file picker\nconst handleFilesReceived = (files: File[]) => {\n emit(\"file-select\", files);\n emit(\"upload-start\", files);\n\n if (props.multiple && multiUpload) {\n multiUpload.addFiles(files);\n setTimeout(() => multiUpload.startAll(), 0);\n } else if (!props.multiple && singleUpload && files[0]) {\n singleUpload.upload(files[0]);\n }\n};\n\n// Handle validation errors\nconst handleValidationError = (errors: string[]) => {\n emit(\"validation-error\", errors);\n};\n\n// Initialize drag-drop\nconst dragDrop = useDragDrop({\n accept: props.accept,\n multiple: props.multiple,\n maxFileSize: props.maxFileSize,\n validator: props.validator,\n onFilesReceived: handleFilesReceived,\n onValidationError: handleValidationError,\n});\n\n// File input ref\nconst fileInputRef = ref<HTMLInputElement>();\n\n// Open file picker\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst openFilePicker = () => {\n if (!props.disabled) {\n fileInputRef.value?.click();\n }\n};\n\n// Computed states\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst isActive = computed(\n () => dragDrop.state.value.isDragging || dragDrop.state.value.isOver,\n);\n\n// biome-ignore lint/correctness/noUnusedVariables: Used in slot templates\nconst isUploading = computed(() => {\n if (props.multiple && multiUpload) {\n return multiUpload.state.value.isUploading;\n } else if (!props.multiple && singleUpload) {\n return singleUpload.state.value.status === \"uploading\";\n }\n return false;\n});\n</script>\n\n<template>\n <div\n class=\"upload-zone\"\n :class=\"{ 'upload-zone--active': isActive, 'upload-zone--disabled': disabled }\"\n @dragenter=\"!disabled && dragDrop.onDragEnter\"\n @dragover=\"!disabled && dragDrop.onDragOver\"\n @dragleave=\"!disabled && dragDrop.onDragLeave\"\n @drop=\"!disabled && dragDrop.onDrop\"\n @click=\"openFilePicker\"\n role=\"button\"\n :tabindex=\"disabled ? -1 : 0\"\n :aria-disabled=\"disabled\"\n :aria-label=\"multiple ? 'Upload multiple files' : 'Upload a file'\"\n @keydown.enter=\"openFilePicker\"\n @keydown.space.prevent=\"openFilePicker\"\n >\n <slot\n :is-dragging=\"dragDrop.state.value.isDragging\"\n :is-over=\"dragDrop.state.value.isOver\"\n :is-uploading=\"isUploading\"\n :errors=\"[...dragDrop.state.value.errors]\"\n :open-file-picker=\"openFilePicker\"\n >\n <!-- Default slot content -->\n <div class=\"upload-zone__content\">\n <p v-if=\"dragDrop.state.value.isDragging\">\n {{ multiple ? 'Drop files here...' : 'Drop file here...' }}\n </p>\n <p v-else>\n {{ multiple ? 'Drag files here or click to select' : 'Drag a file here or click to select' }}\n </p>\n\n <div v-if=\"dragDrop.state.value.errors.length > 0\" class=\"upload-zone__errors\">\n <p v-for=\"(error, index) in dragDrop.state.value.errors\" :key=\"index\">\n {{ error }}\n </p>\n </div>\n </div>\n </slot>\n\n <input\n ref=\"fileInputRef\"\n type=\"file\"\n :multiple=\"dragDrop.inputProps.value.multiple\"\n :accept=\"dragDrop.inputProps.value.accept\"\n :disabled=\"disabled\"\n @change=\"dragDrop.onInputChange\"\n style=\"display: none\"\n aria-hidden=\"true\"\n />\n </div>\n</template>\n\n<style scoped>\n.upload-zone {\n cursor: pointer;\n user-select: none;\n}\n\n.upload-zone--disabled {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.upload-zone__content {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n}\n\n.upload-zone__errors {\n margin-top: 0.5rem;\n color: #dc3545;\n font-size: 0.875rem;\n}\n\n.upload-zone__errors p {\n margin: 0.25rem 0;\n}\n</style>\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{n as e,t}from"./plugin-BC-8nlFO.mjs";import{computed as n,inject as r,onBeforeUnmount as i,onMounted as a,onUnmounted as o,readonly as s,ref as c,shallowReadonly as l}from"vue";import{EventType as u}from"@uploadista/core/flow";import{UploadEventType as d}from"@uploadista/core/types";import{UploadManager as f}from"@uploadista/client-core";function p(e){if(!(`eventType`in e))return!1;let t=e;return t.eventType===u.JobStart||t.eventType===u.JobEnd||t.eventType===u.FlowStart||t.eventType===u.FlowEnd||t.eventType===u.FlowError||t.eventType===u.FlowPause||t.eventType===u.FlowCancel||t.eventType===u.NodeStart||t.eventType===u.NodeEnd||t.eventType===u.NodePause||t.eventType===u.NodeResume||t.eventType===u.NodeError||t.eventType===u.NodeStream||t.eventType===u.NodeResponse}function m(e){if(!(`type`in e))return!1;let t=e;return t.type===d.UPLOAD_STARTED||t.type===d.UPLOAD_PROGRESS||t.type===d.UPLOAD_COMPLETE||t.type===d.UPLOAD_FAILED||t.type===d.UPLOAD_VALIDATION_SUCCESS||t.type===d.UPLOAD_VALIDATION_FAILED||t.type===d.UPLOAD_VALIDATION_WARNING}function h(){let n=r(t);if(!n)throw Error(`useUploadistaClient must be used within a component tree that has the Uploadista plugin or provider installed. Make sure to either use app.use(createUploadistaPlugin({ ... })) in your main app file, or wrap your component tree with <UploadistaProvider>.`);let i=r(e);return{client:n,subscribeToEvents:e=>i?(i.value.add(e),()=>{i.value.delete(e)}):(console.warn(`subscribeToEvents called but no event subscribers provided. Events will not be dispatched. Make sure to use UploadistaProvider or createUploadistaPlugin with proper configuration.`),()=>{})}}function g(e){let{subscribeToEvents:t}=h(),n=null;a(()=>{n=t(e)}),i(()=>{n?.()})}function _(e){let{subscribeToEvents:t}=h(),n=null;a(()=>{n=t(t=>{if(p(t))switch(t.eventType){case u.JobStart:e.onJobStart?.(t);break;case u.JobEnd:e.onJobEnd?.(t);break;case u.FlowStart:e.onFlowStart?.(t);break;case u.FlowEnd:e.onFlowEnd?.(t);break;case u.FlowError:e.onFlowError?.(t);break;case u.FlowPause:e.onFlowPause?.(t);break;case u.FlowCancel:e.onFlowCancel?.(t);break;case u.NodeStart:e.onNodeStart?.(t);break;case u.NodeEnd:e.onNodeEnd?.(t);break;case u.NodePause:e.onNodePause?.(t);break;case u.NodeResume:e.onNodeResume?.(t);break;case u.NodeError:e.onNodeError?.(t);break}})}),i(()=>{n?.()})}function v(e){let{subscribeToEvents:t}=h(),n=null;a(()=>{n=t(t=>{if(!m(t))return;let n=`flow`in t?t.flow:void 0;switch(t.type){case d.UPLOAD_STARTED:e.onUploadStarted?.({...t.data,flow:n});break;case d.UPLOAD_PROGRESS:e.onUploadProgress?.({...t.data,flow:n});break;case d.UPLOAD_COMPLETE:e.onUploadComplete?.({...t.data,flow:n});break;case d.UPLOAD_FAILED:e.onUploadFailed?.({...t.data,flow:n});break;case d.UPLOAD_VALIDATION_SUCCESS:e.onUploadValidationSuccess?.({...t.data,flow:n});break;case d.UPLOAD_VALIDATION_FAILED:e.onUploadValidationFailed?.({...t.data,flow:n});break;case d.UPLOAD_VALIDATION_WARNING:e.onUploadValidationWarning?.({...t.data,flow:n});break}})}),i(()=>{n?.()})}const y={isDragging:!1,isOver:!1,isValid:!0,errors:[]};function b(e={}){let{accept:t,maxFiles:r,maxFileSize:i,multiple:a=!0,validator:o,onFilesReceived:l,onValidationError:u,onDragStateChange:d}=e,f=c({...y}),p=c(0),m=e=>{f.value={...f.value,...e}},h=e=>{let n=[];r&&e.length>r&&n.push(`Maximum ${r} files allowed. You selected ${e.length} files.`);for(let r of e){if(i&&r.size>i){let e=(i/(1024*1024)).toFixed(1),t=(r.size/(1024*1024)).toFixed(1);n.push(`File "${r.name}" (${t}MB) exceeds maximum size of ${e}MB.`)}t&&t.length>0&&(t.some(e=>{if(e.startsWith(`.`))return r.name.toLowerCase().endsWith(e.toLowerCase());if(e.endsWith(`/*`)){let t=e.slice(0,-2);return r.type.startsWith(t)}else return r.type===e})||n.push(`File "${r.name}" type "${r.type}" is not accepted. Accepted types: ${t.join(`, `)}.`))}if(o){let t=o(e);t&&n.push(...t)}return n},g=e=>{let t=Array.from(e),n=h(t);n.length>0?(m({errors:n,isValid:!1}),u?.(n)):(m({errors:[],isValid:!0}),l?.(t))},_=e=>{let t=[];if(e.items)for(let n=0;n<e.items.length;n++){let r=e.items[n];if(r&&r.kind===`file`){let e=r.getAsFile();e&&t.push(e)}}else for(let n=0;n<e.files.length;n++){let r=e.files[n];r&&t.push(r)}return t},v=e=>{e.preventDefault(),e.stopPropagation(),p.value++,p.value===1&&(m({isDragging:!0,isOver:!0}),d?.(!0))},b=e=>{e.preventDefault(),e.stopPropagation(),e.dataTransfer&&(e.dataTransfer.dropEffect=`copy`)},x=e=>{e.preventDefault(),e.stopPropagation(),p.value--,p.value===0&&(m({isDragging:!1,isOver:!1,errors:[]}),d?.(!1))},S=e=>{if(e.preventDefault(),e.stopPropagation(),p.value=0,m({isDragging:!1,isOver:!1}),d?.(!1),e.dataTransfer){let t=_(e.dataTransfer);t.length>0&&g(t)}},C=e=>{let t=e.target;t.files&&t.files.length>0&&g(Array.from(t.files)),t.value=``},w=()=>{f.value={...y},p.value=0},T=n(()=>({type:`file`,multiple:a,accept:t?.join(`, `)}));return{state:s(f),onDragEnter:v,onDragOver:b,onDragLeave:x,onDrop:S,onInputChange:C,inputProps:T,processFiles:g,reset:w}}function x(){let e=r(`flowManagerContext`);if(!e)throw Error(`useFlowManagerContext must be used within a FlowManagerProvider. Make sure to wrap your component tree with <FlowManagerProvider>.`);return e}const S={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,jobId:null,flowStarted:!1,currentNodeName:null,currentNodeType:null,flowOutputs:null};function C(e){let{client:t}=h(),{getManager:r,releaseManager:i}=x(),u=c(S),d=c(null),f=c(!1),p=c({}),m=c(new Map),g=null,_=c(e),v=null;a(async()=>{f.value=!0;try{let{flow:n}=await t.getFlow(e.flowConfig.flowId);d.value=n.nodes.filter(e=>e.type===`input`).map(e=>({nodeId:e.id,nodeName:e.name,nodeDescription:e.description,inputTypeId:e.inputTypeId,required:!0}))}catch(e){console.error(`Failed to discover flow inputs:`,e)}finally{f.value=!1}g=r(e.flowConfig.flowId,{onStateChange:e=>{u.value=e},onProgress:(e,t,n)=>{_.value.onProgress?.(e,t,n)},onChunkComplete:(e,t,n)=>{_.value.onChunkComplete?.(e,t,n)},onFlowComplete:e=>{_.value.onFlowComplete?.(e)},onSuccess:e=>{_.value.onSuccess?.(e)},onError:e=>{_.value.onError?.(e)},onAbort:()=>{_.value.onAbort?.()}},e),v=setInterval(()=>{if(g){let e=g.getInputStates();e.size>0&&(m.value=new Map(e))}},100)}),o(()=>{v&&=(clearInterval(v),null),g&&=(i(e.flowConfig.flowId),null)});let y=(e,t)=>{p.value={...p.value,[e]:t}},b=async()=>{if(!g)throw Error(`FlowManager not initialized`);if(Object.keys(p.value).length===0)throw Error(`No inputs provided. Use setInput() to provide inputs before calling execute()`);await g.executeFlow(p.value)},C=async e=>{if(!g)throw Error(`FlowManager not initialized`);if(d.value&&d.value.length>0){let t=d.value[0];if(!t)throw Error(`No input nodes found`);p.value={[t.nodeId]:e},await g.executeFlow({[t.nodeId]:e})}else await g.upload(e)},w=()=>{g?.abort()},T=()=>{g?.pause()},E=()=>{g?.reset(),p.value={},m.value=new Map},D=n(()=>u.value.status===`uploading`||u.value.status===`processing`),O=n(()=>u.value.status===`uploading`),k=n(()=>u.value.status===`processing`);return{state:l(u),inputMetadata:l(d),inputStates:l(m),inputs:l(p),setInput:y,execute:b,upload:C,abort:w,pause:T,reset:E,isUploading:s(D),isUploadingFile:s(O),isProcessing:s(k),isDiscoveringInputs:s(f)}}function w(e){let t=h(),r=c([]),i=c(new Map),a=c([]),o=c(0),l=e.maxConcurrent??3,u=e=>{if(e.length===0)return 0;let t=e.reduce((e,t)=>e+t.progress,0);return Math.round(t/e.length)},d=async()=>{if(o.value>=l||a.value.length===0)return;let n=a.value.shift();if(!n)return;let s=r.value.find(e=>e.id===n);if(!s||s.status!==`pending`){d();return}o.value++,r.value=r.value.map(e=>e.id===n?{...e,status:`uploading`}:e);try{let{abort:a,jobId:c}=await t.client.uploadWithFlow(s.file,e.flowConfig,{onJobStart:e=>{r.value=r.value.map(t=>t.id===n?{...t,jobId:e}:t)},onProgress:(t,i,a)=>{let o=a?Math.round(i/a*100):0;r.value=r.value.map(t=>{if(t.id===n){let n={...t,progress:o,bytesUploaded:i,totalBytes:a||0};return e.onItemProgress?.(n),n}return t})},onSuccess:t=>{r.value=r.value.map(r=>{if(r.id===n){let n={...r,status:`success`,result:t,progress:100};return e.onItemSuccess?.(n),n}return r}),r.value.every(e=>e.status===`success`||e.status===`error`||e.status===`aborted`)&&e.onComplete?.(r.value),i.value.delete(n),o.value--,d()},onError:t=>{r.value=r.value.map(r=>{if(r.id===n){let n={...r,status:`error`,error:t};return e.onItemError?.(n,t),n}return r}),r.value.every(e=>e.status===`success`||e.status===`error`||e.status===`aborted`)&&e.onComplete?.(r.value),i.value.delete(n),o.value--,d()},onShouldRetry:e.onShouldRetry});i.value.set(n,a),r.value=r.value.map(e=>e.id===n?{...e,jobId:c}:e)}catch(e){r.value=r.value.map(t=>t.id===n?{...t,status:`error`,error:e}:t),o.value--,d()}},f=e=>{let t=Array.from(e).map(e=>({id:`${Date.now()}-${Math.random().toString(36).substr(2,9)}`,file:e,status:`pending`,progress:0,bytesUploaded:0,totalBytes:e.size,error:null,result:null,jobId:null}));r.value=[...r.value,...t]},p=e=>{let t=i.value.get(e);t&&(t(),i.value.delete(e)),r.value=r.value.filter(t=>t.id!==e),a.value=a.value.filter(t=>t!==e)},m=()=>{let e=r.value.filter(e=>e.status===`pending`);a.value.push(...e.map(e=>e.id));for(let e=0;e<l;e++)d()},g=e=>{let t=i.value.get(e);t&&(t(),i.value.delete(e),r.value=r.value.map(t=>t.id===e?{...t,status:`aborted`}:t),o.value--,d())},_=()=>{for(let e of i.value.values())e();i.value.clear(),a.value=[],o.value=0,r.value=r.value.map(e=>e.status===`uploading`?{...e,status:`aborted`}:e)},v=()=>{_(),r.value=[]},y=e=>{r.value=r.value.map(t=>t.id===e?{...t,status:`pending`,progress:0,bytesUploaded:0,error:null}:t),a.value.push(e),d()},b=n(()=>({items:r.value,totalProgress:u(r.value),activeUploads:r.value.filter(e=>e.status===`uploading`).length,completedUploads:r.value.filter(e=>e.status===`success`).length,failedUploads:r.value.filter(e=>e.status===`error`).length}));return{state:s(b),addFiles:f,removeFile:p,startUpload:m,abortUpload:g,abortAll:_,clear:v,retryUpload:y,isUploading:n(()=>b.value.activeUploads>0)}}function T(e={}){let t=h(),{maxConcurrent:r=3}=e,i=c([]),a=c(0),o=c(new Set),l=c(new Map),u=()=>`upload-${Date.now()}-${a.value++}`,d=(e,t)=>{i.value=i.value.map(n=>n.id===e?{...n,state:{...n.state,...t}}:n)},f=()=>{if(i.value.every(e=>[`success`,`error`,`aborted`].includes(e.state.status))&&i.value.length>0){let t=i.value.filter(e=>e.state.status===`success`),n=i.value.filter(e=>[`error`,`aborted`].includes(e.state.status));e.onComplete?.({successful:t,failed:n,total:i.value.length})}},p=async()=>{if(o.value.size>=r)return;let n=i.value.find(e=>e.state.status===`idle`&&!o.value.has(e.id));if(n){o.value.add(n.id),e.onUploadStart?.(n),d(n.id,{status:`uploading`});try{let r=await t.client.upload(n.file,{metadata:e.metadata,uploadLengthDeferred:e.uploadLengthDeferred,uploadSize:e.uploadSize,onProgress:(t,r,i)=>{let a=i?Math.round(r/i*100):0;d(n.id,{progress:a,bytesUploaded:r,totalBytes:i}),e.onUploadProgress?.(n,a,r,i)},onChunkComplete:()=>{},onSuccess:t=>{d(n.id,{status:`success`,result:t,progress:100});let r={...n,state:{...n.state,status:`success`,result:t}};e.onUploadSuccess?.(r,t),o.value.delete(n.id),l.value.delete(n.id),p(),f()},onError:t=>{d(n.id,{status:`error`,error:t});let r={...n,state:{...n.state,status:`error`,error:t}};e.onUploadError?.(r,t),o.value.delete(n.id),l.value.delete(n.id),p(),f()},onShouldRetry:e.onShouldRetry});l.value.set(n.id,r)}catch(t){d(n.id,{status:`error`,error:t});let r={...n,state:{...n.state,status:`error`,error:t}};e.onUploadError?.(r,t),o.value.delete(n.id),l.value.delete(n.id),p(),f()}}},m=n(()=>{let e=i.value;return{total:e.length,completed:e.filter(e=>[`success`,`error`,`aborted`].includes(e.state.status)).length,successful:e.filter(e=>e.state.status===`success`).length,failed:e.filter(e=>[`error`,`aborted`].includes(e.state.status)).length,uploading:e.filter(e=>e.state.status===`uploading`).length,progress:e.length>0?Math.round(e.reduce((e,t)=>e+t.state.progress,0)/e.length):0,totalBytesUploaded:e.reduce((e,t)=>e+t.state.bytesUploaded,0),totalBytes:e.reduce((e,t)=>e+(t.state.totalBytes||0),0),isUploading:e.some(e=>e.state.status===`uploading`),isComplete:e.length>0&&e.every(e=>[`success`,`error`,`aborted`].includes(e.state.status))}}),g=e=>{let t=e.map(e=>({id:u(),file:e,state:{status:`idle`,progress:0,bytesUploaded:0,totalBytes:e instanceof File?e.size:null,error:null,result:null}}));i.value=[...i.value,...t]},_=e=>{let t=i.value.find(t=>t.id===e);if(t&&t.state.status===`uploading`){let t=l.value.get(e);t&&(t.abort(),l.value.delete(e))}i.value=i.value.filter(t=>t.id!==e),o.value.delete(e)},v=e=>{let t=i.value.find(t=>t.id===e);if(t&&t.state.status===`uploading`){let t=l.value.get(e);t&&(t.abort(),l.value.delete(e)),o.value.delete(e),i.value=i.value.map(t=>t.id===e?{...t,state:{...t.state,status:`aborted`}}:t),p()}},y=e=>{let t=i.value.find(t=>t.id===e);t&&[`error`,`aborted`].includes(t.state.status)&&(i.value=i.value.map(t=>t.id===e?{...t,state:{...t.state,status:`idle`,error:null}}:t),setTimeout(()=>p(),0))},b=()=>{let e=i.value.filter(e=>e.state.status===`idle`),t=r-o.value.size,n=e.slice(0,t);for(let e of n)p()},x=()=>{i.value.filter(e=>e.state.status===`uploading`).forEach(e=>{let t=l.value.get(e.id);t&&(t.abort(),l.value.delete(e.id))}),o.value.clear(),i.value=i.value.map(e=>e.state.status===`uploading`?{...e,state:{...e.state,status:`aborted`}}:e)};return{state:s(m),items:s(i),addFiles:g,removeItem:_,removeFile:_,startAll:b,abortUpload:v,abortAll:x,retryUpload:y,retryFailed:()=>{let e=i.value.filter(e=>[`error`,`aborted`].includes(e.state.status));e.length>0&&(i.value=i.value.map(t=>e.some(e=>e.id===t.id)?{...t,state:{...t.state,status:`idle`,error:null}}:t),setTimeout(b,0))},clearCompleted:()=>{i.value=i.value.filter(e=>![`success`,`error`,`aborted`].includes(e.state.status))},clearAll:()=>{x(),i.value=[],o.value.clear()},getItemsByStatus:e=>i.value.filter(t=>t.state.status===e),metrics:{getInsights:()=>t.client.getChunkingInsights(),exportMetrics:()=>t.client.exportMetrics(),getNetworkMetrics:()=>t.client.getNetworkMetrics(),getNetworkCondition:()=>t.client.getNetworkCondition(),resetMetrics:()=>t.client.resetMetrics()}}}const E={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,result:null};function D(e={}){let t=h(),r=c({...E}),i=null;return i=new f((e,n)=>t.client.upload(e,n),{onStateChange:e=>{r.value=e},onProgress:e.onProgress,onChunkComplete:e.onChunkComplete,onSuccess:e.onSuccess,onError:e.onError,onAbort:e.onAbort},e),o(()=>{i?.cleanup()}),{state:r,upload:e=>{i?.upload(e)},abort:()=>{i?.abort()},reset:()=>{i?.reset()},retry:()=>{i?.retry()},isUploading:n(()=>r.value.status===`uploading`),canRetry:n(()=>i?.canRetry()??!1),metrics:{getInsights:()=>t.client.getChunkingInsights(),exportMetrics:()=>t.client.exportMetrics(),getNetworkMetrics:()=>t.client.getNetworkMetrics(),getNetworkCondition:()=>t.client.getNetworkCondition(),resetMetrics:()=>t.client.resetMetrics()}}}const O={totalBytesUploaded:0,totalBytes:0,averageSpeed:0,currentSpeed:0,estimatedTimeRemaining:null,totalFiles:0,completedFiles:0,activeUploads:0,progress:0,peakSpeed:0,startTime:null,endTime:null,totalDuration:null,insights:{overallEfficiency:0,chunkingEffectiveness:0,networkStability:0,recommendations:[],optimalChunkSizeRange:{min:256*1024,max:2*1024*1024}},sessionMetrics:[],chunkMetrics:[]};function k(e={}){let{speedCalculationInterval:t=1e3,speedSampleSize:n=10,onMetricsUpdate:r,onFileStart:i,onFileProgress:a,onFileComplete:l}=e,u=h(),d=c({...O}),f=c([]),p=c([]),m=c(0),g=c(null),_=(e,t)=>{let r={time:e,bytes:t};p.value.push(r),p.value.length>n&&(p.value=p.value.slice(-n));let i=0;if(p.value.length>=2){let e=p.value[p.value.length-1],t=p.value[p.value.length-2];if(e&&t){let n=(e.time-t.time)/1e3,r=e.bytes-t.bytes;i=n>0?r/n:0}}let a=0;if(p.value.length>=2){let e=p.value[0],t=p.value[p.value.length-1];if(e&&t){let n=(t.time-e.time)/1e3,r=t.bytes-e.bytes;a=n>0?r/n:0}}return{currentSpeed:i,averageSpeed:a}},v=()=>{let e=Date.now(),t=f.value.reduce((e,t)=>e+t.size,0),n=f.value.reduce((e,t)=>e+t.bytesUploaded,0),i=f.value.filter(e=>e.isComplete).length,a=f.value.filter(e=>!e.isComplete&&e.bytesUploaded>0).length,{currentSpeed:o,averageSpeed:s}=_(e,n),c=t>0?Math.round(n/t*100):0,l=null;o>0&&(l=(t-n)/o*1e3);let p=f.value.filter(e=>e.startTime>0),m=p.length>0?Math.min(...p.map(e=>e.startTime)):null,h=f.value.filter(e=>e.endTime!==null),g=h.length>0&&i===f.value.length?Math.max(...h.map(e=>e.endTime).filter(e=>e!==null)):null,v=m&&g?g-m:null,y={totalBytesUploaded:n,totalBytes:t,averageSpeed:s,currentSpeed:o,estimatedTimeRemaining:l,totalFiles:f.value.length,completedFiles:i,activeUploads:a,progress:c,peakSpeed:Math.max(d.value.peakSpeed,o),startTime:m,endTime:g,totalDuration:v,insights:u.client.getChunkingInsights(),sessionMetrics:[u.client.exportMetrics().session],chunkMetrics:u.client.exportMetrics().chunks};d.value=y,r?.(y)},y=()=>{g.value&&clearInterval(g.value),g.value=setInterval(()=>{f.value.some(e=>!e.isComplete&&e.bytesUploaded>0)&&v()},t)};return o(()=>{g.value&&clearInterval(g.value)}),{metrics:s(d),fileMetrics:s(f),startFileUpload:(e,t,n)=>{let r={id:e,filename:t,size:n,bytesUploaded:0,progress:0,speed:0,startTime:Date.now(),endTime:null,duration:null,isComplete:!1};f.value.find(t=>t.id===e)?f.value=f.value.map(t=>t.id===e?r:t):f.value=[...f.value,r],i?.(r),f.value.filter(e=>!e.isComplete).length===1&&y()},updateFileProgress:(e,t)=>{let n=Date.now();f.value=f.value.map(r=>{if(r.id!==e)return r;let i=(n-r.startTime)/1e3,o=i>0?t/i:0,s=r.size>0?Math.round(t/r.size*100):0,c={...r,bytesUploaded:t,progress:s,speed:o};return a?.(c),c}),setTimeout(v,0)},completeFileUpload:e=>{let t=Date.now();f.value=f.value.map(n=>{if(n.id!==e)return n;let r=t-n.startTime,i=r>0?n.size/r*1e3:0,a={...n,bytesUploaded:n.size,progress:100,speed:i,endTime:t,duration:r,isComplete:!0};return l?.(a),a}),setTimeout(v,0)},removeFile:e=>{f.value=f.value.filter(t=>t.id!==e),setTimeout(v,0)},reset:()=>{g.value&&=(clearInterval(g.value),null),d.value={...O},f.value=[],p.value=[],m.value=0},getFileMetrics:e=>f.value.find(t=>t.id===e),exportMetrics:()=>({overall:d.value,files:f.value,exportTime:Date.now()})}}export{C as a,_ as c,p as d,m as f,w as i,g as l,D as n,b as o,T as r,v as s,k as t,h as u};
2
- //# sourceMappingURL=composables-7rR8DrBp.mjs.map