1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
4 |
|
5 | var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
|
6 | var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties');
|
7 | var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
|
8 | var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
|
9 | var css = require('@emotion/css');
|
10 | var a11y = require('@spark-web/a11y');
|
11 | var alert = require('@spark-web/alert');
|
12 | var box = require('@spark-web/box');
|
13 | var field = require('@spark-web/field');
|
14 | var icon = require('@spark-web/icon');
|
15 | var stack = require('@spark-web/stack');
|
16 | var text = require('@spark-web/text');
|
17 | var textList = require('@spark-web/text-list');
|
18 | var theme = require('@spark-web/theme');
|
19 | var utils = require('@spark-web/utils');
|
20 | var react = require('react');
|
21 | var reactDropzone = require('react-dropzone');
|
22 | var jsxRuntime = require('react/jsx-runtime');
|
23 |
|
24 | var _excluded = ["role", "tabIndex"],
|
25 | _excluded2 = ["style"];
|
26 | var Dropzone = react.forwardRef(function (_ref, forwardedRef) {
|
27 | var _fileError$errors$;
|
28 | var accept = _ref.accept,
|
29 | _ref$maxFiles = _ref.maxFiles,
|
30 | maxFiles = _ref$maxFiles === void 0 ? 1 : _ref$maxFiles,
|
31 | maxFileSizeKb = _ref.maxFileSizeKb,
|
32 | minFileSizeKb = _ref.minFileSizeKb,
|
33 | name = _ref.name,
|
34 | onBlur = _ref.onBlur,
|
35 | onChange = _ref.onChange,
|
36 | showImageThumbnails = _ref.showImageThumbnails,
|
37 | multiple = _ref.multiple;
|
38 | var _useState = react.useState([]),
|
39 | _useState2 = _slicedToArray(_useState, 2),
|
40 | files = _useState2[0],
|
41 | setFiles = _useState2[1];
|
42 | var _useState3 = react.useState(),
|
43 | _useState4 = _slicedToArray(_useState3, 2),
|
44 | fileError = _useState4[0],
|
45 | setFileError = _useState4[1];
|
46 | var handleRemoveFile = function handleRemoveFile(id) {
|
47 | setFiles(function (previousFiles) {
|
48 | return previousFiles.filter(function (existingFile) {
|
49 | return existingFile.id !== id;
|
50 | });
|
51 | });
|
52 | };
|
53 | var tooManyFilesErrorMessage = react.useMemo(function () {
|
54 | return {
|
55 | type: 'too-many-files',
|
56 | errors: [{
|
57 | message: 'We can’t upload anymore files as there’s too many files. ' + "The maximum number of files is ".concat(maxFiles, ". ") + 'Please remove a file before trying again.'
|
58 | }]
|
59 | };
|
60 | }, [maxFiles]);
|
61 | var handleDropAccepted = function handleDropAccepted(acceptedFiles) {
|
62 | var totalFiles = files.length + acceptedFiles.length;
|
63 | if (maxFiles > 0 && totalFiles > maxFiles) {
|
64 | setFileError(tooManyFilesErrorMessage);
|
65 | return;
|
66 | }
|
67 | setFiles(function (previousFiles) {
|
68 | return [].concat(_toConsumableArray(previousFiles), _toConsumableArray(acceptedFiles.map(function (acceptedFile, index) {
|
69 | return Object.assign(acceptedFile, {
|
70 | id: files.length === 0 ? index + 1 : files.length + index + 1,
|
71 | preview: acceptedFile.type.startsWith('image') ? URL.createObjectURL(acceptedFile) : undefined
|
72 | });
|
73 | })));
|
74 | });
|
75 | };
|
76 | var _useFieldContext = field.useFieldContext(),
|
77 | _useFieldContext2 = _slicedToArray(_useFieldContext, 2),
|
78 | _useFieldContext2$ = _useFieldContext2[0],
|
79 | disabled = _useFieldContext2$.disabled,
|
80 | invalid = _useFieldContext2$.invalid,
|
81 | a11yProps = _useFieldContext2[1];
|
82 | var _useDropzone = reactDropzone.useDropzone({
|
83 | accept: accept,
|
84 | maxFiles: maxFiles,
|
85 | maxSize: maxFileSizeKb && maxFileSizeKb * 1000,
|
86 | minSize: minFileSizeKb && minFileSizeKb * 1000,
|
87 |
|
88 | multiple: multiple !== undefined ? multiple : maxFiles !== 1,
|
89 | onDropAccepted: handleDropAccepted,
|
90 | disabled: disabled
|
91 | }),
|
92 | fileRejections = _useDropzone.fileRejections,
|
93 | getInputProps = _useDropzone.getInputProps,
|
94 | getRootProps = _useDropzone.getRootProps,
|
95 | isDragActive = _useDropzone.isDragActive,
|
96 | isDragReject = _useDropzone.isDragReject,
|
97 | dropzoneInputRef = _useDropzone.inputRef;
|
98 | var _getRootProps = getRootProps();
|
99 | _getRootProps.role;
|
100 | _getRootProps.tabIndex;
|
101 | var dropzoneProps = _objectWithoutProperties(_getRootProps, _excluded);
|
102 | var _getInputProps = getInputProps();
|
103 | _getInputProps.style;
|
104 | var dropzoneInputProps = _objectWithoutProperties(_getInputProps, _excluded2);
|
105 |
|
106 |
|
107 | react.useEffect(function () {
|
108 | onChange === null || onChange === void 0 || onChange({
|
109 | target: {
|
110 | value: files,
|
111 | name: name
|
112 | },
|
113 | type: 'change'
|
114 | });
|
115 | onBlur === null || onBlur === void 0 || onBlur({
|
116 | target: {
|
117 | value: files,
|
118 | name: name
|
119 | },
|
120 | type: 'blur'
|
121 | });
|
122 | }, [files, name, onBlur, onChange]);
|
123 | react.useEffect(function () {
|
124 | var errorMessage = {
|
125 | errors: []
|
126 | };
|
127 | if (fileRejections.length < 1) {
|
128 | return;
|
129 | }
|
130 | if (maxFiles > 0 && fileRejections.length > maxFiles) {
|
131 | errorMessage.type = tooManyFilesErrorMessage.type;
|
132 | errorMessage.errors = tooManyFilesErrorMessage.errors;
|
133 | } else {
|
134 | fileRejections.map(function (_ref2) {
|
135 | var errors = _ref2.errors,
|
136 | name = _ref2.file.name;
|
137 | errors.forEach(function (error) {
|
138 | var _Object$values;
|
139 | var message = 'unknown validation error.';
|
140 | switch (error.code) {
|
141 | case 'file-too-large':
|
142 | message = "is too large. Max supported file size is ".concat(formatFileSize(maxFileSizeKb || Infinity), ".");
|
143 | break;
|
144 | case 'file-too-small':
|
145 | message = "is too small. Min supported file size is ".concat(formatFileSize(minFileSizeKb || 0), ".");
|
146 | break;
|
147 | case 'file-invalid-type':
|
148 | message = "is not a supported file type. Supported file types are ".concat((_Object$values = Object.values(accept !== null && accept !== void 0 ? accept : {})) === null || _Object$values === void 0 ? void 0 : _Object$values.flat().map(function (value) {
|
149 | return value.startsWith('.') ? value.substring(1) : value;
|
150 | }).join(', '), ".");
|
151 | break;
|
152 | }
|
153 | errorMessage.errors.push({
|
154 | name: name,
|
155 | message: message
|
156 | });
|
157 | });
|
158 | });
|
159 | }
|
160 | setFileError(errorMessage);
|
161 | }, [accept, fileRejections, maxFileSizeKb, maxFiles, minFileSizeKb, tooManyFilesErrorMessage]);
|
162 | var isInvalid = invalid || isDragReject;
|
163 | var theme$1 = theme.useTheme();
|
164 | var focusRingStyles = a11y.useFocusRing();
|
165 | var fileUploadError = !!(fileError !== null && fileError !== void 0 && fileError.errors.length);
|
166 | var isMaxFilesReached = maxFiles > 0 && files.length === maxFiles;
|
167 | var isDropzoneDisabled = disabled || fileUploadError || isMaxFilesReached;
|
168 | var dropzoneStyles = useDropzoneStyles({
|
169 | disabled: isDropzoneDisabled,
|
170 | isInvalid: isInvalid
|
171 | });
|
172 | return jsxRuntime.jsxs(stack.Stack, {
|
173 | gap: "large",
|
174 | children: [jsxRuntime.jsx(a11y.VisuallyHidden, _objectSpread(_objectSpread(_objectSpread({
|
175 | as: "input",
|
176 | disabled: disabled,
|
177 | name: name,
|
178 | onBlur: onBlur,
|
179 | onChange: onChange
|
180 | }, a11yProps), dropzoneInputProps), {}, {
|
181 |
|
182 |
|
183 | ref: utils.mergeRefs([forwardedRef, dropzoneInputRef])
|
184 | })), jsxRuntime.jsxs(stack.Stack, _objectSpread(_objectSpread({}, dropzoneProps), {}, {
|
185 | as: "button",
|
186 | align: "center",
|
187 | background: function () {
|
188 | if (disabled) return 'inputDisabled';
|
189 | if (isInvalid) return 'criticalLight';
|
190 | return 'surfaceMuted';
|
191 | }(),
|
192 | border: function () {
|
193 | if (disabled) return 'fieldDisabled';
|
194 | if (isInvalid) return 'critical';
|
195 | return 'field';
|
196 | }(),
|
197 | borderRadius: "medium",
|
198 | borderWidth: "large",
|
199 | gap: "large",
|
200 | padding: "large",
|
201 | position: "relative",
|
202 | className: css.css(dropzoneStyles),
|
203 | disabled: isDropzoneDisabled,
|
204 | children: [isDragActive && jsxRuntime.jsx(box.Box
|
205 |
|
206 | , {
|
207 | position: "absolute",
|
208 | top: 0,
|
209 | bottom: 0,
|
210 | display: "flex",
|
211 | alignItems: "center",
|
212 | children: jsxRuntime.jsx(text.Text, {
|
213 | tone: isDragReject ? 'critical' : 'neutral',
|
214 | children: isDragReject ? 'file type not valid' : 'drop files to upload'
|
215 | })
|
216 | }), jsxRuntime.jsxs(stack.Stack
|
217 |
|
218 | , {
|
219 | "aria-hidden": isDragActive,
|
220 | align: "center",
|
221 | gap: "large",
|
222 | position: "relative",
|
223 | className: css.css(isDragActive ? {
|
224 | opacity: 0,
|
225 | pointerEvents: 'none'
|
226 | } : null),
|
227 | children: [jsxRuntime.jsx(icon.UploadIcon, {
|
228 | size: "medium",
|
229 | tone: disabled ? 'disabled' : 'neutral'
|
230 | }), jsxRuntime.jsxs(text.Text, {
|
231 | align: "center",
|
232 | tone: disabled ? 'disabled' : 'neutral',
|
233 | children: ["click to select files ", jsxRuntime.jsx("br", {}), "or drop files here ", maxFiles > 0 ? "(max ".concat(maxFiles, ")") : '']
|
234 | })]
|
235 | })]
|
236 | })), fileUploadError && jsxRuntime.jsx(alert.Alert, {
|
237 | tone: "critical",
|
238 | heading: fileError.type === 'too-many-files' ? 'Maximum number of files reached' : 'These files couldn’t be added:',
|
239 | closeLabel: "Dismiss alert",
|
240 | onClose: function onClose() {
|
241 | return setFileError(undefined);
|
242 | },
|
243 | children: fileError.type === 'too-many-files' ? jsxRuntime.jsx(text.Text, {
|
244 | children: (_fileError$errors$ = fileError.errors[0]) === null || _fileError$errors$ === void 0 ? void 0 : _fileError$errors$.message
|
245 | }) : jsxRuntime.jsx(textList.TextList, {
|
246 | gap: "medium",
|
247 | children: fileError.errors.map(function (error) {
|
248 | return jsxRuntime.jsxs(text.Text, {
|
249 | weight: "regular",
|
250 | children: [error.name, " - ", error.message]
|
251 | }, error.name);
|
252 | })
|
253 | })
|
254 | }), files.length > 0 && jsxRuntime.jsx(stack.Stack, {
|
255 | as: "ul",
|
256 | role: "list",
|
257 | gap: "medium",
|
258 | children: files.map(function (file) {
|
259 | return jsxRuntime.jsx(box.Box, {
|
260 | as: "li",
|
261 | border: "field",
|
262 | borderRadius: "small",
|
263 | padding: "xsmall",
|
264 | children: jsxRuntime.jsxs(box.Box, {
|
265 | display: "flex",
|
266 | alignItems: "center",
|
267 | gap: "medium",
|
268 | height: "medium",
|
269 | paddingLeft: "small",
|
270 | children: [showImageThumbnails && file.preview ? jsxRuntime.jsx(box.Box, {
|
271 | as: "img",
|
272 | height: "xsmall",
|
273 | width: "xsmall",
|
274 | src: file.preview,
|
275 | className: css.css({
|
276 | objectFit: 'cover'
|
277 | }),
|
278 | alt: ""
|
279 | }) : jsxRuntime.jsx(icon.DocumentTextIcon, {
|
280 | size: "xsmall"
|
281 | }), jsxRuntime.jsx(box.Box, {
|
282 | flex: 1,
|
283 | children: jsxRuntime.jsx(text.Text, {
|
284 | inline: true,
|
285 | children: file.path
|
286 | })
|
287 | }), jsxRuntime.jsxs(box.Box, {
|
288 | as: "button",
|
289 | type: "button",
|
290 | onClick: function onClick() {
|
291 | return handleRemoveFile(file.id);
|
292 | },
|
293 | cursor: "pointer",
|
294 | display: "flex",
|
295 | alignItems: "center",
|
296 | justifyContent: "center",
|
297 | borderRadius: "small",
|
298 | height: "medium",
|
299 | width: "medium",
|
300 | className: css.css({
|
301 | transitionProperty: 'all',
|
302 | transitionTimingFunction: theme$1.animation.standard.easing,
|
303 | transitionDuration: "".concat(theme$1.animation.standard.duration, "ms"),
|
304 | ':hover': {
|
305 | backgroundColor: theme$1.color.background.surfaceMuted
|
306 | },
|
307 | ':focus': focusRingStyles
|
308 | }),
|
309 | children: [jsxRuntime.jsx(a11y.VisuallyHidden, {
|
310 | children: "Remove file"
|
311 | }), jsxRuntime.jsx(icon.XIcon, {
|
312 | size: "xxsmall"
|
313 | })]
|
314 | })]
|
315 | })
|
316 | }, file.id);
|
317 | })
|
318 | })]
|
319 | });
|
320 | });
|
321 | Dropzone.displayName = 'Dropzone';
|
322 | function useDropzoneStyles(_ref3) {
|
323 | var disabled = _ref3.disabled,
|
324 | isInvalid = _ref3.isInvalid;
|
325 | var theme$1 = theme.useTheme();
|
326 | var focusRingStyles = a11y.useFocusRing();
|
327 | return {
|
328 | borderStyle: 'dashed',
|
329 | cursor: disabled ? 'default' : 'pointer',
|
330 | transitionProperty: 'all',
|
331 | transitionTimingFunction: theme$1.animation.standard.easing,
|
332 | transitionDuration: "".concat(theme$1.animation.standard.duration, "ms"),
|
333 | ':hover': {
|
334 | backgroundColor: disabled || isInvalid ? undefined : theme$1.color.background.infoLight,
|
335 | borderColor: disabled || isInvalid ? undefined : theme$1.border.color.fieldHover
|
336 | },
|
337 | ':focus': focusRingStyles
|
338 | };
|
339 | }
|
340 | function formatFileSize(numKb) {
|
341 | if (numKb < 1000) {
|
342 | return "".concat(Math.round(numKb).toFixed(), "kB");
|
343 | }
|
344 | return "".concat(Math.round(numKb / 1000).toFixed(), "MB");
|
345 | }
|
346 |
|
347 | exports.Dropzone = Dropzone;
|