@reykjavik/hanna-react 0.10.63 → 0.10.64
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 +7 -2
- package/FileInput/{FileInput.utils.d.ts → _FileInput.utils.d.ts} +0 -0
- package/FileInput/{FileInput.utils.js → _FileInput.utils.js} +0 -0
- package/FileInput/_FileInputFileList.d.ts +11 -0
- package/FileInput/_FileInputFileList.js +24 -0
- package/FileInput.d.ts +22 -6
- package/FileInput.js +36 -31
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
- ... <!-- Add new lines here. -->
|
|
6
6
|
|
|
7
|
-
## 0.10.63
|
|
7
|
+
## 0.10.63 – 0.10.64
|
|
8
8
|
|
|
9
9
|
_2022-08-29_
|
|
10
10
|
|
|
11
|
-
-
|
|
11
|
+
- feat: Changes to `FileInput`
|
|
12
|
+
- feat: Add prop `FileList` to suppress (`false`) or customize its rendering
|
|
13
|
+
- feat: Add props `multiple`, `accept`
|
|
14
|
+
- feat: Deprecate prop `dropzoneProps`
|
|
15
|
+
- fix: report deleted when adding files in single-file mode
|
|
16
|
+
- fix: Make `dropZoneProps` optional, as originally indented
|
|
12
17
|
- fix: Hide `Carousel` mouse-cursor scroll controls at start/end positions
|
|
13
18
|
- fix: Pass `id` and other HTML props to static (span) `TagPill`s
|
|
14
19
|
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { formatBytes } from './_FileInput.utils';
|
|
2
|
+
import { CustomFile } from './_FileInput.utils';
|
|
3
|
+
export declare type FileListProps = {
|
|
4
|
+
files: Array<CustomFile>;
|
|
5
|
+
showFileSize?: boolean;
|
|
6
|
+
showImagePreviews?: boolean;
|
|
7
|
+
removeFileText: string;
|
|
8
|
+
removeFile: (file: File | string) => void;
|
|
9
|
+
formatBytes: typeof formatBytes;
|
|
10
|
+
};
|
|
11
|
+
export declare const DefaultFileList: (props: FileListProps) => JSX.Element | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultFileList = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
6
|
+
const DefaultFileList = (props) => {
|
|
7
|
+
const { files, showFileSize, showImagePreviews, removeFileText, removeFile, formatBytes, } = props;
|
|
8
|
+
if (!files.length) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return (react_1.default.createElement("ul", { className: "FileInput__filelist" }, files.map((file) => (react_1.default.createElement("li", { key: file.name, className: "FileInput__file" },
|
|
12
|
+
react_1.default.createElement("button", { className: "FileInput__file-remove", type: "button", onClick: () => removeFile(file), "aria-label": removeFileText }, removeFileText),
|
|
13
|
+
react_1.default.createElement("span", { className: "FileInput__fileinfo" },
|
|
14
|
+
showImagePreviews && file.preview && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
15
|
+
react_1.default.createElement("span", { className: "FileInput__preview" },
|
|
16
|
+
react_1.default.createElement("img", { src: file.preview })),
|
|
17
|
+
' ')),
|
|
18
|
+
react_1.default.createElement("span", { className: "FileInput__filename" }, file.name),
|
|
19
|
+
showFileSize && (react_1.default.createElement("small", { className: "FileInput__filesize" },
|
|
20
|
+
" - (",
|
|
21
|
+
formatBytes(file.size),
|
|
22
|
+
")"))))))));
|
|
23
|
+
};
|
|
24
|
+
exports.DefaultFileList = DefaultFileList;
|
package/FileInput.d.ts
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
+
import { FileListProps } from './FileInput/_FileInputFileList';
|
|
1
2
|
import { FormFieldWrappingProps } from './FormField';
|
|
2
|
-
declare type DropzonePropsProps = {
|
|
3
|
-
accept?: string;
|
|
4
|
-
multiple?: boolean;
|
|
5
|
-
};
|
|
6
3
|
export declare type FileInputProps = {
|
|
7
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Flags if the input should accept multiple, or just a single file at a time.
|
|
6
|
+
*
|
|
7
|
+
* Default: `true`
|
|
8
|
+
*/
|
|
9
|
+
multiple?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Accepted file mime type(s).
|
|
12
|
+
*
|
|
13
|
+
* Default: no restrictions.
|
|
14
|
+
*/
|
|
15
|
+
accept?: string | Array<string>;
|
|
8
16
|
dropzoneText: string | JSX.Element;
|
|
17
|
+
removeFileText: string;
|
|
9
18
|
showFileSize?: boolean;
|
|
10
19
|
showImagePreviews?: boolean;
|
|
11
|
-
|
|
20
|
+
FileList?: false | ((props: FileListProps) => JSX.Element | null);
|
|
12
21
|
onFilesUpdated?: (
|
|
13
22
|
/** Updated, full list of Files. */
|
|
14
23
|
files: Array<File>,
|
|
@@ -27,6 +36,13 @@ export declare type FileInputProps = {
|
|
|
27
36
|
}) => void;
|
|
28
37
|
name?: string;
|
|
29
38
|
value?: ReadonlyArray<File>;
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated Use props `multiple`, `accept` instead (Will be removed in v0.11)
|
|
41
|
+
*/
|
|
42
|
+
dropzoneProps?: {
|
|
43
|
+
accept?: string;
|
|
44
|
+
multiple?: boolean;
|
|
45
|
+
};
|
|
30
46
|
} & FormFieldWrappingProps;
|
|
31
47
|
declare const FileInput: (props: FileInputProps) => JSX.Element;
|
|
32
48
|
export default FileInput;
|
package/FileInput.js
CHANGED
|
@@ -5,7 +5,8 @@ const react_1 = tslib_1.__importStar(require("react"));
|
|
|
5
5
|
const react_dropzone_1 = require("react-dropzone"); // https://react-dropzone.js.org/#!/Dropzone
|
|
6
6
|
const hooks_1 = require("@hugsmidjan/react/hooks");
|
|
7
7
|
const getBemClass_1 = tslib_1.__importDefault(require("@hugsmidjan/react/utils/getBemClass"));
|
|
8
|
-
const
|
|
8
|
+
const _FileInput_utils_1 = require("./FileInput/_FileInput.utils");
|
|
9
|
+
const _FileInputFileList_1 = require("./FileInput/_FileInputFileList");
|
|
9
10
|
const FormField_1 = tslib_1.__importDefault(require("./FormField"));
|
|
10
11
|
const arrayToFileList = (arr) => {
|
|
11
12
|
const fileList = new DataTransfer();
|
|
@@ -15,54 +16,63 @@ const arrayToFileList = (arr) => {
|
|
|
15
16
|
return fileList.files;
|
|
16
17
|
};
|
|
17
18
|
const FileInput = (props) => {
|
|
18
|
-
const { className, id, label, hideLabel, dropzoneProps = { multiple: true }, dropzoneText, removeFileText, assistText, disabled, invalid, errorMessage, required, reqText, onFilesUpdated = () => undefined, showFileSize, showImagePreviews, value = [] } = props, inputElementProps = tslib_1.__rest(props, ["className", "id", "label", "hideLabel", "dropzoneProps", "dropzoneText", "removeFileText", "assistText", "disabled", "invalid", "errorMessage", "required", "reqText", "onFilesUpdated", "showFileSize", "showImagePreviews", "value"]);
|
|
19
|
+
const { className, id, label, hideLabel, dropzoneProps = { multiple: true }, multiple = dropzoneProps.multiple, accept, dropzoneText, removeFileText, assistText, disabled, invalid, errorMessage, required, reqText, FileList = _FileInputFileList_1.DefaultFileList, onFilesUpdated = () => undefined, showFileSize, showImagePreviews, value = [] } = props, inputElementProps = tslib_1.__rest(props, ["className", "id", "label", "hideLabel", "dropzoneProps", "multiple", "accept", "dropzoneText", "removeFileText", "assistText", "disabled", "invalid", "errorMessage", "required", "reqText", "FileList", "onFilesUpdated", "showFileSize", "showImagePreviews", "value"]);
|
|
19
20
|
const domid = (0, hooks_1.useDomid)(id);
|
|
20
21
|
const fileInputWrapper = (0, react_1.useRef)(null);
|
|
21
22
|
const fileInput = (0, react_1.useRef)(null);
|
|
22
23
|
const files = value;
|
|
23
24
|
const [isHover, setIsHover] = (0, react_1.useState)(false);
|
|
24
|
-
const { getRootProps, getInputProps, isDragReject, inputRef } = (0, react_dropzone_1.useDropzone)(
|
|
25
|
+
const { getRootProps, getInputProps, isDragReject, inputRef } = (0, react_dropzone_1.useDropzone)({
|
|
26
|
+
onDrop: (acceptedFiles) => {
|
|
25
27
|
acceptedFiles = acceptedFiles.map((file) => {
|
|
26
|
-
(0,
|
|
28
|
+
(0, _FileInput_utils_1.addPreview)(file);
|
|
27
29
|
return file;
|
|
28
30
|
});
|
|
29
31
|
addFiles(acceptedFiles); // eslint-disable-line
|
|
30
32
|
setIsHover(false);
|
|
31
|
-
},
|
|
33
|
+
},
|
|
34
|
+
onDropRejected: (rejectedFiles) => {
|
|
32
35
|
window.alert('Error:\n' +
|
|
33
36
|
rejectedFiles
|
|
34
37
|
.map((elm) => {
|
|
35
38
|
return elm.name;
|
|
36
39
|
})
|
|
37
40
|
.join(', '));
|
|
38
|
-
},
|
|
41
|
+
},
|
|
42
|
+
onDragEnter: () => {
|
|
39
43
|
// 'dragLeave' always fires right after 'dragEnter', use 'dragOver' instead
|
|
40
44
|
// console.log('enter');
|
|
41
45
|
// setIsHover(true);
|
|
42
|
-
},
|
|
46
|
+
},
|
|
47
|
+
onDragLeave: () => {
|
|
43
48
|
// console.log('leave');
|
|
44
49
|
setIsHover(false);
|
|
45
|
-
},
|
|
50
|
+
},
|
|
51
|
+
onDragOver: () => {
|
|
46
52
|
// TODO: add error icon? 'isDragReject' gives unstable results
|
|
47
53
|
// console.log(isDragReject);
|
|
48
54
|
setIsHover(true);
|
|
49
|
-
}
|
|
55
|
+
},
|
|
56
|
+
multiple,
|
|
57
|
+
accept,
|
|
58
|
+
});
|
|
50
59
|
// Add previews on incoming files
|
|
51
60
|
// (NOTE: `addPreview` ignores files that already have preview.)
|
|
52
|
-
files.forEach(
|
|
61
|
+
files.forEach(_FileInput_utils_1.addPreview);
|
|
53
62
|
(0, react_1.useEffect)(() => () => {
|
|
54
63
|
// Make sure to revoke the data uris on unmount to avoid memory leaks
|
|
55
|
-
files.forEach(
|
|
64
|
+
files.forEach(_FileInput_utils_1.releasePreview);
|
|
56
65
|
}, [files]);
|
|
57
|
-
const removeFile = (
|
|
66
|
+
const removeFile = (removeTarget) => {
|
|
58
67
|
if (fileInput.current) {
|
|
59
68
|
const deleted = [];
|
|
69
|
+
const targetName = typeof removeTarget !== 'string' ? removeTarget.name : removeTarget;
|
|
60
70
|
const newFileList = files.filter((file) => {
|
|
61
|
-
if (file.name !==
|
|
71
|
+
if (file.name !== targetName) {
|
|
62
72
|
return true;
|
|
63
73
|
}
|
|
64
74
|
deleted.push(file);
|
|
65
|
-
(0,
|
|
75
|
+
(0, _FileInput_utils_1.releasePreview)(file);
|
|
66
76
|
return false;
|
|
67
77
|
});
|
|
68
78
|
fileInput.current.files = arrayToFileList(newFileList);
|
|
@@ -71,7 +81,7 @@ const FileInput = (props) => {
|
|
|
71
81
|
};
|
|
72
82
|
const addFiles = (added) => {
|
|
73
83
|
if (fileInput.current) {
|
|
74
|
-
const { fileList, diff } = (0,
|
|
84
|
+
const { fileList, diff } = (0, _FileInput_utils_1.getFileListUpdate)(files, added, !multiple);
|
|
75
85
|
fileInput.current.files = arrayToFileList(fileList);
|
|
76
86
|
onFilesUpdated(fileList, diff);
|
|
77
87
|
}
|
|
@@ -80,27 +90,22 @@ const FileInput = (props) => {
|
|
|
80
90
|
inputRef.current.files = arrayToFileList([]);
|
|
81
91
|
}
|
|
82
92
|
};
|
|
83
|
-
|
|
84
|
-
react_1.default.createElement("button", { className: "FileInput__file-remove", type: "button", onClick: () => removeFile(file.name), "aria-label": removeFileText }, removeFileText),
|
|
85
|
-
react_1.default.createElement("span", { className: "FileInput__fileinfo" },
|
|
86
|
-
showImagePreviews && file.preview && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
87
|
-
react_1.default.createElement("span", { className: "FileInput__preview" },
|
|
88
|
-
react_1.default.createElement("img", { src: file.preview })),
|
|
89
|
-
' ')),
|
|
90
|
-
react_1.default.createElement("span", { className: "FileInput__filename" }, file.name),
|
|
91
|
-
showFileSize && (react_1.default.createElement("small", { className: "FileInput__filesize" },
|
|
92
|
-
" - (",
|
|
93
|
-
(0, FileInput_utils_1.formatBytes)(file.size),
|
|
94
|
-
")"))))));
|
|
95
|
-
return (react_1.default.createElement(FormField_1.default, { className: (0, getBemClass_1.default)('FileInput', [dropzoneProps.multiple && 'multi'], className), label: label, id: domid + '-fake', LabelTag: "h4", assistText: assistText, hideLabel: hideLabel, disabled: disabled, invalid: invalid, errorMessage: errorMessage, required: required, reqText: reqText, renderInput: (className, inputProps /* , addFocusProps */) => {
|
|
93
|
+
return (react_1.default.createElement(FormField_1.default, { className: (0, getBemClass_1.default)('FileInput', [multiple && 'multi'], className), label: label, id: domid + '-fake', LabelTag: "h4", assistText: assistText, hideLabel: hideLabel, disabled: disabled, invalid: invalid, errorMessage: errorMessage, required: required, reqText: reqText, renderInput: (className, inputProps /* , addFocusProps */) => {
|
|
96
94
|
return (react_1.default.createElement("div", { className: className.control, ref: fileInputWrapper },
|
|
97
|
-
react_1.default.createElement("input", { className: "FileInput__input", name: inputElementProps.name, id: domid, ref: fileInput, type: "file", style: { display: 'none' }, multiple:
|
|
95
|
+
react_1.default.createElement("input", { className: "FileInput__input", name: inputElementProps.name, id: domid, ref: fileInput, type: "file", style: { display: 'none' }, multiple: multiple || undefined, required: inputProps.required }),
|
|
98
96
|
' ',
|
|
99
|
-
react_1.default.createElement("input", Object.assign({ className: "FileInput__input--fake" }, getInputProps(), { tabIndex: undefined, style: undefined, multiple:
|
|
97
|
+
react_1.default.createElement("input", Object.assign({ className: "FileInput__input--fake" }, getInputProps(), { tabIndex: undefined, style: undefined, multiple: multiple || undefined }, inputProps, { required: undefined })),
|
|
100
98
|
' ',
|
|
101
99
|
react_1.default.createElement("div", Object.assign({ className: (0, getBemClass_1.default)('FileInput__dropzone', [isHover && 'highlight']) }, getRootProps({ isDragReject }), { tabIndex: undefined }),
|
|
102
100
|
react_1.default.createElement("p", { className: "FileInput__droptext" }, dropzoneText)),
|
|
103
|
-
|
|
101
|
+
FileList && (react_1.default.createElement(FileList, Object.assign({}, {
|
|
102
|
+
files,
|
|
103
|
+
showFileSize,
|
|
104
|
+
showImagePreviews,
|
|
105
|
+
removeFileText,
|
|
106
|
+
removeFile,
|
|
107
|
+
formatBytes: _FileInput_utils_1.formatBytes,
|
|
108
|
+
})))));
|
|
104
109
|
} }));
|
|
105
110
|
};
|
|
106
111
|
exports.default = FileInput;
|