uplofile 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -19
- package/dist/index.d.ts +4 -0
- package/dist/index.mjs +28 -18
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -7,11 +7,11 @@ Accessible, unstyled primitives for building your own upload UI — with drag‑
|
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
- React 16+ compatible
|
|
11
|
-
- Drag‑and‑drop or click‑to‑upload
|
|
12
|
-
- Upload progress, plus cancel/retry/remove actions
|
|
10
|
+
- React 16+ compatible
|
|
11
|
+
- Drag‑and‑drop or click‑to‑upload
|
|
12
|
+
- Upload progress, plus cancel/retry/remove actions
|
|
13
13
|
- **Custom Validation:** Use `beforeUpload` to validate files before they start uploading
|
|
14
|
-
- Hidden input for form submissions
|
|
14
|
+
- Hidden input for form submissions
|
|
15
15
|
- Unstyled — bring your own design
|
|
16
16
|
|
|
17
17
|
---
|
|
@@ -36,25 +36,25 @@ Import and use the components in your React component:
|
|
|
36
36
|
"use client";
|
|
37
37
|
|
|
38
38
|
import {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
UplofileDropzone,
|
|
40
|
+
UplofilePreview,
|
|
41
|
+
UplofileRoot,
|
|
42
|
+
UplofileTrigger,
|
|
43
43
|
} from "uplofile";
|
|
44
44
|
|
|
45
45
|
export default function Basic() {
|
|
46
46
|
return (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
<UplofileRoot onRemove={onRemove} upload={upload} removeMode={"strict"}>
|
|
48
|
+
<UplofileDropzone className={"border p-2 rounded"}>
|
|
49
|
+
<span>Drop your files here or</span>{" "}
|
|
50
|
+
<UplofileTrigger className={"underline text-blue-500"}>
|
|
51
|
+
Select file
|
|
52
|
+
</UplofileTrigger>
|
|
53
|
+
<div className={"border-t my-6 py-6"}>
|
|
54
|
+
<UplofilePreview />
|
|
55
|
+
</div>
|
|
56
|
+
</UplofileDropzone>
|
|
57
|
+
</UplofileRoot>
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
60
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ type UploadResult<TMeta = any> = {
|
|
|
29
29
|
type UplofileRootRef<TMeta = any> = {
|
|
30
30
|
setItems: (items: UploadFileItem<TMeta>[] | ((prev: UploadFileItem<TMeta>[]) => UploadFileItem<TMeta>[])) => void;
|
|
31
31
|
getItems: () => UploadFileItem<TMeta>[];
|
|
32
|
+
isLoading: boolean;
|
|
32
33
|
onDrop: (e: DragEvent) => void;
|
|
33
34
|
onDragOver: (e: DragEvent) => void;
|
|
34
35
|
openFileDialog: () => void;
|
|
@@ -66,6 +67,7 @@ type ItemActions = {
|
|
|
66
67
|
type ImageUploaderContextValue<TMeta = any> = {
|
|
67
68
|
items: UploadFileItem<TMeta>[];
|
|
68
69
|
setItems: (items: UploadFileItem<TMeta>[]) => void;
|
|
70
|
+
isLoading: boolean;
|
|
69
71
|
disabled?: boolean;
|
|
70
72
|
multiple: boolean;
|
|
71
73
|
accept: string;
|
|
@@ -92,6 +94,7 @@ type ImageUploaderContextValue<TMeta = any> = {
|
|
|
92
94
|
};
|
|
93
95
|
type TriggerRenderProps<TMeta = any> = {
|
|
94
96
|
items: UploadFileItem<TMeta>[];
|
|
97
|
+
isLoading: boolean;
|
|
95
98
|
isUploading: boolean;
|
|
96
99
|
uploadingCount: number;
|
|
97
100
|
doneCount: number;
|
|
@@ -101,6 +104,7 @@ type TriggerRenderProps<TMeta = any> = {
|
|
|
101
104
|
};
|
|
102
105
|
type PreviewRenderProps<TMeta = any> = {
|
|
103
106
|
items: UploadFileItem<TMeta>[];
|
|
107
|
+
isLoading: boolean;
|
|
104
108
|
setItems: (items: UploadFileItem<TMeta>[]) => void;
|
|
105
109
|
actions: ItemActions;
|
|
106
110
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -117,6 +117,7 @@ const acceptsFile = (file, accept)=>{
|
|
|
117
117
|
const UploaderCtx = /*#__PURE__*/ createContext(null);
|
|
118
118
|
const Root = /*#__PURE__*/ forwardRef(({ multiple = true, initial = [], onChange, upload, removeMode = "optimistic", onRemove, accept = "image/*", beforeUpload, name = "image", maxCount, disabled, children }, ref)=>{
|
|
119
119
|
const [items, setItems] = useState([]);
|
|
120
|
+
const [isLoading, setIsLoading] = useState(Array.isArray(initial) ? initial.length > 0 : !!initial);
|
|
120
121
|
const controllers = useRef(new Map());
|
|
121
122
|
const removeControllers = useRef(new Map());
|
|
122
123
|
const inputRef = useRef(null);
|
|
@@ -125,21 +126,25 @@ const Root = /*#__PURE__*/ forwardRef(({ multiple = true, initial = [], onChange
|
|
|
125
126
|
useEffect(()=>{
|
|
126
127
|
if (hasHydratedInitialRef.current) return;
|
|
127
128
|
const hydrate = async ()=>{
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
129
|
+
try {
|
|
130
|
+
const arr = await initial;
|
|
131
|
+
if (!Array.isArray(arr) || arr.length === 0) return;
|
|
132
|
+
const mapped = arr.map((it)=>{
|
|
133
|
+
return {
|
|
134
|
+
uid: it.uid || it.id,
|
|
135
|
+
id: it.id,
|
|
136
|
+
name: it.name,
|
|
137
|
+
url: it.url,
|
|
138
|
+
status: "done",
|
|
139
|
+
meta: it.meta
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
// Only hydrate if the user hasn't already added/modified items locally
|
|
143
|
+
setItems((prev)=>prev.length === 0 ? mapped : prev);
|
|
144
|
+
hasHydratedInitialRef.current = true;
|
|
145
|
+
} finally{
|
|
146
|
+
setIsLoading(false);
|
|
147
|
+
}
|
|
143
148
|
};
|
|
144
149
|
void hydrate();
|
|
145
150
|
}, [
|
|
@@ -377,6 +382,7 @@ const Root = /*#__PURE__*/ forwardRef(({ multiple = true, initial = [], onChange
|
|
|
377
382
|
}, []);
|
|
378
383
|
const ctx = {
|
|
379
384
|
items,
|
|
385
|
+
isLoading,
|
|
380
386
|
disabled,
|
|
381
387
|
multiple,
|
|
382
388
|
accept,
|
|
@@ -409,6 +415,7 @@ const Root = /*#__PURE__*/ forwardRef(({ multiple = true, initial = [], onChange
|
|
|
409
415
|
useImperativeHandle(ref, ()=>({
|
|
410
416
|
setItems: emitChange,
|
|
411
417
|
getItems: ()=>items,
|
|
418
|
+
isLoading,
|
|
412
419
|
onDrop,
|
|
413
420
|
onDragOver,
|
|
414
421
|
openFileDialog: ()=>inputRef.current?.click(),
|
|
@@ -416,6 +423,7 @@ const Root = /*#__PURE__*/ forwardRef(({ multiple = true, initial = [], onChange
|
|
|
416
423
|
}), [
|
|
417
424
|
emitChange,
|
|
418
425
|
items,
|
|
426
|
+
isLoading,
|
|
419
427
|
onDrop,
|
|
420
428
|
onDragOver,
|
|
421
429
|
actions
|
|
@@ -453,11 +461,12 @@ const Dropzone = ({ asChild, ...rest })=>{
|
|
|
453
461
|
};
|
|
454
462
|
|
|
455
463
|
const Preview = ({ render })=>{
|
|
456
|
-
const { items, actions, setItems } = useUplofile();
|
|
464
|
+
const { items, actions, setItems, isLoading } = useUplofile();
|
|
457
465
|
if (render && typeof render === "function") return render({
|
|
458
466
|
items,
|
|
459
467
|
setItems,
|
|
460
|
-
actions
|
|
468
|
+
actions,
|
|
469
|
+
isLoading
|
|
461
470
|
});
|
|
462
471
|
if (items.length === 0) return null;
|
|
463
472
|
return /*#__PURE__*/ jsx("div", {
|
|
@@ -765,7 +774,7 @@ const Remove = ({ uid, asChild, ...rest })=>{
|
|
|
765
774
|
};
|
|
766
775
|
|
|
767
776
|
const Trigger = ({ asChild, children, render, ...rest })=>{
|
|
768
|
-
const { openFileDialog, disabled, items } = useUplofile();
|
|
777
|
+
const { openFileDialog, disabled, items, isLoading } = useUplofile();
|
|
769
778
|
const Comp = asChild ? Slot : "button";
|
|
770
779
|
const uploading = items.filter((i)=>i.status === "uploading");
|
|
771
780
|
const uploadingCount = uploading.length;
|
|
@@ -774,6 +783,7 @@ const Trigger = ({ asChild, children, render, ...rest })=>{
|
|
|
774
783
|
const totalProgress = uploadingCount ? Math.round(uploading.reduce((acc, it)=>acc + (typeof it.progress === "number" ? it.progress : 0), 0) / uploadingCount) : undefined;
|
|
775
784
|
const api = {
|
|
776
785
|
items,
|
|
786
|
+
isLoading,
|
|
777
787
|
isUploading: uploadingCount > 0,
|
|
778
788
|
uploadingCount,
|
|
779
789
|
doneCount,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uplofile",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Composable file‑upload components for React.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chris Josh <KristofaJosh>",
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
"clean": "rm -rf dist",
|
|
42
42
|
"prepare": "pnpm run build",
|
|
43
43
|
"prepublishOnly": "pnpm run build",
|
|
44
|
-
"test": "vitest"
|
|
44
|
+
"test": "vitest",
|
|
45
|
+
"format": "prettier --write ."
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
48
|
"@radix-ui/react-slot": "1.1.0"
|