@seed-design/react-file-upload 0.0.0-alpha-20260416134952
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/lib/FileUpload-12s-1EmFGBYg.cjs +585 -0
- package/lib/FileUpload-12s-BsPs5ndy.js +569 -0
- package/lib/index.cjs +60 -0
- package/lib/index.d.ts +8012 -0
- package/lib/index.js +43 -0
- package/package.json +48 -0
- package/src/FileUpload.namespace.ts +26 -0
- package/src/FileUpload.tsx +253 -0
- package/src/accept-utils.test.ts +87 -0
- package/src/accept-utils.ts +83 -0
- package/src/index.ts +54 -0
- package/src/types.ts +24 -0
- package/src/useFileUpload.test.tsx +1854 -0
- package/src/useFileUpload.ts +500 -0
- package/src/useFileUploadContext.tsx +50 -0
- package/src/utils.test.ts +46 -0
- package/src/utils.ts +24 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
3
|
+
var reactComposeRefs = require('@radix-ui/react-compose-refs');
|
|
4
|
+
var domUtils = require('@seed-design/dom-utils');
|
|
5
|
+
var reactPrimitive = require('@seed-design/react-primitive');
|
|
6
|
+
var react = require('react');
|
|
7
|
+
var reactUseControllableState = require('@radix-ui/react-use-controllable-state');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Image extension set sourced from mime-db (MIT license).
|
|
11
|
+
* @see https://www.npmjs.com/package/mime
|
|
12
|
+
*/ const IMAGE_EXTENSIONS = new Set([
|
|
13
|
+
"exr",
|
|
14
|
+
"apng",
|
|
15
|
+
"avci",
|
|
16
|
+
"avcs",
|
|
17
|
+
"avif",
|
|
18
|
+
"bmp",
|
|
19
|
+
"dib",
|
|
20
|
+
"cgm",
|
|
21
|
+
"drle",
|
|
22
|
+
"dpx",
|
|
23
|
+
"emf",
|
|
24
|
+
"fits",
|
|
25
|
+
"g3",
|
|
26
|
+
"gif",
|
|
27
|
+
"heic",
|
|
28
|
+
"heics",
|
|
29
|
+
"heif",
|
|
30
|
+
"heifs",
|
|
31
|
+
"hej2",
|
|
32
|
+
"ief",
|
|
33
|
+
"jaii",
|
|
34
|
+
"jais",
|
|
35
|
+
"jls",
|
|
36
|
+
"jp2",
|
|
37
|
+
"jpg2",
|
|
38
|
+
"jpg",
|
|
39
|
+
"jpeg",
|
|
40
|
+
"jpe",
|
|
41
|
+
"jph",
|
|
42
|
+
"jhc",
|
|
43
|
+
"jpm",
|
|
44
|
+
"jpgm",
|
|
45
|
+
"jpx",
|
|
46
|
+
"jpf",
|
|
47
|
+
"jxl",
|
|
48
|
+
"jxr",
|
|
49
|
+
"jxra",
|
|
50
|
+
"jxrs",
|
|
51
|
+
"jxs",
|
|
52
|
+
"jxsc",
|
|
53
|
+
"jxsi",
|
|
54
|
+
"jxss",
|
|
55
|
+
"ktx",
|
|
56
|
+
"ktx2",
|
|
57
|
+
"jfif",
|
|
58
|
+
"png",
|
|
59
|
+
"sgi",
|
|
60
|
+
"svg",
|
|
61
|
+
"svgz",
|
|
62
|
+
"t38",
|
|
63
|
+
"tif",
|
|
64
|
+
"tiff",
|
|
65
|
+
"tfx",
|
|
66
|
+
"webp",
|
|
67
|
+
"wmf"
|
|
68
|
+
]);
|
|
69
|
+
function isImageAccept(pattern) {
|
|
70
|
+
if (pattern.startsWith("image/")) return true;
|
|
71
|
+
if (pattern.startsWith(".")) return IMAGE_EXTENSIONS.has(pattern.slice(1).toLowerCase());
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Determines the file accept type category based on accept patterns.
|
|
76
|
+
* Returns "image" if all patterns are image-related, undefined otherwise.
|
|
77
|
+
*/ function getFileAcceptType(accept) {
|
|
78
|
+
if (!accept) return undefined;
|
|
79
|
+
const list = Array.isArray(accept) ? accept : accept.split(",").map((s)=>s.trim());
|
|
80
|
+
return list.every(isImageAccept) ? "image" : undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const FileUploadContext$1 = /*#__PURE__*/ react.createContext(null);
|
|
84
|
+
const FileUploadProvider = FileUploadContext$1.Provider;
|
|
85
|
+
function useFileUploadContext({ strict = true } = {}) {
|
|
86
|
+
const context = react.useContext(FileUploadContext$1);
|
|
87
|
+
if (!context && strict) {
|
|
88
|
+
throw new Error("useFileUploadContext must be used within a FileUpload");
|
|
89
|
+
}
|
|
90
|
+
return context;
|
|
91
|
+
}
|
|
92
|
+
const ItemContext = /*#__PURE__*/ react.createContext(null);
|
|
93
|
+
const FileUploadItemProvider = ItemContext.Provider;
|
|
94
|
+
function useFileUploadItemContext({ strict = true } = {}) {
|
|
95
|
+
const context = react.useContext(ItemContext);
|
|
96
|
+
if (!context && strict) {
|
|
97
|
+
throw new Error("useFileUploadItemContext must be used within a FileUploadItem");
|
|
98
|
+
}
|
|
99
|
+
return context;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function syncInputFiles(inputEl, files) {
|
|
103
|
+
const dataTransfer = new DataTransfer();
|
|
104
|
+
for (const file of files){
|
|
105
|
+
dataTransfer.items.add(file);
|
|
106
|
+
}
|
|
107
|
+
inputEl.files = dataTransfer.files;
|
|
108
|
+
}
|
|
109
|
+
function useFileUploadState(props) {
|
|
110
|
+
const [acceptedFileEntries, setAcceptedFileEntries] = reactUseControllableState.useControllableState({
|
|
111
|
+
prop: props.acceptedFileEntries,
|
|
112
|
+
defaultProp: props.defaultAcceptedFileEntries ?? [],
|
|
113
|
+
onChange: (filesWithStatus)=>{
|
|
114
|
+
props.onAcceptedFileEntriesChange?.(filesWithStatus);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
const [isDragging, setIsDragging] = react.useState(false);
|
|
118
|
+
return {
|
|
119
|
+
acceptedFileEntries: acceptedFileEntries ?? [],
|
|
120
|
+
isDragging,
|
|
121
|
+
setAcceptedFileEntries,
|
|
122
|
+
setIsDragging
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function useFileUpload({ accept, disabled = false, required = false, invalid = false, readOnly = false, maxFiles = 1, maxFileSize = Number.POSITIVE_INFINITY, minFileSize = 0, name, validate, preventDocumentDrop = true, onFileReject, onFileAccept, ...props } = {}) {
|
|
126
|
+
const inputRef = react.useRef(null);
|
|
127
|
+
const dropzoneRef = react.useRef(null);
|
|
128
|
+
const idCounterRef = react.useRef(0);
|
|
129
|
+
const { acceptedFileEntries, isDragging, setAcceptedFileEntries, setIsDragging } = useFileUploadState(props);
|
|
130
|
+
const multiple = maxFiles > 1;
|
|
131
|
+
const maxFilesReached = acceptedFileEntries.length >= maxFiles;
|
|
132
|
+
const triggerDisabled = disabled || maxFilesReached;
|
|
133
|
+
const acceptString = Array.isArray(accept) ? accept.join(",") : accept;
|
|
134
|
+
const acceptType = getFileAcceptType(accept);
|
|
135
|
+
const isValidFileType = react.useCallback((file)=>{
|
|
136
|
+
if (!accept) return true;
|
|
137
|
+
const acceptList = Array.isArray(accept) ? accept : accept.split(",").map((s)=>s.trim());
|
|
138
|
+
return acceptList.some((acceptPattern)=>{
|
|
139
|
+
// .pdf
|
|
140
|
+
if (acceptPattern.startsWith(".")) return file.name.toLowerCase().endsWith(acceptPattern.toLowerCase());
|
|
141
|
+
// image/* or image/png
|
|
142
|
+
if (acceptPattern.includes("*")) {
|
|
143
|
+
const [type] = acceptPattern.split("/");
|
|
144
|
+
return file.type.startsWith(`${type}/`);
|
|
145
|
+
}
|
|
146
|
+
return file.type === acceptPattern;
|
|
147
|
+
});
|
|
148
|
+
}, [
|
|
149
|
+
accept
|
|
150
|
+
]);
|
|
151
|
+
const validateFiles = react.useCallback((files)=>{
|
|
152
|
+
const accepted = [];
|
|
153
|
+
const rejected = [];
|
|
154
|
+
const currentCount = acceptedFileEntries.length;
|
|
155
|
+
let addedCount = 0;
|
|
156
|
+
for (const file of files){
|
|
157
|
+
const errors = [];
|
|
158
|
+
if (currentCount + addedCount >= maxFiles) {
|
|
159
|
+
errors.push("TOO_MANY_FILES");
|
|
160
|
+
}
|
|
161
|
+
if (!isValidFileType(file)) {
|
|
162
|
+
errors.push("INVALID_TYPE");
|
|
163
|
+
}
|
|
164
|
+
if (file.size > maxFileSize) {
|
|
165
|
+
errors.push("FILE_TOO_LARGE");
|
|
166
|
+
}
|
|
167
|
+
if (file.size < minFileSize) {
|
|
168
|
+
errors.push("FILE_TOO_SMALL");
|
|
169
|
+
}
|
|
170
|
+
if (validate) {
|
|
171
|
+
const customErrors = validate(file);
|
|
172
|
+
if (customErrors) {
|
|
173
|
+
errors.push(...customErrors);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (errors.length > 0) {
|
|
177
|
+
rejected.push({
|
|
178
|
+
file,
|
|
179
|
+
errors
|
|
180
|
+
});
|
|
181
|
+
} else {
|
|
182
|
+
accepted.push(file);
|
|
183
|
+
addedCount++;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
accepted,
|
|
188
|
+
rejected
|
|
189
|
+
};
|
|
190
|
+
}, [
|
|
191
|
+
maxFileSize,
|
|
192
|
+
minFileSize,
|
|
193
|
+
maxFiles,
|
|
194
|
+
acceptedFileEntries.length,
|
|
195
|
+
validate,
|
|
196
|
+
isValidFileType
|
|
197
|
+
]);
|
|
198
|
+
const openFilePicker = react.useCallback(()=>{
|
|
199
|
+
if (triggerDisabled) return;
|
|
200
|
+
if (!inputRef.current) return;
|
|
201
|
+
// Reset value before opening the picker so re-selecting the same file still fires a change event
|
|
202
|
+
// see: https://github.com/chakra-ui/zag/blob/main/packages/machines/file-upload/src/file-upload.connect.ts
|
|
203
|
+
inputRef.current.value = "";
|
|
204
|
+
inputRef.current.click();
|
|
205
|
+
}, [
|
|
206
|
+
triggerDisabled
|
|
207
|
+
]);
|
|
208
|
+
const updateFileEntryStatus = react.useCallback((id, details)=>{
|
|
209
|
+
setAcceptedFileEntries((prev)=>(prev ?? []).map((f)=>f.id === id ? {
|
|
210
|
+
...f,
|
|
211
|
+
...details
|
|
212
|
+
} : f));
|
|
213
|
+
}, [
|
|
214
|
+
setAcceptedFileEntries
|
|
215
|
+
]);
|
|
216
|
+
const setFileEntries = react.useCallback((files)=>{
|
|
217
|
+
if (disabled) return;
|
|
218
|
+
const { accepted, rejected } = validateFiles(files);
|
|
219
|
+
const acceptedEntries = accepted.map((file)=>({
|
|
220
|
+
id: `file-${Date.now()}-${++idCounterRef.current}`,
|
|
221
|
+
file,
|
|
222
|
+
status: "pending"
|
|
223
|
+
}));
|
|
224
|
+
if (acceptedEntries.length > 0) {
|
|
225
|
+
const finalEntries = multiple ? acceptedEntries : [
|
|
226
|
+
acceptedEntries[0]
|
|
227
|
+
];
|
|
228
|
+
if (multiple) {
|
|
229
|
+
setAcceptedFileEntries((prev)=>[
|
|
230
|
+
...prev ?? [],
|
|
231
|
+
...finalEntries
|
|
232
|
+
]);
|
|
233
|
+
} else {
|
|
234
|
+
setAcceptedFileEntries(finalEntries);
|
|
235
|
+
}
|
|
236
|
+
onFileAccept?.(finalEntries, {
|
|
237
|
+
updateFileEntryStatus
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
if (rejected.length > 0) {
|
|
241
|
+
onFileReject?.(rejected);
|
|
242
|
+
}
|
|
243
|
+
}, [
|
|
244
|
+
disabled,
|
|
245
|
+
multiple,
|
|
246
|
+
validateFiles,
|
|
247
|
+
setAcceptedFileEntries,
|
|
248
|
+
onFileReject,
|
|
249
|
+
onFileAccept,
|
|
250
|
+
updateFileEntryStatus
|
|
251
|
+
]);
|
|
252
|
+
const reorderFileEntry = react.useCallback((fromIndex, toIndex)=>{
|
|
253
|
+
if (disabled) return;
|
|
254
|
+
setAcceptedFileEntries((prev)=>{
|
|
255
|
+
const files = [
|
|
256
|
+
...prev ?? []
|
|
257
|
+
];
|
|
258
|
+
if (fromIndex < 0 || fromIndex >= files.length) return prev;
|
|
259
|
+
if (toIndex < 0 || toIndex >= files.length) return prev;
|
|
260
|
+
const [removed] = files.splice(fromIndex, 1);
|
|
261
|
+
files.splice(toIndex, 0, removed);
|
|
262
|
+
return files;
|
|
263
|
+
});
|
|
264
|
+
}, [
|
|
265
|
+
disabled,
|
|
266
|
+
setAcceptedFileEntries
|
|
267
|
+
]);
|
|
268
|
+
const createFileUrl = react.useCallback((file, callback)=>{
|
|
269
|
+
const url = URL.createObjectURL(file);
|
|
270
|
+
callback(url);
|
|
271
|
+
return ()=>URL.revokeObjectURL(url);
|
|
272
|
+
}, []);
|
|
273
|
+
const removeFileEntry = react.useCallback((id)=>{
|
|
274
|
+
setAcceptedFileEntries((prev)=>(prev ?? []).filter((f)=>f.id !== id));
|
|
275
|
+
}, [
|
|
276
|
+
setAcceptedFileEntries
|
|
277
|
+
]);
|
|
278
|
+
const clearFileEntries = react.useCallback(()=>{
|
|
279
|
+
setAcceptedFileEntries([]);
|
|
280
|
+
}, [
|
|
281
|
+
setAcceptedFileEntries
|
|
282
|
+
]);
|
|
283
|
+
const stateProps = domUtils.elementProps({
|
|
284
|
+
"data-dragging-over": domUtils.dataAttr(isDragging),
|
|
285
|
+
"data-disabled": domUtils.dataAttr(triggerDisabled),
|
|
286
|
+
"data-invalid": domUtils.dataAttr(invalid)
|
|
287
|
+
});
|
|
288
|
+
react.useEffect(()=>{
|
|
289
|
+
if (!inputRef.current) return;
|
|
290
|
+
syncInputFiles(inputRef.current, acceptedFileEntries.map((e)=>e.file));
|
|
291
|
+
}, [
|
|
292
|
+
acceptedFileEntries
|
|
293
|
+
]);
|
|
294
|
+
react.useEffect(()=>{
|
|
295
|
+
if (!preventDocumentDrop) return;
|
|
296
|
+
if (disabled) return;
|
|
297
|
+
const onDragOver = (event)=>{
|
|
298
|
+
if (!dropzoneRef.current) return;
|
|
299
|
+
event.preventDefault();
|
|
300
|
+
};
|
|
301
|
+
const onDrop = (event)=>{
|
|
302
|
+
if (!dropzoneRef.current) return;
|
|
303
|
+
const target = event.target;
|
|
304
|
+
if (dropzoneRef.current.contains(target)) return;
|
|
305
|
+
event.preventDefault();
|
|
306
|
+
};
|
|
307
|
+
document.addEventListener("dragover", onDragOver);
|
|
308
|
+
document.addEventListener("drop", onDrop);
|
|
309
|
+
return ()=>{
|
|
310
|
+
document.removeEventListener("dragover", onDragOver);
|
|
311
|
+
document.removeEventListener("drop", onDrop);
|
|
312
|
+
};
|
|
313
|
+
}, [
|
|
314
|
+
preventDocumentDrop,
|
|
315
|
+
disabled
|
|
316
|
+
]);
|
|
317
|
+
return {
|
|
318
|
+
inputRef,
|
|
319
|
+
dropzoneRef,
|
|
320
|
+
acceptedFileEntries,
|
|
321
|
+
dragging: isDragging,
|
|
322
|
+
disabled,
|
|
323
|
+
invalid,
|
|
324
|
+
required,
|
|
325
|
+
maxFiles,
|
|
326
|
+
currentFileEntryCount: acceptedFileEntries.length,
|
|
327
|
+
acceptType,
|
|
328
|
+
openFilePicker,
|
|
329
|
+
setFileEntries,
|
|
330
|
+
reorderFileEntry,
|
|
331
|
+
createFileUrl,
|
|
332
|
+
updateFileEntryStatus,
|
|
333
|
+
removeFileEntry,
|
|
334
|
+
clearFileEntries,
|
|
335
|
+
stateProps,
|
|
336
|
+
dropzoneProps: domUtils.elementProps({
|
|
337
|
+
...stateProps,
|
|
338
|
+
onDragOver: (event)=>{
|
|
339
|
+
if (triggerDisabled) return;
|
|
340
|
+
event.preventDefault();
|
|
341
|
+
event.stopPropagation();
|
|
342
|
+
setIsDragging(true);
|
|
343
|
+
},
|
|
344
|
+
onDragEnter: (event)=>{
|
|
345
|
+
if (triggerDisabled) return;
|
|
346
|
+
event.preventDefault();
|
|
347
|
+
event.stopPropagation();
|
|
348
|
+
setIsDragging(true);
|
|
349
|
+
},
|
|
350
|
+
onDragLeave: (event)=>{
|
|
351
|
+
if (triggerDisabled) return;
|
|
352
|
+
event.preventDefault();
|
|
353
|
+
event.stopPropagation();
|
|
354
|
+
// Only set dragging to false if we're leaving the dropzone entirely
|
|
355
|
+
const relatedTarget = event.relatedTarget;
|
|
356
|
+
if (!event.currentTarget.contains(relatedTarget)) {
|
|
357
|
+
setIsDragging(false);
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
onDrop: (event)=>{
|
|
361
|
+
if (disabled) return;
|
|
362
|
+
event.preventDefault();
|
|
363
|
+
event.stopPropagation();
|
|
364
|
+
setIsDragging(false);
|
|
365
|
+
const files = event.dataTransfer?.files;
|
|
366
|
+
if (files && files.length > 0) {
|
|
367
|
+
setFileEntries(Array.from(files));
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}),
|
|
371
|
+
triggerProps: domUtils.buttonProps({
|
|
372
|
+
...stateProps,
|
|
373
|
+
type: "button",
|
|
374
|
+
disabled: triggerDisabled,
|
|
375
|
+
onClick: openFilePicker
|
|
376
|
+
}),
|
|
377
|
+
hiddenInputProps: domUtils.inputProps({
|
|
378
|
+
type: "file",
|
|
379
|
+
name,
|
|
380
|
+
accept: acceptString,
|
|
381
|
+
multiple,
|
|
382
|
+
disabled,
|
|
383
|
+
"aria-required": domUtils.ariaAttr(required),
|
|
384
|
+
tabIndex: -1,
|
|
385
|
+
style: domUtils.visuallyHidden,
|
|
386
|
+
onChange: (event)=>{
|
|
387
|
+
const files = event.target.files;
|
|
388
|
+
if (files) {
|
|
389
|
+
setFileEntries(Array.from(files));
|
|
390
|
+
}
|
|
391
|
+
event.target.value = "";
|
|
392
|
+
}
|
|
393
|
+
})
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function useFileUploadItem(fileEntry) {
|
|
397
|
+
const { createFileUrl, removeFileEntry, acceptType } = useFileUploadContext();
|
|
398
|
+
const [isOverlayRendered, setIsOverlayRendered] = react.useState(false);
|
|
399
|
+
const overlayRef = react.useCallback((node)=>{
|
|
400
|
+
setIsOverlayRendered(!!node);
|
|
401
|
+
}, []);
|
|
402
|
+
// Image blob URL management
|
|
403
|
+
const [imageSrc, setImageSrc] = react.useState();
|
|
404
|
+
react.useEffect(()=>{
|
|
405
|
+
if (acceptType !== "image") return;
|
|
406
|
+
if (!fileEntry.file) return;
|
|
407
|
+
return createFileUrl(fileEntry.file, setImageSrc);
|
|
408
|
+
}, [
|
|
409
|
+
fileEntry.file,
|
|
410
|
+
createFileUrl,
|
|
411
|
+
acceptType
|
|
412
|
+
]);
|
|
413
|
+
const overlayStateProps = domUtils.elementProps({
|
|
414
|
+
"data-has-overlay": domUtils.dataAttr(isOverlayRendered)
|
|
415
|
+
});
|
|
416
|
+
return {
|
|
417
|
+
...fileEntry,
|
|
418
|
+
refs: {
|
|
419
|
+
overlay: overlayRef
|
|
420
|
+
},
|
|
421
|
+
...acceptType === "image" && imageSrc && {
|
|
422
|
+
imageProps: {
|
|
423
|
+
src: imageSrc,
|
|
424
|
+
alt: fileEntry.file.name
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
thumbnailProps: overlayStateProps,
|
|
428
|
+
metadataProps: overlayStateProps,
|
|
429
|
+
// NOTE: `disabled` of item remove button works separately from the overall `disabled` state so we don't have stateProps here
|
|
430
|
+
removeButtonProps: domUtils.buttonProps({
|
|
431
|
+
type: "button",
|
|
432
|
+
onClick: ()=>{
|
|
433
|
+
removeFileEntry(fileEntry.id);
|
|
434
|
+
}
|
|
435
|
+
})
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const FileUploadRoot = /*#__PURE__*/ react.forwardRef(({ // UseFileUploadProps
|
|
440
|
+
accept, acceptedFileEntries, defaultAcceptedFileEntries, disabled, invalid, maxFileSize, maxFiles, minFileSize, name, onAcceptedFileEntriesChange, onFileAccept, onFileReject, preventDocumentDrop, readOnly, required, validate, ...otherProps }, ref)=>{
|
|
441
|
+
const api = useFileUpload({
|
|
442
|
+
accept,
|
|
443
|
+
acceptedFileEntries,
|
|
444
|
+
defaultAcceptedFileEntries,
|
|
445
|
+
disabled,
|
|
446
|
+
invalid,
|
|
447
|
+
maxFileSize,
|
|
448
|
+
maxFiles,
|
|
449
|
+
minFileSize,
|
|
450
|
+
name,
|
|
451
|
+
onAcceptedFileEntriesChange,
|
|
452
|
+
onFileAccept,
|
|
453
|
+
onFileReject,
|
|
454
|
+
preventDocumentDrop,
|
|
455
|
+
readOnly,
|
|
456
|
+
required,
|
|
457
|
+
validate
|
|
458
|
+
});
|
|
459
|
+
return /*#__PURE__*/ jsxRuntime.jsx(FileUploadProvider, {
|
|
460
|
+
value: api,
|
|
461
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
|
|
462
|
+
ref: ref,
|
|
463
|
+
...api.stateProps,
|
|
464
|
+
...otherProps
|
|
465
|
+
})
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
FileUploadRoot.displayName = "FileUploadRoot";
|
|
469
|
+
const FileUploadDropzone = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
470
|
+
const { dropzoneRef, dropzoneProps } = useFileUploadContext();
|
|
471
|
+
const mergedProps = domUtils.mergeProps(dropzoneProps, props);
|
|
472
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
|
|
473
|
+
ref: reactComposeRefs.composeRefs(dropzoneRef, ref),
|
|
474
|
+
...mergedProps
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
FileUploadDropzone.displayName = "FileUploadDropzone";
|
|
478
|
+
const FileUploadTrigger = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
479
|
+
const { triggerProps } = useFileUploadContext();
|
|
480
|
+
const mergedProps = domUtils.mergeProps(triggerProps, props);
|
|
481
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.button, {
|
|
482
|
+
ref: ref,
|
|
483
|
+
...mergedProps
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
FileUploadTrigger.displayName = "FileUploadTrigger";
|
|
487
|
+
const FileUploadHiddenInput = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
488
|
+
const { inputRef, hiddenInputProps } = useFileUploadContext();
|
|
489
|
+
const mergedProps = domUtils.mergeProps(hiddenInputProps, props);
|
|
490
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.input, {
|
|
491
|
+
ref: reactComposeRefs.composeRefs(inputRef, ref),
|
|
492
|
+
...mergedProps
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
FileUploadHiddenInput.displayName = "FileUploadHiddenInput";
|
|
496
|
+
const FileUploadItemName = /*#__PURE__*/ react.forwardRef(({ children, ...props }, ref)=>{
|
|
497
|
+
const { stateProps } = useFileUploadContext();
|
|
498
|
+
const { file } = useFileUploadItemContext();
|
|
499
|
+
const mergedProps = domUtils.mergeProps(stateProps, props);
|
|
500
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.span, {
|
|
501
|
+
ref: ref,
|
|
502
|
+
...mergedProps,
|
|
503
|
+
children: children ?? file.name
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
FileUploadItemName.displayName = "FileUploadItemName";
|
|
507
|
+
const FileUploadItemSize = /*#__PURE__*/ react.forwardRef(({ children, formatBytes, ...props }, ref)=>{
|
|
508
|
+
const { stateProps } = useFileUploadContext();
|
|
509
|
+
const { file } = useFileUploadItemContext();
|
|
510
|
+
const mergedProps = domUtils.mergeProps(stateProps, props);
|
|
511
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.span, {
|
|
512
|
+
ref: ref,
|
|
513
|
+
...mergedProps,
|
|
514
|
+
children: children ?? formatBytes(file.size)
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
FileUploadItemSize.displayName = "FileUploadItemSize";
|
|
518
|
+
const FileUploadItemRemoveButton = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
519
|
+
const { removeButtonProps } = useFileUploadItemContext();
|
|
520
|
+
const mergedProps = domUtils.mergeProps(removeButtonProps, props);
|
|
521
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.button, {
|
|
522
|
+
ref: ref,
|
|
523
|
+
...mergedProps
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
FileUploadItemRemoveButton.displayName = "FileUploadItemRemoveButton";
|
|
527
|
+
const FileUploadItemImage = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
528
|
+
const ctx = useFileUploadItemContext();
|
|
529
|
+
if (!("imageProps" in ctx)) return null;
|
|
530
|
+
const mergedProps = domUtils.mergeProps(ctx.imageProps ?? {}, props);
|
|
531
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.img, {
|
|
532
|
+
ref: ref,
|
|
533
|
+
...mergedProps
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
FileUploadItemImage.displayName = "FileUploadItemImage";
|
|
537
|
+
const FileUploadItemThumbnail = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
538
|
+
const { thumbnailProps } = useFileUploadItemContext();
|
|
539
|
+
const mergedProps = domUtils.mergeProps(thumbnailProps, props);
|
|
540
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
|
|
541
|
+
ref: ref,
|
|
542
|
+
...mergedProps
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
FileUploadItemThumbnail.displayName = "FileUploadItemThumbnail";
|
|
546
|
+
const FileUploadItemMetadata = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
547
|
+
const { metadataProps } = useFileUploadItemContext();
|
|
548
|
+
const mergedProps = domUtils.mergeProps(metadataProps, props);
|
|
549
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
|
|
550
|
+
ref: ref,
|
|
551
|
+
...mergedProps
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
FileUploadItemMetadata.displayName = "FileUploadItemMetadata";
|
|
555
|
+
const FileUploadItemBackdrop = /*#__PURE__*/ react.forwardRef(({ status, children, ...props }, ref)=>{
|
|
556
|
+
const entry = useFileUploadItemContext();
|
|
557
|
+
if (entry.status !== status) return null;
|
|
558
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
|
|
559
|
+
ref: reactComposeRefs.composeRefs(entry.refs.overlay, ref),
|
|
560
|
+
...props,
|
|
561
|
+
children: typeof children === "function" ? children(entry) : children
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
FileUploadItemBackdrop.displayName = "FileUploadItemBackdrop";
|
|
565
|
+
const FileUploadContext = (props)=>{
|
|
566
|
+
return props.children(useFileUploadContext());
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
exports.FileUploadContext = FileUploadContext;
|
|
570
|
+
exports.FileUploadDropzone = FileUploadDropzone;
|
|
571
|
+
exports.FileUploadHiddenInput = FileUploadHiddenInput;
|
|
572
|
+
exports.FileUploadItemBackdrop = FileUploadItemBackdrop;
|
|
573
|
+
exports.FileUploadItemImage = FileUploadItemImage;
|
|
574
|
+
exports.FileUploadItemMetadata = FileUploadItemMetadata;
|
|
575
|
+
exports.FileUploadItemName = FileUploadItemName;
|
|
576
|
+
exports.FileUploadItemProvider = FileUploadItemProvider;
|
|
577
|
+
exports.FileUploadItemRemoveButton = FileUploadItemRemoveButton;
|
|
578
|
+
exports.FileUploadItemSize = FileUploadItemSize;
|
|
579
|
+
exports.FileUploadItemThumbnail = FileUploadItemThumbnail;
|
|
580
|
+
exports.FileUploadRoot = FileUploadRoot;
|
|
581
|
+
exports.FileUploadTrigger = FileUploadTrigger;
|
|
582
|
+
exports.useFileUpload = useFileUpload;
|
|
583
|
+
exports.useFileUploadContext = useFileUploadContext;
|
|
584
|
+
exports.useFileUploadItem = useFileUploadItem;
|
|
585
|
+
exports.useFileUploadItemContext = useFileUploadItemContext;
|