jaci-ui 0.2.0 → 0.4.0
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/CHANGELOG.md +12 -0
- package/README.md +95 -0
- package/dist/components/button-group/button-group.cjs +22 -0
- package/dist/components/button-group/button-group.cjs.map +1 -0
- package/dist/components/button-group/button-group.d.cts +12 -0
- package/dist/components/button-group/button-group.d.ts +12 -0
- package/dist/components/button-group/button-group.js +21 -0
- package/dist/components/button-group/button-group.js.map +1 -0
- package/dist/components/button-group/index.d.cts +2 -0
- package/dist/components/button-group/index.d.ts +2 -0
- package/dist/components/calendar/calendar.cjs +377 -0
- package/dist/components/calendar/calendar.cjs.map +1 -0
- package/dist/components/calendar/calendar.d.cts +56 -0
- package/dist/components/calendar/calendar.d.ts +56 -0
- package/dist/components/calendar/calendar.js +368 -0
- package/dist/components/calendar/calendar.js.map +1 -0
- package/dist/components/calendar/index.d.cts +2 -0
- package/dist/components/calendar/index.d.ts +2 -0
- package/dist/components/combobox/combobox.cjs +13 -1
- package/dist/components/combobox/combobox.cjs.map +1 -1
- package/dist/components/combobox/combobox.d.cts +7 -2
- package/dist/components/combobox/combobox.d.ts +7 -2
- package/dist/components/combobox/combobox.js +13 -2
- package/dist/components/combobox/combobox.js.map +1 -1
- package/dist/components/combobox/index.d.cts +2 -2
- package/dist/components/combobox/index.d.ts +2 -2
- package/dist/components/controls/input.cjs +26 -5
- package/dist/components/controls/input.cjs.map +1 -1
- package/dist/components/controls/input.d.cts +5 -2
- package/dist/components/controls/input.d.ts +5 -2
- package/dist/components/controls/input.js +28 -7
- package/dist/components/controls/input.js.map +1 -1
- package/dist/components/controls/textarea.cjs +26 -5
- package/dist/components/controls/textarea.cjs.map +1 -1
- package/dist/components/controls/textarea.d.cts +5 -2
- package/dist/components/controls/textarea.d.ts +5 -2
- package/dist/components/controls/textarea.js +28 -7
- package/dist/components/controls/textarea.js.map +1 -1
- package/dist/components/date-picker/date-picker.cjs +9 -9
- package/dist/components/date-picker/date-picker.cjs.map +1 -1
- package/dist/components/date-picker/date-picker.d.cts +3 -1
- package/dist/components/date-picker/date-picker.d.ts +3 -1
- package/dist/components/date-picker/date-picker.js +9 -9
- package/dist/components/date-picker/date-picker.js.map +1 -1
- package/dist/components/date-range-picker/date-range-picker.cjs +589 -0
- package/dist/components/date-range-picker/date-range-picker.cjs.map +1 -0
- package/dist/components/date-range-picker/date-range-picker.d.cts +134 -0
- package/dist/components/date-range-picker/date-range-picker.d.ts +134 -0
- package/dist/components/date-range-picker/date-range-picker.js +568 -0
- package/dist/components/date-range-picker/date-range-picker.js.map +1 -0
- package/dist/components/date-range-picker/index.d.cts +2 -0
- package/dist/components/date-range-picker/index.d.ts +2 -0
- package/dist/components/empty-state/empty-state.cjs +62 -0
- package/dist/components/empty-state/empty-state.cjs.map +1 -0
- package/dist/components/empty-state/empty-state.d.cts +18 -0
- package/dist/components/empty-state/empty-state.d.ts +18 -0
- package/dist/components/empty-state/empty-state.js +57 -0
- package/dist/components/empty-state/empty-state.js.map +1 -0
- package/dist/components/empty-state/index.d.cts +2 -0
- package/dist/components/empty-state/index.d.ts +2 -0
- package/dist/components/field/field.cjs +106 -11
- package/dist/components/field/field.cjs.map +1 -1
- package/dist/components/field/field.d.cts +22 -4
- package/dist/components/field/field.d.ts +22 -4
- package/dist/components/field/field.js +107 -13
- package/dist/components/field/field.js.map +1 -1
- package/dist/components/field/index.d.cts +2 -2
- package/dist/components/field/index.d.ts +2 -2
- package/dist/components/icon-button/icon-button.cjs +40 -0
- package/dist/components/icon-button/icon-button.cjs.map +1 -0
- package/dist/components/icon-button/icon-button.d.cts +12 -0
- package/dist/components/icon-button/icon-button.d.ts +12 -0
- package/dist/components/icon-button/icon-button.js +40 -0
- package/dist/components/icon-button/icon-button.js.map +1 -0
- package/dist/components/icon-button/index.d.cts +2 -0
- package/dist/components/icon-button/index.d.ts +2 -0
- package/dist/components/input-group/index.d.cts +2 -0
- package/dist/components/input-group/index.d.ts +2 -0
- package/dist/components/input-group/input-group.cjs +32 -0
- package/dist/components/input-group/input-group.cjs.map +1 -0
- package/dist/components/input-group/input-group.d.cts +15 -0
- package/dist/components/input-group/input-group.d.ts +15 -0
- package/dist/components/input-group/input-group.js +30 -0
- package/dist/components/input-group/input-group.js.map +1 -0
- package/dist/components/pin-input/index.d.cts +2 -0
- package/dist/components/pin-input/index.d.ts +2 -0
- package/dist/components/pin-input/pin-input.cjs +266 -0
- package/dist/components/pin-input/pin-input.cjs.map +1 -0
- package/dist/components/pin-input/pin-input.d.cts +46 -0
- package/dist/components/pin-input/pin-input.d.ts +46 -0
- package/dist/components/pin-input/pin-input.js +258 -0
- package/dist/components/pin-input/pin-input.js.map +1 -0
- package/dist/components/select/index.d.cts +2 -2
- package/dist/components/select/index.d.ts +2 -2
- package/dist/components/select/select.cjs +80 -3
- package/dist/components/select/select.cjs.map +1 -1
- package/dist/components/select/select.d.cts +18 -3
- package/dist/components/select/select.d.ts +18 -3
- package/dist/components/select/select.js +78 -5
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/tags-input/tags-input.cjs +83 -5
- package/dist/components/tags-input/tags-input.cjs.map +1 -1
- package/dist/components/tags-input/tags-input.d.cts +3 -0
- package/dist/components/tags-input/tags-input.d.ts +3 -0
- package/dist/components/tags-input/tags-input.js +83 -5
- package/dist/components/tags-input/tags-input.js.map +1 -1
- package/dist/components/upload/index.d.cts +2 -2
- package/dist/components/upload/index.d.ts +2 -2
- package/dist/components/upload/upload.cjs +90 -10
- package/dist/components/upload/upload.cjs.map +1 -1
- package/dist/components/upload/upload.d.cts +25 -2
- package/dist/components/upload/upload.d.ts +25 -2
- package/dist/components/upload/upload.js +89 -11
- package/dist/components/upload/upload.js.map +1 -1
- package/dist/index.cjs +70 -0
- package/dist/index.d.cts +21 -5
- package/dist/index.d.ts +21 -5
- package/dist/index.js +13 -5
- package/dist/styled-system/recipes/button-group.cjs +30 -0
- package/dist/styled-system/recipes/button-group.cjs.map +1 -0
- package/dist/styled-system/recipes/button-group.js +30 -0
- package/dist/styled-system/recipes/button-group.js.map +1 -0
- package/dist/styled-system/recipes/calendar.cjs +43 -0
- package/dist/styled-system/recipes/calendar.cjs.map +1 -0
- package/dist/styled-system/recipes/calendar.js +43 -0
- package/dist/styled-system/recipes/calendar.js.map +1 -0
- package/dist/styled-system/recipes/combobox.cjs +1 -0
- package/dist/styled-system/recipes/combobox.cjs.map +1 -1
- package/dist/styled-system/recipes/combobox.js +1 -0
- package/dist/styled-system/recipes/combobox.js.map +1 -1
- package/dist/styled-system/recipes/date-range-picker.cjs +52 -0
- package/dist/styled-system/recipes/date-range-picker.cjs.map +1 -0
- package/dist/styled-system/recipes/date-range-picker.js +52 -0
- package/dist/styled-system/recipes/date-range-picker.js.map +1 -0
- package/dist/styled-system/recipes/empty-state.cjs +36 -0
- package/dist/styled-system/recipes/empty-state.cjs.map +1 -0
- package/dist/styled-system/recipes/empty-state.js +36 -0
- package/dist/styled-system/recipes/empty-state.js.map +1 -0
- package/dist/styled-system/recipes/icon-button.cjs +40 -0
- package/dist/styled-system/recipes/icon-button.cjs.map +1 -0
- package/dist/styled-system/recipes/icon-button.js +40 -0
- package/dist/styled-system/recipes/icon-button.js.map +1 -0
- package/dist/styled-system/recipes/input-group.cjs +30 -0
- package/dist/styled-system/recipes/input-group.cjs.map +1 -0
- package/dist/styled-system/recipes/input-group.js +30 -0
- package/dist/styled-system/recipes/input-group.js.map +1 -0
- package/dist/styled-system/recipes/pin-input.cjs +39 -0
- package/dist/styled-system/recipes/pin-input.cjs.map +1 -0
- package/dist/styled-system/recipes/pin-input.js +39 -0
- package/dist/styled-system/recipes/pin-input.js.map +1 -0
- package/dist/styled-system/recipes/select.cjs +5 -1
- package/dist/styled-system/recipes/select.cjs.map +1 -1
- package/dist/styled-system/recipes/select.js +5 -1
- package/dist/styled-system/recipes/select.js.map +1 -1
- package/dist/styled-system/recipes/upload.cjs +2 -0
- package/dist/styled-system/recipes/upload.cjs.map +1 -1
- package/dist/styled-system/recipes/upload.js +2 -0
- package/dist/styled-system/recipes/upload.js.map +1 -1
- package/dist/styles/theme.cjs +15 -0
- package/dist/styles/theme.cjs.map +1 -1
- package/dist/styles/theme.js +15 -0
- package/dist/styles/theme.js.map +1 -1
- package/dist/styles.css +901 -46
- package/dist/theme/index.d.cts +2 -0
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/theme-provider.cjs +86 -0
- package/dist/theme/theme-provider.cjs.map +1 -0
- package/dist/theme/theme-provider.d.cts +66 -0
- package/dist/theme/theme-provider.d.ts +66 -0
- package/dist/theme/theme-provider.js +85 -0
- package/dist/theme/theme-provider.js.map +1 -0
- package/package.json +3 -2
|
@@ -30,7 +30,7 @@ function acceptsFile(file, accept) {
|
|
|
30
30
|
return pattern === fileType;
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
-
const UploadRoot = (0, react.forwardRef)(function UploadRoot({ accept, children, className, defaultFiles = [], disabled = false, files: controlledFiles, maxFiles, maxSize, multiple = false, onFilesChange, onReject, ...props }, ref) {
|
|
33
|
+
const UploadRoot = (0, react.forwardRef)(function UploadRoot({ accept, fileState, children, className, defaultFiles = [], disabled = false, files: controlledFiles, maxFiles, maxSize, multiple = false, onFilesChange, onCancel, onReject, validateFile, ...props }, ref) {
|
|
34
34
|
const [uncontrolledFiles, setUncontrolledFiles] = (0, react.useState)(defaultFiles);
|
|
35
35
|
const [dropActive, setDropActive] = (0, react.useState)(false);
|
|
36
36
|
const [rejections, setRejections] = (0, react.useState)([]);
|
|
@@ -43,14 +43,18 @@ const UploadRoot = (0, react.forwardRef)(function UploadRoot({ accept, children,
|
|
|
43
43
|
const currentFiles = controlledFiles ?? uncontrolledFiles;
|
|
44
44
|
const fileLimit = maxFiles ?? (multiple ? void 0 : 1);
|
|
45
45
|
const updateFiles = (0, react.useCallback)((nextFiles) => {
|
|
46
|
-
setUncontrolledFiles(nextFiles);
|
|
46
|
+
if (controlledFiles === void 0) setUncontrolledFiles(nextFiles);
|
|
47
47
|
onFilesChange?.(nextFiles);
|
|
48
|
-
}, [onFilesChange]);
|
|
48
|
+
}, [controlledFiles, onFilesChange]);
|
|
49
|
+
const removeFile = (0, react.useCallback)((file) => {
|
|
50
|
+
updateFiles(currentFiles.filter((current) => fileKey(current) !== fileKey(file)));
|
|
51
|
+
}, [currentFiles, updateFiles]);
|
|
49
52
|
const addFiles = (0, react.useCallback)((fileList) => {
|
|
50
53
|
if (disabled) return;
|
|
51
54
|
const candidates = Array.from(fileList);
|
|
52
55
|
const acceptedFiles = [];
|
|
53
56
|
const nextRejections = [];
|
|
57
|
+
const pendingValidations = /* @__PURE__ */ new Map();
|
|
54
58
|
const existingKeys = new Set(currentFiles.map(fileKey));
|
|
55
59
|
for (const file of candidates) {
|
|
56
60
|
const key = fileKey(file);
|
|
@@ -86,10 +90,46 @@ const UploadRoot = (0, react.forwardRef)(function UploadRoot({ accept, children,
|
|
|
86
90
|
});
|
|
87
91
|
continue;
|
|
88
92
|
}
|
|
93
|
+
if (validateFile) {
|
|
94
|
+
const validation = validateFile(file);
|
|
95
|
+
if (validation && typeof validation !== "object") {
|
|
96
|
+
nextRejections.push({
|
|
97
|
+
file,
|
|
98
|
+
reason: "validation",
|
|
99
|
+
message: validation
|
|
100
|
+
});
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (validation && typeof validation === "object" && "then" in validation) pendingValidations.set(file, Promise.resolve(validation));
|
|
104
|
+
}
|
|
89
105
|
acceptedFiles.push(file);
|
|
90
106
|
}
|
|
91
107
|
const nextFiles = multiple ? [...currentFiles, ...acceptedFiles] : acceptedFiles.slice(0, 1);
|
|
92
108
|
if (acceptedFiles.length > 0) updateFiles(nextFiles);
|
|
109
|
+
if (validateFile) for (const file of acceptedFiles) {
|
|
110
|
+
const validation = pendingValidations.get(file);
|
|
111
|
+
if (validation) validation.then((message) => {
|
|
112
|
+
if (!message) return;
|
|
113
|
+
const rejection = {
|
|
114
|
+
file,
|
|
115
|
+
reason: "validation",
|
|
116
|
+
message
|
|
117
|
+
};
|
|
118
|
+
updateFiles(nextFiles.filter((current) => fileKey(current) !== fileKey(file)));
|
|
119
|
+
setRejections((current) => [...current, rejection]);
|
|
120
|
+
onReject?.([rejection]);
|
|
121
|
+
}).catch((error) => {
|
|
122
|
+
const message = error instanceof Error ? error.message : "File validation failed.";
|
|
123
|
+
const rejection = {
|
|
124
|
+
file,
|
|
125
|
+
reason: "validation",
|
|
126
|
+
message
|
|
127
|
+
};
|
|
128
|
+
updateFiles(nextFiles.filter((current) => fileKey(current) !== fileKey(file)));
|
|
129
|
+
setRejections((current) => [...current, rejection]);
|
|
130
|
+
onReject?.([rejection]);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
93
133
|
if (nextRejections.length > 0) {
|
|
94
134
|
setRejections(nextRejections);
|
|
95
135
|
onReject?.(nextRejections);
|
|
@@ -102,19 +142,20 @@ const UploadRoot = (0, react.forwardRef)(function UploadRoot({ accept, children,
|
|
|
102
142
|
maxSize,
|
|
103
143
|
multiple,
|
|
104
144
|
onReject,
|
|
105
|
-
updateFiles
|
|
145
|
+
updateFiles,
|
|
146
|
+
validateFile
|
|
106
147
|
]);
|
|
107
|
-
const
|
|
108
|
-
updateFiles(currentFiles.filter((current) => fileKey(current) !== fileKey(file)));
|
|
109
|
-
}, [currentFiles, updateFiles]);
|
|
148
|
+
const cancelFile = (0, react.useCallback)((file) => onCancel?.(file), [onCancel]);
|
|
110
149
|
const context = (0, react.useMemo)(() => ({
|
|
111
150
|
accept,
|
|
112
151
|
addFiles,
|
|
152
|
+
cancelFile,
|
|
113
153
|
disabled,
|
|
114
154
|
dropActive,
|
|
115
155
|
files: currentFiles,
|
|
116
156
|
inputId,
|
|
117
157
|
inputRef,
|
|
158
|
+
fileState,
|
|
118
159
|
maxFiles: fileLimit,
|
|
119
160
|
maxSize,
|
|
120
161
|
multiple,
|
|
@@ -125,10 +166,12 @@ const UploadRoot = (0, react.forwardRef)(function UploadRoot({ accept, children,
|
|
|
125
166
|
}), [
|
|
126
167
|
accept,
|
|
127
168
|
addFiles,
|
|
169
|
+
cancelFile,
|
|
128
170
|
currentFiles,
|
|
129
171
|
disabled,
|
|
130
172
|
dropActive,
|
|
131
173
|
fileLimit,
|
|
174
|
+
fileState,
|
|
132
175
|
inputId,
|
|
133
176
|
maxSize,
|
|
134
177
|
multiple,
|
|
@@ -285,9 +328,10 @@ const UploadPreview = (0, react.forwardRef)(function UploadPreview({ alt, classN
|
|
|
285
328
|
}) : fallback
|
|
286
329
|
});
|
|
287
330
|
});
|
|
288
|
-
const UploadProgress = (0, react.forwardRef)(function UploadProgress({ className, label = "Uploading", value, ...props }, ref) {
|
|
289
|
-
const { styles } = useUploadContext();
|
|
290
|
-
const
|
|
331
|
+
const UploadProgress = (0, react.forwardRef)(function UploadProgress({ className, file, label = "Uploading", value, ...props }, ref) {
|
|
332
|
+
const { fileState, styles } = useUploadContext();
|
|
333
|
+
const state = file ? fileState?.(file) : void 0;
|
|
334
|
+
const normalizedValue = value === void 0 ? state?.progress === void 0 ? void 0 : Math.min(100, Math.max(0, state.progress)) : Math.min(100, Math.max(0, value));
|
|
291
335
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
292
336
|
...props,
|
|
293
337
|
ref,
|
|
@@ -365,6 +409,38 @@ const UploadRemove = (0, react.forwardRef)(function UploadRemove({ children = "
|
|
|
365
409
|
children
|
|
366
410
|
});
|
|
367
411
|
});
|
|
412
|
+
const UploadStatus = (0, react.forwardRef)(function UploadStatus({ children, className, file, ...props }, ref) {
|
|
413
|
+
const { fileState, styles } = useUploadContext();
|
|
414
|
+
const state = fileState?.(file);
|
|
415
|
+
const content = children ?? state?.error ?? state?.status ?? "queued";
|
|
416
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
417
|
+
...props,
|
|
418
|
+
"aria-live": "polite",
|
|
419
|
+
className: require_cx.cx(styles.status, className),
|
|
420
|
+
"data-status": state?.status,
|
|
421
|
+
"data-slot": "upload-status",
|
|
422
|
+
ref,
|
|
423
|
+
children: content
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
const UploadCancel = (0, react.forwardRef)(function UploadCancel({ children = "Cancel", className, file, onClick, ...props }, ref) {
|
|
427
|
+
const { cancelFile, disabled, fileState, styles } = useUploadContext();
|
|
428
|
+
const state = fileState?.(file);
|
|
429
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
430
|
+
...props,
|
|
431
|
+
"aria-label": props["aria-label"] ?? `Cancel ${file.name}`,
|
|
432
|
+
className: require_cx.cx(styles.cancel, className),
|
|
433
|
+
"data-slot": "upload-cancel",
|
|
434
|
+
disabled: disabled || state?.status === "canceled" || state?.status === "success",
|
|
435
|
+
onClick: (event) => {
|
|
436
|
+
cancelFile(file);
|
|
437
|
+
onClick?.(event);
|
|
438
|
+
},
|
|
439
|
+
ref,
|
|
440
|
+
type: "button",
|
|
441
|
+
children
|
|
442
|
+
});
|
|
443
|
+
});
|
|
368
444
|
const UploadError = (0, react.forwardRef)(function UploadError({ children, className, ...props }, ref) {
|
|
369
445
|
const { rejections, styles } = useUploadContext();
|
|
370
446
|
if (children === void 0 && rejections.length === 0) return null;
|
|
@@ -390,10 +466,13 @@ const Upload = {
|
|
|
390
466
|
List: UploadList,
|
|
391
467
|
Item: UploadItem,
|
|
392
468
|
Remove: UploadRemove,
|
|
469
|
+
Status: UploadStatus,
|
|
470
|
+
Cancel: UploadCancel,
|
|
393
471
|
Error: UploadError
|
|
394
472
|
};
|
|
395
473
|
//#endregion
|
|
396
474
|
exports.Upload = Upload;
|
|
475
|
+
exports.UploadCancel = UploadCancel;
|
|
397
476
|
exports.UploadDropzone = UploadDropzone;
|
|
398
477
|
exports.UploadError = UploadError;
|
|
399
478
|
exports.UploadHint = UploadHint;
|
|
@@ -405,6 +484,7 @@ exports.UploadPreview = UploadPreview;
|
|
|
405
484
|
exports.UploadProgress = UploadProgress;
|
|
406
485
|
exports.UploadRemove = UploadRemove;
|
|
407
486
|
exports.UploadRoot = UploadRoot;
|
|
487
|
+
exports.UploadStatus = UploadStatus;
|
|
408
488
|
exports.UploadText = UploadText;
|
|
409
489
|
exports.UploadTrigger = UploadTrigger;
|
|
410
490
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.cjs","names":["upload","cx"],"sources":["../../../src/components/upload/upload.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { ChangeEvent, ComponentPropsWithoutRef, ReactNode, RefObject } from \"react\";\n\nimport { cx } from \"../../styled-system/css\";\nimport { upload } from \"../../styled-system/recipes\";\n\nexport type UploadRejectionReason = \"type\" | \"size\" | \"count\" | \"duplicate\";\n\nexport interface UploadRejection {\n file: File;\n message: string;\n reason: UploadRejectionReason;\n}\n\ninterface UploadContextValue {\n accept: string | undefined;\n addFiles: (files: FileList | File[]) => void;\n disabled: boolean;\n dropActive: boolean;\n files: File[];\n inputId: string;\n inputRef: RefObject<HTMLInputElement | null>;\n maxFiles: number | undefined;\n maxSize: number | undefined;\n multiple: boolean;\n removeFile: (file: File) => void;\n rejections: UploadRejection[];\n setDropActive: (active: boolean) => void;\n styles: ReturnType<typeof upload>;\n}\n\nconst UploadContext = createContext<UploadContextValue | null>(null);\n\nfunction useUploadContext() {\n const context = useContext(UploadContext);\n if (!context) {\n throw new Error(\"Upload parts must be rendered inside Upload.Root.\");\n }\n\n return context;\n}\n\nfunction fileKey(file: File) {\n return `${file.name}-${file.size}-${file.lastModified}`;\n}\n\nfunction formatBytes(bytes: number) {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction acceptsFile(file: File, accept: string | undefined) {\n if (!accept) {\n return true;\n }\n\n const fileName = file.name.toLowerCase();\n const fileType = file.type.toLowerCase();\n\n return accept.split(\",\").some((entry) => {\n const pattern = entry.trim().toLowerCase();\n if (!pattern) return true;\n if (pattern.startsWith(\".\")) return fileName.endsWith(pattern);\n if (pattern.endsWith(\"/*\")) return fileType.startsWith(pattern.slice(0, -1));\n return pattern === fileType;\n });\n}\n\nexport interface UploadRootProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n /** Accepted MIME types or file extensions, using the native input syntax. */\n accept?: string;\n /** Controlled files. Use with `onFilesChange`. */\n files?: File[];\n /** Initial files for an uncontrolled upload. */\n defaultFiles?: File[];\n /** Called whenever accepted files are added or removed. */\n onFilesChange?: (files: File[]) => void;\n /** Called with files rejected by `accept`, `maxSize`, `maxFiles` or duplicates. */\n onReject?: (rejections: UploadRejection[]) => void;\n /** Maximum number of accepted files. Defaults to one when `multiple` is false. */\n maxFiles?: number;\n /** Maximum size per file, in bytes. */\n maxSize?: number;\n /** Allows selecting more than one file. */\n multiple?: boolean;\n /** Disables file selection and drag-and-drop. */\n disabled?: boolean;\n children?: ReactNode;\n}\n\nexport const UploadRoot = forwardRef<HTMLDivElement, UploadRootProps>(function UploadRoot(\n {\n accept,\n children,\n className,\n defaultFiles = [],\n disabled = false,\n files: controlledFiles,\n maxFiles,\n maxSize,\n multiple = false,\n onFilesChange,\n onReject,\n ...props\n },\n ref,\n) {\n const [uncontrolledFiles, setUncontrolledFiles] = useState<File[]>(defaultFiles);\n const [dropActive, setDropActive] = useState(false);\n const [rejections, setRejections] = useState<UploadRejection[]>([]);\n const inputRef = useRef<HTMLInputElement>(null);\n const inputId = useId();\n const styles = upload({ disabled, dropActive });\n const currentFiles = controlledFiles ?? uncontrolledFiles;\n const fileLimit = maxFiles ?? (multiple ? undefined : 1);\n\n const updateFiles = useCallback(\n (nextFiles: File[]) => {\n setUncontrolledFiles(nextFiles);\n onFilesChange?.(nextFiles);\n },\n [onFilesChange],\n );\n\n const addFiles = useCallback(\n (fileList: FileList | File[]) => {\n if (disabled) return;\n\n const candidates = Array.from(fileList);\n const acceptedFiles: File[] = [];\n const nextRejections: UploadRejection[] = [];\n const existingKeys = new Set(currentFiles.map(fileKey));\n\n for (const file of candidates) {\n const key = fileKey(file);\n if (existingKeys.has(key) || acceptedFiles.some((accepted) => fileKey(accepted) === key)) {\n nextRejections.push({\n file,\n reason: \"duplicate\",\n message: `${file.name} was already added.`,\n });\n continue;\n }\n if (!acceptsFile(file, accept)) {\n nextRejections.push({\n file,\n reason: \"type\",\n message: `${file.name} is not an accepted file type.`,\n });\n continue;\n }\n if (maxSize !== undefined && file.size > maxSize) {\n nextRejections.push({\n file,\n reason: \"size\",\n message: `${file.name} is larger than the allowed limit.`,\n });\n continue;\n }\n if (\n fileLimit !== undefined &&\n (multiple ? currentFiles.length + acceptedFiles.length : acceptedFiles.length) >=\n fileLimit\n ) {\n nextRejections.push({\n file,\n reason: \"count\",\n message: `Only ${fileLimit} file${fileLimit === 1 ? \"\" : \"s\"} can be selected.`,\n });\n continue;\n }\n acceptedFiles.push(file);\n }\n\n const nextFiles = multiple ? [...currentFiles, ...acceptedFiles] : acceptedFiles.slice(0, 1);\n if (acceptedFiles.length > 0) {\n updateFiles(nextFiles);\n }\n if (nextRejections.length > 0) {\n setRejections(nextRejections);\n onReject?.(nextRejections);\n } else {\n setRejections([]);\n }\n },\n [accept, currentFiles, disabled, fileLimit, maxSize, multiple, onReject, updateFiles],\n );\n\n const removeFile = useCallback(\n (file: File) => {\n updateFiles(currentFiles.filter((current) => fileKey(current) !== fileKey(file)));\n },\n [currentFiles, updateFiles],\n );\n\n const context = useMemo<UploadContextValue>(\n () => ({\n accept,\n addFiles,\n disabled,\n dropActive,\n files: currentFiles,\n inputId,\n inputRef,\n maxFiles: fileLimit,\n maxSize,\n multiple,\n removeFile,\n rejections,\n setDropActive,\n styles,\n }),\n [\n accept,\n addFiles,\n currentFiles,\n disabled,\n dropActive,\n fileLimit,\n inputId,\n maxSize,\n multiple,\n rejections,\n removeFile,\n styles,\n ],\n );\n\n return (\n <UploadContext.Provider value={context}>\n <div\n {...props}\n ref={ref}\n className={cx(styles.root, className)}\n data-disabled={disabled || undefined}\n data-jaci-component=\"upload\"\n data-slot=\"upload\"\n >\n {children}\n </div>\n </UploadContext.Provider>\n );\n});\n\nexport interface UploadDropzoneProps extends ComponentPropsWithoutRef<\"label\"> {\n children?: ReactNode;\n}\n\nexport const UploadDropzone = forwardRef<HTMLLabelElement, UploadDropzoneProps>(\n function UploadDropzone(\n { children, className, htmlFor, onDragEnter, onDragLeave, onDragOver, onDrop, ...props },\n ref,\n ) {\n const { addFiles, disabled, dropActive, inputId, setDropActive, styles } = useUploadContext();\n\n return (\n <label\n {...props}\n ref={ref}\n aria-disabled={disabled || undefined}\n className={cx(styles.dropzone, className)}\n data-drag-active={dropActive || undefined}\n data-slot=\"upload-dropzone\"\n htmlFor={htmlFor ?? inputId}\n onDragEnter={(event) => {\n event.preventDefault();\n if (!disabled) {\n setDropActive(true);\n event.currentTarget.dataset.dragActive = \"true\";\n }\n onDragEnter?.(event);\n }}\n onDragLeave={(event) => {\n event.preventDefault();\n if (event.currentTarget === event.target) {\n setDropActive(false);\n event.currentTarget.dataset.dragActive = \"false\";\n }\n onDragLeave?.(event);\n }}\n onDragOver={(event) => {\n event.preventDefault();\n if (!disabled) setDropActive(true);\n onDragOver?.(event);\n }}\n onDrop={(event) => {\n event.preventDefault();\n setDropActive(false);\n event.currentTarget.dataset.dragActive = \"false\";\n if (!disabled) addFiles(event.dataTransfer.files);\n onDrop?.(event);\n }}\n >\n {children}\n </label>\n );\n },\n);\n\nexport type UploadInputProps = ComponentPropsWithoutRef<\"input\">;\n\nexport const UploadInput = forwardRef<HTMLInputElement, UploadInputProps>(function UploadInput(\n { accept, className, id, multiple, onChange, ...props },\n ref,\n) {\n const {\n addFiles,\n accept: rootAccept,\n disabled,\n inputId,\n inputRef,\n multiple: rootMultiple,\n styles,\n } = useUploadContext();\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n if (event.currentTarget.files) addFiles(event.currentTarget.files);\n event.currentTarget.value = \"\";\n onChange?.(event);\n };\n\n return (\n <input\n {...props}\n accept={accept ?? rootAccept}\n aria-label={props[\"aria-label\"] ?? \"Select files\"}\n className={cx(styles.input, className)}\n disabled={disabled}\n id={id ?? inputId}\n multiple={multiple ?? rootMultiple}\n onChange={handleChange}\n ref={(node) => {\n inputRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }}\n tabIndex={-1}\n type=\"file\"\n />\n );\n});\n\nexport type UploadTriggerProps = ComponentPropsWithoutRef<\"button\">;\n\nexport const UploadTrigger = forwardRef<HTMLButtonElement, UploadTriggerProps>(\n function UploadTrigger(\n { children = \"Choose files\", className, disabled, onClick, ...props },\n ref,\n ) {\n const { disabled: rootDisabled, inputRef, styles } = useUploadContext();\n\n return (\n <button\n {...props}\n className={cx(styles.trigger, className)}\n data-slot=\"upload-trigger\"\n disabled={disabled ?? rootDisabled}\n onClick={(event) => {\n inputRef.current?.click();\n onClick?.(event);\n }}\n ref={ref}\n type=\"button\"\n >\n {children}\n </button>\n );\n },\n);\n\nexport type UploadIconProps = ComponentPropsWithoutRef<\"span\">;\n\nexport const UploadIcon = forwardRef<HTMLSpanElement, UploadIconProps>(function UploadIcon(\n { children = \"↥\", className, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n return (\n <span\n {...props}\n ref={ref}\n aria-hidden=\"true\"\n className={cx(styles.icon, className)}\n data-slot=\"upload-icon\"\n >\n {children}\n </span>\n );\n});\n\nexport type UploadTextProps = ComponentPropsWithoutRef<\"span\">;\n\nexport const UploadText = forwardRef<HTMLSpanElement, UploadTextProps>(function UploadText(\n { className, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n return (\n <span {...props} ref={ref} className={cx(styles.text, className)} data-slot=\"upload-text\" />\n );\n});\n\nexport type UploadHintProps = ComponentPropsWithoutRef<\"span\">;\n\nexport const UploadHint = forwardRef<HTMLSpanElement, UploadHintProps>(function UploadHint(\n { className, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n return (\n <span {...props} ref={ref} className={cx(styles.hint, className)} data-slot=\"upload-hint\" />\n );\n});\n\nexport interface UploadPreviewProps extends ComponentPropsWithoutRef<\"span\"> {\n /** File whose preview should be rendered. Image files use a temporary object URL. */\n file: File;\n /** Alternative text for image previews. Defaults to the file name. */\n alt?: string;\n /** Content rendered while the preview is unavailable or the file is not an image. */\n fallback?: ReactNode;\n}\n\nexport const UploadPreview = forwardRef<HTMLSpanElement, UploadPreviewProps>(function UploadPreview(\n { alt, className, fallback = \"Preview unavailable\", file, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n const [src, setSrc] = useState<string | null>(null);\n\n useEffect(() => {\n if (\n !file.type.startsWith(\"image/\") ||\n typeof URL === \"undefined\" ||\n typeof URL.createObjectURL !== \"function\"\n ) {\n setSrc(null);\n return;\n }\n\n const objectUrl = URL.createObjectURL(file);\n setSrc(objectUrl);\n return () => URL.revokeObjectURL(objectUrl);\n }, [file]);\n\n return (\n <span\n {...props}\n ref={ref}\n aria-hidden={props[\"aria-label\"] ? undefined : true}\n className={cx(styles.preview, className)}\n data-slot=\"upload-preview\"\n role={props[\"aria-label\"] ? \"img\" : undefined}\n >\n {src ? <img alt={alt ?? file.name} src={src} /> : fallback}\n </span>\n );\n});\n\nexport interface UploadProgressProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /** Progress from 0 to 100. Omit it for an indeterminate upload. */\n value?: number;\n /** Accessible label and optional visible status text. */\n label?: ReactNode;\n}\n\nexport const UploadProgress = forwardRef<HTMLDivElement, UploadProgressProps>(\n function UploadProgress({ className, label = \"Uploading\", value, ...props }, ref) {\n const { styles } = useUploadContext();\n const normalizedValue = value === undefined ? undefined : Math.min(100, Math.max(0, value));\n\n return (\n <div\n {...props}\n ref={ref}\n aria-label={typeof label === \"string\" ? label : \"Upload progress\"}\n aria-valuemax={100}\n aria-valuemin={0}\n aria-valuenow={normalizedValue}\n className={cx(styles.progress, className)}\n data-indeterminate={normalizedValue === undefined || undefined}\n data-slot=\"upload-progress\"\n role=\"progressbar\"\n >\n <span className={styles.progressTrack} data-slot=\"upload-progress-track\">\n <span\n className={styles.progressIndicator}\n data-indeterminate={normalizedValue === undefined || undefined}\n data-slot=\"upload-progress-indicator\"\n style={{ width: normalizedValue === undefined ? undefined : `${normalizedValue}%` }}\n />\n </span>\n <span className={styles.progressLabel} data-slot=\"upload-progress-label\">\n {label}\n </span>\n </div>\n );\n },\n);\n\nexport type UploadListProps = ComponentPropsWithoutRef<\"ul\">;\n\nexport const UploadList = forwardRef<HTMLUListElement, UploadListProps>(function UploadList(\n { children, className, ...props },\n ref,\n) {\n const { files, styles } = useUploadContext();\n return (\n <ul {...props} ref={ref} className={cx(styles.list, className)} data-slot=\"upload-list\">\n {children ?? files.map((file) => <UploadItem file={file} key={fileKey(file)} />)}\n </ul>\n );\n});\n\nexport interface UploadItemProps extends Omit<ComponentPropsWithoutRef<\"li\">, \"children\"> {\n file: File;\n children?: ReactNode;\n}\n\nexport const UploadItem = forwardRef<HTMLLIElement, UploadItemProps>(function UploadItem(\n { children, className, file, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n return (\n <li {...props} ref={ref} className={cx(styles.item, className)} data-slot=\"upload-item\">\n {children ?? (\n <>\n <span className={styles.itemName} data-slot=\"upload-item-name\" title={file.name}>\n {file.name}\n </span>\n <span className={styles.itemMeta} data-slot=\"upload-item-meta\">\n {formatBytes(file.size)}\n </span>\n <UploadRemove file={file} />\n </>\n )}\n </li>\n );\n});\n\nexport interface UploadRemoveProps extends ComponentPropsWithoutRef<\"button\"> {\n file: File;\n}\n\nexport const UploadRemove = forwardRef<HTMLButtonElement, UploadRemoveProps>(function UploadRemove(\n { children = \"×\", className, file, onClick, ...props },\n ref,\n) {\n const { disabled, removeFile, styles } = useUploadContext();\n return (\n <button\n {...props}\n aria-label={props[\"aria-label\"] ?? `Remove ${file.name}`}\n className={cx(styles.remove, className)}\n data-slot=\"upload-remove\"\n disabled={disabled}\n onClick={(event) => {\n removeFile(file);\n onClick?.(event);\n }}\n ref={ref}\n type=\"button\"\n >\n {children}\n </button>\n );\n});\n\nexport type UploadErrorProps = ComponentPropsWithoutRef<\"p\">;\n\nexport const UploadError = forwardRef<HTMLParagraphElement, UploadErrorProps>(function UploadError(\n { children, className, ...props },\n ref,\n) {\n const { rejections, styles } = useUploadContext();\n if (children === undefined && rejections.length === 0) return null;\n\n return (\n <p\n {...props}\n ref={ref}\n className={cx(styles.error, className)}\n data-slot=\"upload-error\"\n role=\"alert\"\n >\n {children ?? rejections.map((rejection) => rejection.message).join(\" \")}\n </p>\n );\n});\n\nexport const Upload = {\n Root: UploadRoot,\n Dropzone: UploadDropzone,\n Input: UploadInput,\n Trigger: UploadTrigger,\n Icon: UploadIcon,\n Text: UploadText,\n Hint: UploadHint,\n Preview: UploadPreview,\n Progress: UploadProgress,\n List: UploadList,\n Item: UploadItem,\n Remove: UploadRemove,\n Error: UploadError,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"upload.cjs","names":["upload","cx"],"sources":["../../../src/components/upload/upload.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { ChangeEvent, ComponentPropsWithoutRef, ReactNode, RefObject } from \"react\";\n\nimport { cx } from \"../../styled-system/css\";\nimport { upload } from \"../../styled-system/recipes\";\n\nexport type UploadRejectionReason = \"type\" | \"size\" | \"count\" | \"duplicate\" | \"validation\";\n\nexport type UploadFileStatus = \"queued\" | \"uploading\" | \"success\" | \"error\" | \"canceled\";\n\nexport interface UploadFileState {\n status: UploadFileStatus;\n progress?: number;\n error?: ReactNode;\n}\n\nexport interface UploadRejection {\n file: File;\n message: string;\n reason: UploadRejectionReason;\n}\n\ninterface UploadContextValue {\n accept: string | undefined;\n addFiles: (files: FileList | File[]) => void;\n disabled: boolean;\n dropActive: boolean;\n files: File[];\n inputId: string;\n inputRef: RefObject<HTMLInputElement | null>;\n fileState: ((file: File) => UploadFileState | undefined) | undefined;\n maxFiles: number | undefined;\n maxSize: number | undefined;\n multiple: boolean;\n removeFile: (file: File) => void;\n cancelFile: (file: File) => void;\n rejections: UploadRejection[];\n setDropActive: (active: boolean) => void;\n styles: ReturnType<typeof upload>;\n}\n\nconst UploadContext = createContext<UploadContextValue | null>(null);\n\nfunction useUploadContext() {\n const context = useContext(UploadContext);\n if (!context) {\n throw new Error(\"Upload parts must be rendered inside Upload.Root.\");\n }\n\n return context;\n}\n\nfunction fileKey(file: File) {\n return `${file.name}-${file.size}-${file.lastModified}`;\n}\n\nfunction formatBytes(bytes: number) {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction acceptsFile(file: File, accept: string | undefined) {\n if (!accept) {\n return true;\n }\n\n const fileName = file.name.toLowerCase();\n const fileType = file.type.toLowerCase();\n\n return accept.split(\",\").some((entry) => {\n const pattern = entry.trim().toLowerCase();\n if (!pattern) return true;\n if (pattern.startsWith(\".\")) return fileName.endsWith(pattern);\n if (pattern.endsWith(\"/*\")) return fileType.startsWith(pattern.slice(0, -1));\n return pattern === fileType;\n });\n}\n\nexport interface UploadRootProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n /** Accepted MIME types or file extensions, using the native input syntax. */\n accept?: string;\n /** Controlled files. Use with `onFilesChange`. */\n files?: File[];\n /** Initial files for an uncontrolled upload. */\n defaultFiles?: File[];\n /** Called whenever accepted files are added or removed. */\n onFilesChange?: (files: File[]) => void;\n /** Called with files rejected by `accept`, `maxSize`, `maxFiles` or duplicates. */\n onReject?: (rejections: UploadRejection[]) => void;\n /** Maximum number of accepted files. Defaults to one when `multiple` is false. */\n maxFiles?: number;\n /** Maximum size per file, in bytes. */\n maxSize?: number;\n /** Allows selecting more than one file. */\n multiple?: boolean;\n /** Disables file selection and drag-and-drop. */\n disabled?: boolean;\n /** Optional asynchronous validation. Return an error message to reject a file. */\n validateFile?: (file: File) => string | null | Promise<string | null>;\n /** Controlled status used by the status, progress and cancel slots. */\n fileState?: (file: File) => UploadFileState | undefined;\n /** Called when a consumer cancels an upload. */\n onCancel?: (file: File) => void;\n children?: ReactNode;\n}\n\nexport const UploadRoot = forwardRef<HTMLDivElement, UploadRootProps>(function UploadRoot(\n {\n accept,\n fileState,\n children,\n className,\n defaultFiles = [],\n disabled = false,\n files: controlledFiles,\n maxFiles,\n maxSize,\n multiple = false,\n onFilesChange,\n onCancel,\n onReject,\n validateFile,\n ...props\n },\n ref,\n) {\n const [uncontrolledFiles, setUncontrolledFiles] = useState<File[]>(defaultFiles);\n const [dropActive, setDropActive] = useState(false);\n const [rejections, setRejections] = useState<UploadRejection[]>([]);\n const inputRef = useRef<HTMLInputElement>(null);\n const inputId = useId();\n const styles = upload({ disabled, dropActive });\n const currentFiles = controlledFiles ?? uncontrolledFiles;\n const fileLimit = maxFiles ?? (multiple ? undefined : 1);\n\n const updateFiles = useCallback(\n (nextFiles: File[]) => {\n if (controlledFiles === undefined) setUncontrolledFiles(nextFiles);\n onFilesChange?.(nextFiles);\n },\n [controlledFiles, onFilesChange],\n );\n\n const removeFile = useCallback(\n (file: File) => {\n updateFiles(currentFiles.filter((current) => fileKey(current) !== fileKey(file)));\n },\n [currentFiles, updateFiles],\n );\n\n const addFiles = useCallback(\n (fileList: FileList | File[]) => {\n if (disabled) return;\n\n const candidates = Array.from(fileList);\n const acceptedFiles: File[] = [];\n const nextRejections: UploadRejection[] = [];\n const pendingValidations = new Map<File, Promise<string | null>>();\n const existingKeys = new Set(currentFiles.map(fileKey));\n\n for (const file of candidates) {\n const key = fileKey(file);\n if (existingKeys.has(key) || acceptedFiles.some((accepted) => fileKey(accepted) === key)) {\n nextRejections.push({\n file,\n reason: \"duplicate\",\n message: `${file.name} was already added.`,\n });\n continue;\n }\n if (!acceptsFile(file, accept)) {\n nextRejections.push({\n file,\n reason: \"type\",\n message: `${file.name} is not an accepted file type.`,\n });\n continue;\n }\n if (maxSize !== undefined && file.size > maxSize) {\n nextRejections.push({\n file,\n reason: \"size\",\n message: `${file.name} is larger than the allowed limit.`,\n });\n continue;\n }\n if (\n fileLimit !== undefined &&\n (multiple ? currentFiles.length + acceptedFiles.length : acceptedFiles.length) >=\n fileLimit\n ) {\n nextRejections.push({\n file,\n reason: \"count\",\n message: `Only ${fileLimit} file${fileLimit === 1 ? \"\" : \"s\"} can be selected.`,\n });\n continue;\n }\n if (validateFile) {\n const validation = validateFile(file);\n if (validation && typeof validation !== \"object\") {\n nextRejections.push({ file, reason: \"validation\", message: validation });\n continue;\n }\n if (validation && typeof validation === \"object\" && \"then\" in validation) {\n pendingValidations.set(file, Promise.resolve(validation));\n }\n }\n acceptedFiles.push(file);\n }\n\n const nextFiles = multiple ? [...currentFiles, ...acceptedFiles] : acceptedFiles.slice(0, 1);\n if (acceptedFiles.length > 0) {\n updateFiles(nextFiles);\n }\n if (validateFile) {\n for (const file of acceptedFiles) {\n const validation = pendingValidations.get(file);\n if (validation) {\n void validation\n .then((message) => {\n if (!message) return;\n const rejection = { file, reason: \"validation\" as const, message };\n updateFiles(nextFiles.filter((current) => fileKey(current) !== fileKey(file)));\n setRejections((current) => [...current, rejection]);\n onReject?.([rejection]);\n })\n .catch((error: unknown) => {\n const message = error instanceof Error ? error.message : \"File validation failed.\";\n const rejection = { file, reason: \"validation\" as const, message };\n updateFiles(nextFiles.filter((current) => fileKey(current) !== fileKey(file)));\n setRejections((current) => [...current, rejection]);\n onReject?.([rejection]);\n });\n }\n }\n }\n if (nextRejections.length > 0) {\n setRejections(nextRejections);\n onReject?.(nextRejections);\n } else {\n setRejections([]);\n }\n },\n [\n accept,\n currentFiles,\n disabled,\n fileLimit,\n maxSize,\n multiple,\n onReject,\n updateFiles,\n validateFile,\n ],\n );\n\n const cancelFile = useCallback((file: File) => onCancel?.(file), [onCancel]);\n\n const context = useMemo<UploadContextValue>(\n () => ({\n accept,\n addFiles,\n cancelFile,\n disabled,\n dropActive,\n files: currentFiles,\n inputId,\n inputRef,\n fileState,\n maxFiles: fileLimit,\n maxSize,\n multiple,\n removeFile,\n rejections,\n setDropActive,\n styles,\n }),\n [\n accept,\n addFiles,\n cancelFile,\n currentFiles,\n disabled,\n dropActive,\n fileLimit,\n fileState,\n inputId,\n maxSize,\n multiple,\n rejections,\n removeFile,\n styles,\n ],\n );\n\n return (\n <UploadContext.Provider value={context}>\n <div\n {...props}\n ref={ref}\n className={cx(styles.root, className)}\n data-disabled={disabled || undefined}\n data-jaci-component=\"upload\"\n data-slot=\"upload\"\n >\n {children}\n </div>\n </UploadContext.Provider>\n );\n});\n\nexport interface UploadDropzoneProps extends ComponentPropsWithoutRef<\"label\"> {\n children?: ReactNode;\n}\n\nexport const UploadDropzone = forwardRef<HTMLLabelElement, UploadDropzoneProps>(\n function UploadDropzone(\n { children, className, htmlFor, onDragEnter, onDragLeave, onDragOver, onDrop, ...props },\n ref,\n ) {\n const { addFiles, disabled, dropActive, inputId, setDropActive, styles } = useUploadContext();\n\n return (\n <label\n {...props}\n ref={ref}\n aria-disabled={disabled || undefined}\n className={cx(styles.dropzone, className)}\n data-drag-active={dropActive || undefined}\n data-slot=\"upload-dropzone\"\n htmlFor={htmlFor ?? inputId}\n onDragEnter={(event) => {\n event.preventDefault();\n if (!disabled) {\n setDropActive(true);\n event.currentTarget.dataset.dragActive = \"true\";\n }\n onDragEnter?.(event);\n }}\n onDragLeave={(event) => {\n event.preventDefault();\n if (event.currentTarget === event.target) {\n setDropActive(false);\n event.currentTarget.dataset.dragActive = \"false\";\n }\n onDragLeave?.(event);\n }}\n onDragOver={(event) => {\n event.preventDefault();\n if (!disabled) setDropActive(true);\n onDragOver?.(event);\n }}\n onDrop={(event) => {\n event.preventDefault();\n setDropActive(false);\n event.currentTarget.dataset.dragActive = \"false\";\n if (!disabled) addFiles(event.dataTransfer.files);\n onDrop?.(event);\n }}\n >\n {children}\n </label>\n );\n },\n);\n\nexport type UploadInputProps = ComponentPropsWithoutRef<\"input\">;\n\nexport const UploadInput = forwardRef<HTMLInputElement, UploadInputProps>(function UploadInput(\n { accept, className, id, multiple, onChange, ...props },\n ref,\n) {\n const {\n addFiles,\n accept: rootAccept,\n disabled,\n inputId,\n inputRef,\n multiple: rootMultiple,\n styles,\n } = useUploadContext();\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n if (event.currentTarget.files) addFiles(event.currentTarget.files);\n event.currentTarget.value = \"\";\n onChange?.(event);\n };\n\n return (\n <input\n {...props}\n accept={accept ?? rootAccept}\n aria-label={props[\"aria-label\"] ?? \"Select files\"}\n className={cx(styles.input, className)}\n disabled={disabled}\n id={id ?? inputId}\n multiple={multiple ?? rootMultiple}\n onChange={handleChange}\n ref={(node) => {\n inputRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }}\n tabIndex={-1}\n type=\"file\"\n />\n );\n});\n\nexport type UploadTriggerProps = ComponentPropsWithoutRef<\"button\">;\n\nexport const UploadTrigger = forwardRef<HTMLButtonElement, UploadTriggerProps>(\n function UploadTrigger(\n { children = \"Choose files\", className, disabled, onClick, ...props },\n ref,\n ) {\n const { disabled: rootDisabled, inputRef, styles } = useUploadContext();\n\n return (\n <button\n {...props}\n className={cx(styles.trigger, className)}\n data-slot=\"upload-trigger\"\n disabled={disabled ?? rootDisabled}\n onClick={(event) => {\n inputRef.current?.click();\n onClick?.(event);\n }}\n ref={ref}\n type=\"button\"\n >\n {children}\n </button>\n );\n },\n);\n\nexport type UploadIconProps = ComponentPropsWithoutRef<\"span\">;\n\nexport const UploadIcon = forwardRef<HTMLSpanElement, UploadIconProps>(function UploadIcon(\n { children = \"↥\", className, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n return (\n <span\n {...props}\n ref={ref}\n aria-hidden=\"true\"\n className={cx(styles.icon, className)}\n data-slot=\"upload-icon\"\n >\n {children}\n </span>\n );\n});\n\nexport type UploadTextProps = ComponentPropsWithoutRef<\"span\">;\n\nexport const UploadText = forwardRef<HTMLSpanElement, UploadTextProps>(function UploadText(\n { className, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n return (\n <span {...props} ref={ref} className={cx(styles.text, className)} data-slot=\"upload-text\" />\n );\n});\n\nexport type UploadHintProps = ComponentPropsWithoutRef<\"span\">;\n\nexport const UploadHint = forwardRef<HTMLSpanElement, UploadHintProps>(function UploadHint(\n { className, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n return (\n <span {...props} ref={ref} className={cx(styles.hint, className)} data-slot=\"upload-hint\" />\n );\n});\n\nexport interface UploadPreviewProps extends ComponentPropsWithoutRef<\"span\"> {\n /** File whose preview should be rendered. Image files use a temporary object URL. */\n file: File;\n /** Alternative text for image previews. Defaults to the file name. */\n alt?: string;\n /** Content rendered while the preview is unavailable or the file is not an image. */\n fallback?: ReactNode;\n}\n\nexport const UploadPreview = forwardRef<HTMLSpanElement, UploadPreviewProps>(function UploadPreview(\n { alt, className, fallback = \"Preview unavailable\", file, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n const [src, setSrc] = useState<string | null>(null);\n\n useEffect(() => {\n if (\n !file.type.startsWith(\"image/\") ||\n typeof URL === \"undefined\" ||\n typeof URL.createObjectURL !== \"function\"\n ) {\n setSrc(null);\n return;\n }\n\n const objectUrl = URL.createObjectURL(file);\n setSrc(objectUrl);\n return () => URL.revokeObjectURL(objectUrl);\n }, [file]);\n\n return (\n <span\n {...props}\n ref={ref}\n aria-hidden={props[\"aria-label\"] ? undefined : true}\n className={cx(styles.preview, className)}\n data-slot=\"upload-preview\"\n role={props[\"aria-label\"] ? \"img\" : undefined}\n >\n {src ? <img alt={alt ?? file.name} src={src} /> : fallback}\n </span>\n );\n});\n\nexport interface UploadProgressProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /** Progress from 0 to 100. Omit it for an indeterminate upload. */\n value?: number;\n /** Accessible label and optional visible status text. */\n label?: ReactNode;\n file?: File;\n}\n\nexport const UploadProgress = forwardRef<HTMLDivElement, UploadProgressProps>(\n function UploadProgress({ className, file, label = \"Uploading\", value, ...props }, ref) {\n const { fileState, styles } = useUploadContext();\n const state = file ? fileState?.(file) : undefined;\n const normalizedValue =\n value === undefined\n ? state?.progress === undefined\n ? undefined\n : Math.min(100, Math.max(0, state.progress))\n : Math.min(100, Math.max(0, value));\n\n return (\n <div\n {...props}\n ref={ref}\n aria-label={typeof label === \"string\" ? label : \"Upload progress\"}\n aria-valuemax={100}\n aria-valuemin={0}\n aria-valuenow={normalizedValue}\n className={cx(styles.progress, className)}\n data-indeterminate={normalizedValue === undefined || undefined}\n data-slot=\"upload-progress\"\n role=\"progressbar\"\n >\n <span className={styles.progressTrack} data-slot=\"upload-progress-track\">\n <span\n className={styles.progressIndicator}\n data-indeterminate={normalizedValue === undefined || undefined}\n data-slot=\"upload-progress-indicator\"\n style={{ width: normalizedValue === undefined ? undefined : `${normalizedValue}%` }}\n />\n </span>\n <span className={styles.progressLabel} data-slot=\"upload-progress-label\">\n {label}\n </span>\n </div>\n );\n },\n);\n\nexport type UploadListProps = ComponentPropsWithoutRef<\"ul\">;\n\nexport const UploadList = forwardRef<HTMLUListElement, UploadListProps>(function UploadList(\n { children, className, ...props },\n ref,\n) {\n const { files, styles } = useUploadContext();\n return (\n <ul {...props} ref={ref} className={cx(styles.list, className)} data-slot=\"upload-list\">\n {children ?? files.map((file) => <UploadItem file={file} key={fileKey(file)} />)}\n </ul>\n );\n});\n\nexport interface UploadItemProps extends Omit<ComponentPropsWithoutRef<\"li\">, \"children\"> {\n file: File;\n children?: ReactNode;\n}\n\nexport const UploadItem = forwardRef<HTMLLIElement, UploadItemProps>(function UploadItem(\n { children, className, file, ...props },\n ref,\n) {\n const { styles } = useUploadContext();\n return (\n <li {...props} ref={ref} className={cx(styles.item, className)} data-slot=\"upload-item\">\n {children ?? (\n <>\n <span className={styles.itemName} data-slot=\"upload-item-name\" title={file.name}>\n {file.name}\n </span>\n <span className={styles.itemMeta} data-slot=\"upload-item-meta\">\n {formatBytes(file.size)}\n </span>\n <UploadRemove file={file} />\n </>\n )}\n </li>\n );\n});\n\nexport interface UploadRemoveProps extends ComponentPropsWithoutRef<\"button\"> {\n file: File;\n}\n\nexport const UploadRemove = forwardRef<HTMLButtonElement, UploadRemoveProps>(function UploadRemove(\n { children = \"×\", className, file, onClick, ...props },\n ref,\n) {\n const { disabled, removeFile, styles } = useUploadContext();\n return (\n <button\n {...props}\n aria-label={props[\"aria-label\"] ?? `Remove ${file.name}`}\n className={cx(styles.remove, className)}\n data-slot=\"upload-remove\"\n disabled={disabled}\n onClick={(event) => {\n removeFile(file);\n onClick?.(event);\n }}\n ref={ref}\n type=\"button\"\n >\n {children}\n </button>\n );\n});\n\nexport interface UploadStatusProps extends ComponentPropsWithoutRef<\"span\"> {\n file: File;\n}\n\nexport const UploadStatus = forwardRef<HTMLSpanElement, UploadStatusProps>(function UploadStatus(\n { children, className, file, ...props },\n ref,\n) {\n const { fileState, styles } = useUploadContext();\n const state = fileState?.(file);\n const content = children ?? state?.error ?? state?.status ?? \"queued\";\n return (\n <span\n {...props}\n aria-live=\"polite\"\n className={cx(styles.status, className)}\n data-status={state?.status}\n data-slot=\"upload-status\"\n ref={ref}\n >\n {content}\n </span>\n );\n});\n\nexport interface UploadCancelProps extends ComponentPropsWithoutRef<\"button\"> {\n file: File;\n}\n\nexport const UploadCancel = forwardRef<HTMLButtonElement, UploadCancelProps>(function UploadCancel(\n { children = \"Cancel\", className, file, onClick, ...props },\n ref,\n) {\n const { cancelFile, disabled, fileState, styles } = useUploadContext();\n const state = fileState?.(file);\n return (\n <button\n {...props}\n aria-label={props[\"aria-label\"] ?? `Cancel ${file.name}`}\n className={cx(styles.cancel, className)}\n data-slot=\"upload-cancel\"\n disabled={disabled || state?.status === \"canceled\" || state?.status === \"success\"}\n onClick={(event) => {\n cancelFile(file);\n onClick?.(event);\n }}\n ref={ref}\n type=\"button\"\n >\n {children}\n </button>\n );\n});\n\nexport type UploadErrorProps = ComponentPropsWithoutRef<\"p\">;\n\nexport const UploadError = forwardRef<HTMLParagraphElement, UploadErrorProps>(function UploadError(\n { children, className, ...props },\n ref,\n) {\n const { rejections, styles } = useUploadContext();\n if (children === undefined && rejections.length === 0) return null;\n\n return (\n <p\n {...props}\n ref={ref}\n className={cx(styles.error, className)}\n data-slot=\"upload-error\"\n role=\"alert\"\n >\n {children ?? rejections.map((rejection) => rejection.message).join(\" \")}\n </p>\n );\n});\n\nexport const Upload = {\n Root: UploadRoot,\n Dropzone: UploadDropzone,\n Input: UploadInput,\n Trigger: UploadTrigger,\n Icon: UploadIcon,\n Text: UploadText,\n Hint: UploadHint,\n Preview: UploadPreview,\n Progress: UploadProgress,\n List: UploadList,\n Item: UploadItem,\n Remove: UploadRemove,\n Status: UploadStatus,\n Cancel: UploadCancel,\n Error: UploadError,\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
2
|
//#region src/components/upload/upload.d.ts
|
|
3
|
-
type UploadRejectionReason = "type" | "size" | "count" | "duplicate";
|
|
3
|
+
type UploadRejectionReason = "type" | "size" | "count" | "duplicate" | "validation";
|
|
4
|
+
type UploadFileStatus = "queued" | "uploading" | "success" | "error" | "canceled";
|
|
5
|
+
interface UploadFileState {
|
|
6
|
+
status: UploadFileStatus;
|
|
7
|
+
progress?: number;
|
|
8
|
+
error?: ReactNode;
|
|
9
|
+
}
|
|
4
10
|
interface UploadRejection {
|
|
5
11
|
file: File;
|
|
6
12
|
message: string;
|
|
@@ -25,6 +31,12 @@ interface UploadRootProps extends Omit<ComponentPropsWithoutRef<"div">, "onChang
|
|
|
25
31
|
multiple?: boolean;
|
|
26
32
|
/** Disables file selection and drag-and-drop. */
|
|
27
33
|
disabled?: boolean;
|
|
34
|
+
/** Optional asynchronous validation. Return an error message to reject a file. */
|
|
35
|
+
validateFile?: (file: File) => string | null | Promise<string | null>;
|
|
36
|
+
/** Controlled status used by the status, progress and cancel slots. */
|
|
37
|
+
fileState?: (file: File) => UploadFileState | undefined;
|
|
38
|
+
/** Called when a consumer cancels an upload. */
|
|
39
|
+
onCancel?: (file: File) => void;
|
|
28
40
|
children?: ReactNode;
|
|
29
41
|
}
|
|
30
42
|
declare const UploadRoot: import("react").ForwardRefExoticComponent<UploadRootProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -56,6 +68,7 @@ interface UploadProgressProps extends Omit<ComponentPropsWithoutRef<"div">, "chi
|
|
|
56
68
|
value?: number;
|
|
57
69
|
/** Accessible label and optional visible status text. */
|
|
58
70
|
label?: ReactNode;
|
|
71
|
+
file?: File;
|
|
59
72
|
}
|
|
60
73
|
declare const UploadProgress: import("react").ForwardRefExoticComponent<UploadProgressProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
61
74
|
type UploadListProps = ComponentPropsWithoutRef<"ul">;
|
|
@@ -69,6 +82,14 @@ interface UploadRemoveProps extends ComponentPropsWithoutRef<"button"> {
|
|
|
69
82
|
file: File;
|
|
70
83
|
}
|
|
71
84
|
declare const UploadRemove: import("react").ForwardRefExoticComponent<UploadRemoveProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
85
|
+
interface UploadStatusProps extends ComponentPropsWithoutRef<"span"> {
|
|
86
|
+
file: File;
|
|
87
|
+
}
|
|
88
|
+
declare const UploadStatus: import("react").ForwardRefExoticComponent<UploadStatusProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
89
|
+
interface UploadCancelProps extends ComponentPropsWithoutRef<"button"> {
|
|
90
|
+
file: File;
|
|
91
|
+
}
|
|
92
|
+
declare const UploadCancel: import("react").ForwardRefExoticComponent<UploadCancelProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
72
93
|
type UploadErrorProps = ComponentPropsWithoutRef<"p">;
|
|
73
94
|
declare const UploadError: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
|
|
74
95
|
declare const Upload: {
|
|
@@ -84,8 +105,10 @@ declare const Upload: {
|
|
|
84
105
|
List: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLUListElement>, HTMLUListElement>, "ref"> & import("react").RefAttributes<HTMLUListElement>>;
|
|
85
106
|
Item: import("react").ForwardRefExoticComponent<UploadItemProps & import("react").RefAttributes<HTMLLIElement>>;
|
|
86
107
|
Remove: import("react").ForwardRefExoticComponent<UploadRemoveProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
108
|
+
Status: import("react").ForwardRefExoticComponent<UploadStatusProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
109
|
+
Cancel: import("react").ForwardRefExoticComponent<UploadCancelProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
87
110
|
Error: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
|
|
88
111
|
};
|
|
89
112
|
//#endregion
|
|
90
|
-
export { Upload, UploadDropzone, UploadDropzoneProps, UploadError, UploadErrorProps, UploadHint, UploadHintProps, UploadIcon, UploadIconProps, UploadInput, UploadInputProps, UploadItem, UploadItemProps, UploadList, UploadListProps, UploadPreview, UploadPreviewProps, UploadProgress, UploadProgressProps, UploadRejection, UploadRejectionReason, UploadRemove, UploadRemoveProps, UploadRoot, UploadRootProps, UploadText, UploadTextProps, UploadTrigger, UploadTriggerProps };
|
|
113
|
+
export { Upload, UploadCancel, UploadCancelProps, UploadDropzone, UploadDropzoneProps, UploadError, UploadErrorProps, UploadFileState, UploadFileStatus, UploadHint, UploadHintProps, UploadIcon, UploadIconProps, UploadInput, UploadInputProps, UploadItem, UploadItemProps, UploadList, UploadListProps, UploadPreview, UploadPreviewProps, UploadProgress, UploadProgressProps, UploadRejection, UploadRejectionReason, UploadRemove, UploadRemoveProps, UploadRoot, UploadRootProps, UploadStatus, UploadStatusProps, UploadText, UploadTextProps, UploadTrigger, UploadTriggerProps };
|
|
91
114
|
//# sourceMappingURL=upload.d.cts.map
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
2
|
//#region src/components/upload/upload.d.ts
|
|
3
|
-
type UploadRejectionReason = "type" | "size" | "count" | "duplicate";
|
|
3
|
+
type UploadRejectionReason = "type" | "size" | "count" | "duplicate" | "validation";
|
|
4
|
+
type UploadFileStatus = "queued" | "uploading" | "success" | "error" | "canceled";
|
|
5
|
+
interface UploadFileState {
|
|
6
|
+
status: UploadFileStatus;
|
|
7
|
+
progress?: number;
|
|
8
|
+
error?: ReactNode;
|
|
9
|
+
}
|
|
4
10
|
interface UploadRejection {
|
|
5
11
|
file: File;
|
|
6
12
|
message: string;
|
|
@@ -25,6 +31,12 @@ interface UploadRootProps extends Omit<ComponentPropsWithoutRef<"div">, "onChang
|
|
|
25
31
|
multiple?: boolean;
|
|
26
32
|
/** Disables file selection and drag-and-drop. */
|
|
27
33
|
disabled?: boolean;
|
|
34
|
+
/** Optional asynchronous validation. Return an error message to reject a file. */
|
|
35
|
+
validateFile?: (file: File) => string | null | Promise<string | null>;
|
|
36
|
+
/** Controlled status used by the status, progress and cancel slots. */
|
|
37
|
+
fileState?: (file: File) => UploadFileState | undefined;
|
|
38
|
+
/** Called when a consumer cancels an upload. */
|
|
39
|
+
onCancel?: (file: File) => void;
|
|
28
40
|
children?: ReactNode;
|
|
29
41
|
}
|
|
30
42
|
declare const UploadRoot: import("react").ForwardRefExoticComponent<UploadRootProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -56,6 +68,7 @@ interface UploadProgressProps extends Omit<ComponentPropsWithoutRef<"div">, "chi
|
|
|
56
68
|
value?: number;
|
|
57
69
|
/** Accessible label and optional visible status text. */
|
|
58
70
|
label?: ReactNode;
|
|
71
|
+
file?: File;
|
|
59
72
|
}
|
|
60
73
|
declare const UploadProgress: import("react").ForwardRefExoticComponent<UploadProgressProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
61
74
|
type UploadListProps = ComponentPropsWithoutRef<"ul">;
|
|
@@ -69,6 +82,14 @@ interface UploadRemoveProps extends ComponentPropsWithoutRef<"button"> {
|
|
|
69
82
|
file: File;
|
|
70
83
|
}
|
|
71
84
|
declare const UploadRemove: import("react").ForwardRefExoticComponent<UploadRemoveProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
85
|
+
interface UploadStatusProps extends ComponentPropsWithoutRef<"span"> {
|
|
86
|
+
file: File;
|
|
87
|
+
}
|
|
88
|
+
declare const UploadStatus: import("react").ForwardRefExoticComponent<UploadStatusProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
89
|
+
interface UploadCancelProps extends ComponentPropsWithoutRef<"button"> {
|
|
90
|
+
file: File;
|
|
91
|
+
}
|
|
92
|
+
declare const UploadCancel: import("react").ForwardRefExoticComponent<UploadCancelProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
72
93
|
type UploadErrorProps = ComponentPropsWithoutRef<"p">;
|
|
73
94
|
declare const UploadError: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
|
|
74
95
|
declare const Upload: {
|
|
@@ -84,8 +105,10 @@ declare const Upload: {
|
|
|
84
105
|
List: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLUListElement>, HTMLUListElement>, "ref"> & import("react").RefAttributes<HTMLUListElement>>;
|
|
85
106
|
Item: import("react").ForwardRefExoticComponent<UploadItemProps & import("react").RefAttributes<HTMLLIElement>>;
|
|
86
107
|
Remove: import("react").ForwardRefExoticComponent<UploadRemoveProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
108
|
+
Status: import("react").ForwardRefExoticComponent<UploadStatusProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
109
|
+
Cancel: import("react").ForwardRefExoticComponent<UploadCancelProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
87
110
|
Error: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
|
|
88
111
|
};
|
|
89
112
|
//#endregion
|
|
90
|
-
export { Upload, UploadDropzone, UploadDropzoneProps, UploadError, UploadErrorProps, UploadHint, UploadHintProps, UploadIcon, UploadIconProps, UploadInput, UploadInputProps, UploadItem, UploadItemProps, UploadList, UploadListProps, UploadPreview, UploadPreviewProps, UploadProgress, UploadProgressProps, UploadRejection, UploadRejectionReason, UploadRemove, UploadRemoveProps, UploadRoot, UploadRootProps, UploadText, UploadTextProps, UploadTrigger, UploadTriggerProps };
|
|
113
|
+
export { Upload, UploadCancel, UploadCancelProps, UploadDropzone, UploadDropzoneProps, UploadError, UploadErrorProps, UploadFileState, UploadFileStatus, UploadHint, UploadHintProps, UploadIcon, UploadIconProps, UploadInput, UploadInputProps, UploadItem, UploadItemProps, UploadList, UploadListProps, UploadPreview, UploadPreviewProps, UploadProgress, UploadProgressProps, UploadRejection, UploadRejectionReason, UploadRemove, UploadRemoveProps, UploadRoot, UploadRootProps, UploadStatus, UploadStatusProps, UploadText, UploadTextProps, UploadTrigger, UploadTriggerProps };
|
|
91
114
|
//# sourceMappingURL=upload.d.ts.map
|
|
@@ -30,7 +30,7 @@ function acceptsFile(file, accept) {
|
|
|
30
30
|
return pattern === fileType;
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
-
const UploadRoot = forwardRef(function UploadRoot({ accept, children, className, defaultFiles = [], disabled = false, files: controlledFiles, maxFiles, maxSize, multiple = false, onFilesChange, onReject, ...props }, ref) {
|
|
33
|
+
const UploadRoot = forwardRef(function UploadRoot({ accept, fileState, children, className, defaultFiles = [], disabled = false, files: controlledFiles, maxFiles, maxSize, multiple = false, onFilesChange, onCancel, onReject, validateFile, ...props }, ref) {
|
|
34
34
|
const [uncontrolledFiles, setUncontrolledFiles] = useState(defaultFiles);
|
|
35
35
|
const [dropActive, setDropActive] = useState(false);
|
|
36
36
|
const [rejections, setRejections] = useState([]);
|
|
@@ -43,14 +43,18 @@ const UploadRoot = forwardRef(function UploadRoot({ accept, children, className,
|
|
|
43
43
|
const currentFiles = controlledFiles ?? uncontrolledFiles;
|
|
44
44
|
const fileLimit = maxFiles ?? (multiple ? void 0 : 1);
|
|
45
45
|
const updateFiles = useCallback((nextFiles) => {
|
|
46
|
-
setUncontrolledFiles(nextFiles);
|
|
46
|
+
if (controlledFiles === void 0) setUncontrolledFiles(nextFiles);
|
|
47
47
|
onFilesChange?.(nextFiles);
|
|
48
|
-
}, [onFilesChange]);
|
|
48
|
+
}, [controlledFiles, onFilesChange]);
|
|
49
|
+
const removeFile = useCallback((file) => {
|
|
50
|
+
updateFiles(currentFiles.filter((current) => fileKey(current) !== fileKey(file)));
|
|
51
|
+
}, [currentFiles, updateFiles]);
|
|
49
52
|
const addFiles = useCallback((fileList) => {
|
|
50
53
|
if (disabled) return;
|
|
51
54
|
const candidates = Array.from(fileList);
|
|
52
55
|
const acceptedFiles = [];
|
|
53
56
|
const nextRejections = [];
|
|
57
|
+
const pendingValidations = /* @__PURE__ */ new Map();
|
|
54
58
|
const existingKeys = new Set(currentFiles.map(fileKey));
|
|
55
59
|
for (const file of candidates) {
|
|
56
60
|
const key = fileKey(file);
|
|
@@ -86,10 +90,46 @@ const UploadRoot = forwardRef(function UploadRoot({ accept, children, className,
|
|
|
86
90
|
});
|
|
87
91
|
continue;
|
|
88
92
|
}
|
|
93
|
+
if (validateFile) {
|
|
94
|
+
const validation = validateFile(file);
|
|
95
|
+
if (validation && typeof validation !== "object") {
|
|
96
|
+
nextRejections.push({
|
|
97
|
+
file,
|
|
98
|
+
reason: "validation",
|
|
99
|
+
message: validation
|
|
100
|
+
});
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (validation && typeof validation === "object" && "then" in validation) pendingValidations.set(file, Promise.resolve(validation));
|
|
104
|
+
}
|
|
89
105
|
acceptedFiles.push(file);
|
|
90
106
|
}
|
|
91
107
|
const nextFiles = multiple ? [...currentFiles, ...acceptedFiles] : acceptedFiles.slice(0, 1);
|
|
92
108
|
if (acceptedFiles.length > 0) updateFiles(nextFiles);
|
|
109
|
+
if (validateFile) for (const file of acceptedFiles) {
|
|
110
|
+
const validation = pendingValidations.get(file);
|
|
111
|
+
if (validation) validation.then((message) => {
|
|
112
|
+
if (!message) return;
|
|
113
|
+
const rejection = {
|
|
114
|
+
file,
|
|
115
|
+
reason: "validation",
|
|
116
|
+
message
|
|
117
|
+
};
|
|
118
|
+
updateFiles(nextFiles.filter((current) => fileKey(current) !== fileKey(file)));
|
|
119
|
+
setRejections((current) => [...current, rejection]);
|
|
120
|
+
onReject?.([rejection]);
|
|
121
|
+
}).catch((error) => {
|
|
122
|
+
const message = error instanceof Error ? error.message : "File validation failed.";
|
|
123
|
+
const rejection = {
|
|
124
|
+
file,
|
|
125
|
+
reason: "validation",
|
|
126
|
+
message
|
|
127
|
+
};
|
|
128
|
+
updateFiles(nextFiles.filter((current) => fileKey(current) !== fileKey(file)));
|
|
129
|
+
setRejections((current) => [...current, rejection]);
|
|
130
|
+
onReject?.([rejection]);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
93
133
|
if (nextRejections.length > 0) {
|
|
94
134
|
setRejections(nextRejections);
|
|
95
135
|
onReject?.(nextRejections);
|
|
@@ -102,19 +142,20 @@ const UploadRoot = forwardRef(function UploadRoot({ accept, children, className,
|
|
|
102
142
|
maxSize,
|
|
103
143
|
multiple,
|
|
104
144
|
onReject,
|
|
105
|
-
updateFiles
|
|
145
|
+
updateFiles,
|
|
146
|
+
validateFile
|
|
106
147
|
]);
|
|
107
|
-
const
|
|
108
|
-
updateFiles(currentFiles.filter((current) => fileKey(current) !== fileKey(file)));
|
|
109
|
-
}, [currentFiles, updateFiles]);
|
|
148
|
+
const cancelFile = useCallback((file) => onCancel?.(file), [onCancel]);
|
|
110
149
|
const context = useMemo(() => ({
|
|
111
150
|
accept,
|
|
112
151
|
addFiles,
|
|
152
|
+
cancelFile,
|
|
113
153
|
disabled,
|
|
114
154
|
dropActive,
|
|
115
155
|
files: currentFiles,
|
|
116
156
|
inputId,
|
|
117
157
|
inputRef,
|
|
158
|
+
fileState,
|
|
118
159
|
maxFiles: fileLimit,
|
|
119
160
|
maxSize,
|
|
120
161
|
multiple,
|
|
@@ -125,10 +166,12 @@ const UploadRoot = forwardRef(function UploadRoot({ accept, children, className,
|
|
|
125
166
|
}), [
|
|
126
167
|
accept,
|
|
127
168
|
addFiles,
|
|
169
|
+
cancelFile,
|
|
128
170
|
currentFiles,
|
|
129
171
|
disabled,
|
|
130
172
|
dropActive,
|
|
131
173
|
fileLimit,
|
|
174
|
+
fileState,
|
|
132
175
|
inputId,
|
|
133
176
|
maxSize,
|
|
134
177
|
multiple,
|
|
@@ -285,9 +328,10 @@ const UploadPreview = forwardRef(function UploadPreview({ alt, className, fallba
|
|
|
285
328
|
}) : fallback
|
|
286
329
|
});
|
|
287
330
|
});
|
|
288
|
-
const UploadProgress = forwardRef(function UploadProgress({ className, label = "Uploading", value, ...props }, ref) {
|
|
289
|
-
const { styles } = useUploadContext();
|
|
290
|
-
const
|
|
331
|
+
const UploadProgress = forwardRef(function UploadProgress({ className, file, label = "Uploading", value, ...props }, ref) {
|
|
332
|
+
const { fileState, styles } = useUploadContext();
|
|
333
|
+
const state = file ? fileState?.(file) : void 0;
|
|
334
|
+
const normalizedValue = value === void 0 ? state?.progress === void 0 ? void 0 : Math.min(100, Math.max(0, state.progress)) : Math.min(100, Math.max(0, value));
|
|
291
335
|
return /* @__PURE__ */ jsxs("div", {
|
|
292
336
|
...props,
|
|
293
337
|
ref,
|
|
@@ -365,6 +409,38 @@ const UploadRemove = forwardRef(function UploadRemove({ children = "×", classNa
|
|
|
365
409
|
children
|
|
366
410
|
});
|
|
367
411
|
});
|
|
412
|
+
const UploadStatus = forwardRef(function UploadStatus({ children, className, file, ...props }, ref) {
|
|
413
|
+
const { fileState, styles } = useUploadContext();
|
|
414
|
+
const state = fileState?.(file);
|
|
415
|
+
const content = children ?? state?.error ?? state?.status ?? "queued";
|
|
416
|
+
return /* @__PURE__ */ jsx("span", {
|
|
417
|
+
...props,
|
|
418
|
+
"aria-live": "polite",
|
|
419
|
+
className: cx(styles.status, className),
|
|
420
|
+
"data-status": state?.status,
|
|
421
|
+
"data-slot": "upload-status",
|
|
422
|
+
ref,
|
|
423
|
+
children: content
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
const UploadCancel = forwardRef(function UploadCancel({ children = "Cancel", className, file, onClick, ...props }, ref) {
|
|
427
|
+
const { cancelFile, disabled, fileState, styles } = useUploadContext();
|
|
428
|
+
const state = fileState?.(file);
|
|
429
|
+
return /* @__PURE__ */ jsx("button", {
|
|
430
|
+
...props,
|
|
431
|
+
"aria-label": props["aria-label"] ?? `Cancel ${file.name}`,
|
|
432
|
+
className: cx(styles.cancel, className),
|
|
433
|
+
"data-slot": "upload-cancel",
|
|
434
|
+
disabled: disabled || state?.status === "canceled" || state?.status === "success",
|
|
435
|
+
onClick: (event) => {
|
|
436
|
+
cancelFile(file);
|
|
437
|
+
onClick?.(event);
|
|
438
|
+
},
|
|
439
|
+
ref,
|
|
440
|
+
type: "button",
|
|
441
|
+
children
|
|
442
|
+
});
|
|
443
|
+
});
|
|
368
444
|
const UploadError = forwardRef(function UploadError({ children, className, ...props }, ref) {
|
|
369
445
|
const { rejections, styles } = useUploadContext();
|
|
370
446
|
if (children === void 0 && rejections.length === 0) return null;
|
|
@@ -390,9 +466,11 @@ const Upload = {
|
|
|
390
466
|
List: UploadList,
|
|
391
467
|
Item: UploadItem,
|
|
392
468
|
Remove: UploadRemove,
|
|
469
|
+
Status: UploadStatus,
|
|
470
|
+
Cancel: UploadCancel,
|
|
393
471
|
Error: UploadError
|
|
394
472
|
};
|
|
395
473
|
//#endregion
|
|
396
|
-
export { Upload, UploadDropzone, UploadError, UploadHint, UploadIcon, UploadInput, UploadItem, UploadList, UploadPreview, UploadProgress, UploadRemove, UploadRoot, UploadText, UploadTrigger };
|
|
474
|
+
export { Upload, UploadCancel, UploadDropzone, UploadError, UploadHint, UploadIcon, UploadInput, UploadItem, UploadList, UploadPreview, UploadProgress, UploadRemove, UploadRoot, UploadStatus, UploadText, UploadTrigger };
|
|
397
475
|
|
|
398
476
|
//# sourceMappingURL=upload.js.map
|