@spaced-out/ui-design-system 0.1.29 → 0.1.31
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/.cspell/custom-words.txt +5 -0
- package/.github/workflows/pages.yml +3 -0
- package/.github/workflows/publish_to_npm.yml +1 -1
- package/.github/workflows/pull_request_checks.yml +44 -0
- package/.github/workflows/pull_request_semantics_checker.yml +1 -0
- package/.storybook/main.js +1 -1
- package/.storybook/preview-head.html +8 -3
- package/CHANGELOG.md +33 -0
- package/design-tokens/color/app-color.json +3 -0
- package/design-tokens/color/base-color.json +3 -0
- package/design-tokens/index.js +5 -3
- package/design-tokens/size/base-size.json +15 -0
- package/lib/components/Dialog/Dialog.module.css +1 -1
- package/lib/components/FileUpload/FileUpload.js +195 -0
- package/lib/components/FileUpload/FileUpload.js.flow +301 -0
- package/lib/components/FileUpload/FileUpload.module.css +185 -0
- package/lib/components/FileUpload/index.js +16 -0
- package/lib/components/FileUpload/index.js.flow +3 -0
- package/lib/components/Input/Input.js +2 -2
- package/lib/components/Input/Input.js.flow +11 -7
- package/lib/components/Input/Input.module.css +16 -5
- package/lib/components/LinearLoader/LinearLoader.js +10 -3
- package/lib/components/LinearLoader/LinearLoader.js.flow +15 -2
- package/lib/components/LinearLoader/LinearLoader.module.css +34 -1
- package/lib/components/Modal/Modal.js +3 -2
- package/lib/components/Modal/Modal.js.flow +10 -4
- package/lib/components/Modal/Modal.module.css +13 -1
- package/lib/components/Modal/index.js.flow +1 -0
- package/lib/components/Textarea/Textarea.js +2 -2
- package/lib/components/Textarea/Textarea.js.flow +10 -6
- package/lib/components/Textarea/Textarea.module.css +19 -5
- package/lib/components/index.js +11 -0
- package/lib/components/index.js.flow +1 -0
- package/lib/hooks/index.js +11 -0
- package/lib/hooks/index.js.flow +1 -0
- package/lib/hooks/useFileUpload/index.js +16 -0
- package/lib/hooks/useFileUpload/index.js.flow +3 -0
- package/lib/hooks/useFileUpload/useFileUpload.js +279 -0
- package/lib/hooks/useFileUpload/useFileUpload.js.flow +304 -0
- package/lib/styles/index.css +12 -0
- package/lib/styles/index.js +15 -3
- package/lib/styles/index.js.flow +12 -0
- package/lib/styles/variables/_color.css +2 -0
- package/lib/styles/variables/_color.js +3 -1
- package/lib/styles/variables/_color.js.flow +2 -0
- package/lib/styles/variables/_size.css +10 -0
- package/lib/styles/variables/_size.js +11 -1
- package/lib/styles/variables/_size.js.flow +10 -0
- package/lib/utils/helpers/helpers.js +39 -2
- package/lib/utils/helpers/helpers.js.flow +37 -0
- package/lib/utils/makeClassNameComponent/makeClassNameComponent.js.flow +0 -1
- package/lib/utils/tokens/tokens.js +15 -2
- package/lib/utils/tokens/tokens.js.flow +16 -0
- package/package.json +3 -2
- /package/design-tokens/motion/{app.motion.json → app-motion.json} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
@value (
|
|
2
2
|
borderRadiusSmall
|
|
3
3
|
) from '../../styles/variables/_border.css';
|
|
4
|
+
|
|
4
5
|
@value (colorFillPrimary, colorBorderPrimary) from '../../styles/variables/_color.css';
|
|
5
6
|
|
|
6
7
|
@value (
|
|
@@ -11,10 +12,18 @@
|
|
|
11
12
|
) from '../../styles/variables/_size.css';
|
|
12
13
|
|
|
13
14
|
@value (
|
|
14
|
-
motionDurationSlow
|
|
15
|
+
motionDurationSlow,
|
|
16
|
+
motionDurationSlowest,
|
|
17
|
+
motionEaseInEaseOut
|
|
15
18
|
) from '../../styles/variables/_motion.css';
|
|
16
19
|
|
|
20
|
+
@value (
|
|
21
|
+
spaceNone,
|
|
22
|
+
spaceFluid
|
|
23
|
+
) from '../../styles/variables/_space.css';
|
|
24
|
+
|
|
17
25
|
.lineContainer {
|
|
26
|
+
position: relative;
|
|
18
27
|
display: flex;
|
|
19
28
|
justify-content: flex-start;
|
|
20
29
|
align-items: center;
|
|
@@ -41,3 +50,27 @@
|
|
|
41
50
|
height: sizeFluid;
|
|
42
51
|
transition: motionDurationSlow;
|
|
43
52
|
}
|
|
53
|
+
|
|
54
|
+
.indeterminate {
|
|
55
|
+
position: absolute;
|
|
56
|
+
|
|
57
|
+
animation: infiniteProgressBar calc(motionDurationSlowest * 3)
|
|
58
|
+
motionEaseInEaseOut;
|
|
59
|
+
animation-iteration-count: infinite;
|
|
60
|
+
animation-fill-mode: both;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@keyframes infiniteProgressBar {
|
|
64
|
+
0% {
|
|
65
|
+
left: spaceNone;
|
|
66
|
+
width: spaceNone;
|
|
67
|
+
}
|
|
68
|
+
50% {
|
|
69
|
+
left: spaceNone;
|
|
70
|
+
width: spaceFluid;
|
|
71
|
+
}
|
|
72
|
+
100% {
|
|
73
|
+
left: spaceFluid;
|
|
74
|
+
width: spaceNone;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -120,7 +120,8 @@ const Modal = _ref4 => {
|
|
|
120
120
|
hideBackdrop = false,
|
|
121
121
|
tapOutsideToClose = true,
|
|
122
122
|
initialFocus = -1,
|
|
123
|
-
customAnimation
|
|
123
|
+
customAnimation,
|
|
124
|
+
size = 'small'
|
|
124
125
|
} = _ref4;
|
|
125
126
|
const {
|
|
126
127
|
refs,
|
|
@@ -213,7 +214,7 @@ const Modal = _ref4 => {
|
|
|
213
214
|
}, classNames?.backdrop),
|
|
214
215
|
onClick: onBackdropClick
|
|
215
216
|
}), isMounted && /*#__PURE__*/React.createElement("div", {
|
|
216
|
-
className: (0, _classify.default)(_ModalModule.default.modal, classNames?.content),
|
|
217
|
+
className: (0, _classify.default)(_ModalModule.default.modal, _ModalModule.default[size], classNames?.content),
|
|
217
218
|
role: "dialog",
|
|
218
219
|
style: {
|
|
219
220
|
// Transition styles
|
|
@@ -51,13 +51,18 @@ export type ModalProps = {
|
|
|
51
51
|
isOpen?: boolean,
|
|
52
52
|
onClose?: ?(SyntheticEvent<HTMLElement>) => mixed,
|
|
53
53
|
hideBackdrop?: boolean,
|
|
54
|
-
// This prop is removed now
|
|
55
|
-
removeWhenClosed?: boolean,
|
|
56
54
|
tapOutsideToClose?: boolean,
|
|
57
55
|
initialFocus?: number,
|
|
58
56
|
customAnimation?: UseTransitionStylesProps,
|
|
59
57
|
};
|
|
60
58
|
|
|
59
|
+
export type ModalSize = 'small' | 'medium' | 'large';
|
|
60
|
+
|
|
61
|
+
export type BaseModalProps = {
|
|
62
|
+
...ModalProps,
|
|
63
|
+
size?: ModalSize,
|
|
64
|
+
};
|
|
65
|
+
|
|
61
66
|
export type ModalHeaderProps = {
|
|
62
67
|
children?: React.Node,
|
|
63
68
|
hideCloseBtn?: boolean,
|
|
@@ -189,7 +194,8 @@ export const Modal = ({
|
|
|
189
194
|
tapOutsideToClose = true,
|
|
190
195
|
initialFocus = -1,
|
|
191
196
|
customAnimation,
|
|
192
|
-
|
|
197
|
+
size = 'small',
|
|
198
|
+
}: BaseModalProps): React.Node => {
|
|
193
199
|
const {refs, context} = useFloating({open: isOpen});
|
|
194
200
|
const {isMounted, styles} = useTransitionStyles(
|
|
195
201
|
context,
|
|
@@ -301,7 +307,7 @@ export const Modal = ({
|
|
|
301
307
|
/>
|
|
302
308
|
{isMounted && (
|
|
303
309
|
<div
|
|
304
|
-
className={classify(css.modal, classNames?.content)}
|
|
310
|
+
className={classify(css.modal, css[size], classNames?.content)}
|
|
305
311
|
role="dialog"
|
|
306
312
|
style={{
|
|
307
313
|
// Transition styles
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@value (colorBackgroundTertiary, colorBackgroundPrimary, colorBackdropFill) from '../../styles/variables/_color.css';
|
|
2
2
|
@value (spaceNone, spaceSmall, spaceMedium, spaceXXSmall, spaceHalfFluid, spaceNegHalfFluid) from '../../styles/variables/_space.css';
|
|
3
|
-
@value (sizeFluid, size60) from '../../styles/variables/_size.css';
|
|
3
|
+
@value (sizeFluid, size60, size320, size480, size640) from '../../styles/variables/_size.css';
|
|
4
4
|
@value (elevationNone, elevationModal, elevationBackdrop) from '../../styles/variables/_elevation.css';
|
|
5
5
|
@value (opacity100, opacity0) from '../../styles/variables/_opacity.css';
|
|
6
6
|
@value (motionDurationNormal, motionEaseInEaseOut) from '../../styles/variables/_motion.css';
|
|
@@ -27,6 +27,18 @@
|
|
|
27
27
|
border-radius: borderRadiusMedium;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
.modal.small {
|
|
31
|
+
width: size320;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.modal.medium {
|
|
35
|
+
width: size480;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.modal.large {
|
|
39
|
+
width: size640;
|
|
40
|
+
}
|
|
41
|
+
|
|
30
42
|
.modalContainer.open.in .modal {
|
|
31
43
|
opacity: opacity100;
|
|
32
44
|
transform: translate(spaceNegHalfFluid, spaceNegHalfFluid) scale(1);
|
|
@@ -59,12 +59,12 @@ const Textarea_ = (props, ref) => {
|
|
|
59
59
|
}, '*')), /*#__PURE__*/React.createElement(_Text.FormLabelSmall, {
|
|
60
60
|
color: error || textCountError ? 'danger' : 'secondary'
|
|
61
61
|
}, !!textCountLimit && (value && value.length || 0) + '/' + textCountLimit)), /*#__PURE__*/React.createElement("div", {
|
|
62
|
-
className: (0, _classify.classify)(_TextareaModule.default.box,
|
|
62
|
+
className: (0, _classify.classify)(_TextareaModule.default.box, {
|
|
63
63
|
[_TextareaModule.default.inputDisabled]: disabled ?? false,
|
|
64
64
|
[_TextareaModule.default.medium]: size === 'medium',
|
|
65
65
|
[_TextareaModule.default.small]: size === 'small',
|
|
66
66
|
[_TextareaModule.default.locked]: locked
|
|
67
|
-
})
|
|
67
|
+
}, classNames?.box)
|
|
68
68
|
}, /*#__PURE__*/React.createElement("textarea", _extends({}, textareaProps, {
|
|
69
69
|
disabled: locked || disabled,
|
|
70
70
|
name: name,
|
|
@@ -91,12 +91,16 @@ const Textarea_ = (props: TextareaProps, ref): React.Node => {
|
|
|
91
91
|
</div>
|
|
92
92
|
)}
|
|
93
93
|
<div
|
|
94
|
-
className={classify(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
className={classify(
|
|
95
|
+
css.box,
|
|
96
|
+
{
|
|
97
|
+
[css.inputDisabled]: disabled ?? false,
|
|
98
|
+
[css.medium]: size === 'medium',
|
|
99
|
+
[css.small]: size === 'small',
|
|
100
|
+
[css.locked]: locked,
|
|
101
|
+
},
|
|
102
|
+
classNames?.box,
|
|
103
|
+
)}
|
|
100
104
|
>
|
|
101
105
|
<textarea
|
|
102
106
|
{...textareaProps}
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
@value (
|
|
15
15
|
borderRadiusMedium,
|
|
16
16
|
borderRadiusSmall,
|
|
17
|
-
|
|
17
|
+
borderWidthPrimary,
|
|
18
18
|
borderWidthTertiary,
|
|
19
19
|
borderWidthNone
|
|
20
20
|
) from '../../styles/variables/_border.css';
|
|
21
21
|
|
|
22
22
|
@value (
|
|
23
23
|
colorTextPrimary,
|
|
24
|
-
|
|
24
|
+
colorTextTertiary,
|
|
25
25
|
colorBorderPrimary,
|
|
26
26
|
colorFillPrimary,
|
|
27
27
|
colorFocusPrimary,
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
colorTextDisabled,
|
|
30
30
|
colorFillDisabled,
|
|
31
31
|
colorTextDanger,
|
|
32
|
-
colorBackgroundTertiary
|
|
32
|
+
colorBackgroundTertiary,
|
|
33
|
+
colorBorderTertiary
|
|
33
34
|
) from '../../styles/variables/_color.css';
|
|
34
35
|
|
|
35
36
|
.container {
|
|
@@ -43,10 +44,19 @@
|
|
|
43
44
|
color: colorTextPrimary;
|
|
44
45
|
gap: spaceSmall;
|
|
45
46
|
height: size160;
|
|
46
|
-
border:
|
|
47
|
+
border: borderWidthPrimary solid colorBorderPrimary;
|
|
47
48
|
background-color: colorBackgroundTertiary;
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
.wrapper:not(.withError) .box:not(.inputDisabled):not(.locked):hover {
|
|
52
|
+
border-color: colorBorderTertiary;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.wrapper:not(.withError):focus-within
|
|
56
|
+
.box:not(.inputDisabled):not(.locked):hover {
|
|
57
|
+
border-color: colorFillPrimary;
|
|
58
|
+
}
|
|
59
|
+
|
|
50
60
|
.box textarea {
|
|
51
61
|
padding: spaceXSmall spaceSmall;
|
|
52
62
|
}
|
|
@@ -82,7 +92,7 @@
|
|
|
82
92
|
resize: none;
|
|
83
93
|
}
|
|
84
94
|
|
|
85
|
-
.wrapper:not(.
|
|
95
|
+
.wrapper:not(.withError):focus-within .box:not(.inputDisabled) {
|
|
86
96
|
border-color: colorFillPrimary;
|
|
87
97
|
box-shadow: borderWidthNone borderWidthNone borderWidthNone
|
|
88
98
|
borderWidthTertiary colorFocusPrimary;
|
|
@@ -94,6 +104,10 @@
|
|
|
94
104
|
background-color: colorFillDisabled;
|
|
95
105
|
}
|
|
96
106
|
|
|
107
|
+
textarea::placeholder {
|
|
108
|
+
color: colorTextTertiary;
|
|
109
|
+
}
|
|
110
|
+
|
|
97
111
|
.inputDisabled textarea::placeholder {
|
|
98
112
|
color: inherit;
|
|
99
113
|
}
|
package/lib/components/index.js
CHANGED
|
@@ -201,6 +201,17 @@ Object.keys(_ErrorMessage).forEach(function (key) {
|
|
|
201
201
|
}
|
|
202
202
|
});
|
|
203
203
|
});
|
|
204
|
+
var _FileUpload = require("./FileUpload");
|
|
205
|
+
Object.keys(_FileUpload).forEach(function (key) {
|
|
206
|
+
if (key === "default" || key === "__esModule") return;
|
|
207
|
+
if (key in exports && exports[key] === _FileUpload[key]) return;
|
|
208
|
+
Object.defineProperty(exports, key, {
|
|
209
|
+
enumerable: true,
|
|
210
|
+
get: function () {
|
|
211
|
+
return _FileUpload[key];
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
});
|
|
204
215
|
var _FocusManager = require("./FocusManager");
|
|
205
216
|
Object.keys(_FocusManager).forEach(function (key) {
|
|
206
217
|
if (key === "default" || key === "__esModule") return;
|
package/lib/hooks/index.js
CHANGED
|
@@ -14,6 +14,17 @@ Object.keys(_useCopyToClipboard).forEach(function (key) {
|
|
|
14
14
|
}
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
|
+
var _useFileUpload = require("./useFileUpload");
|
|
18
|
+
Object.keys(_useFileUpload).forEach(function (key) {
|
|
19
|
+
if (key === "default" || key === "__esModule") return;
|
|
20
|
+
if (key in exports && exports[key] === _useFileUpload[key]) return;
|
|
21
|
+
Object.defineProperty(exports, key, {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () {
|
|
24
|
+
return _useFileUpload[key];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
17
28
|
var _useInputState = require("./useInputState");
|
|
18
29
|
Object.keys(_useInputState).forEach(function (key) {
|
|
19
30
|
if (key === "default" || key === "__esModule") return;
|
package/lib/hooks/index.js.flow
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _useFileUpload = require("./useFileUpload");
|
|
7
|
+
Object.keys(_useFileUpload).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _useFileUpload[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _useFileUpload[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useFileUpload = void 0;
|
|
7
|
+
var React = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactDropzone = require("react-dropzone");
|
|
9
|
+
var _helpers = require("../../utils/helpers");
|
|
10
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
11
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
12
|
+
|
|
13
|
+
// $FlowFixMe[untyped-import]
|
|
14
|
+
|
|
15
|
+
const initialState = {
|
|
16
|
+
validFiles: [],
|
|
17
|
+
rejectedFiles: []
|
|
18
|
+
};
|
|
19
|
+
const reducer = (state, action) => {
|
|
20
|
+
switch (action.type) {
|
|
21
|
+
case 'ADD_VALID_FILES':
|
|
22
|
+
return {
|
|
23
|
+
...state,
|
|
24
|
+
validFiles: [...state.validFiles, ...action.files]
|
|
25
|
+
};
|
|
26
|
+
case 'ADD_REJECTED_FILES':
|
|
27
|
+
return {
|
|
28
|
+
...state,
|
|
29
|
+
rejectedFiles: [...state.rejectedFiles, ...action.files]
|
|
30
|
+
};
|
|
31
|
+
case 'REMOVE_FILE':
|
|
32
|
+
return {
|
|
33
|
+
...state,
|
|
34
|
+
validFiles: state.validFiles.filter(file => file.id !== action.id),
|
|
35
|
+
rejectedFiles: state.rejectedFiles.filter(file => file.id !== action.id)
|
|
36
|
+
};
|
|
37
|
+
case 'CLEAR_FILES':
|
|
38
|
+
return {
|
|
39
|
+
validFiles: [],
|
|
40
|
+
rejectedFiles: []
|
|
41
|
+
};
|
|
42
|
+
case 'UPDATE_FILE_PROGRESS':
|
|
43
|
+
return {
|
|
44
|
+
...state,
|
|
45
|
+
validFiles: state.validFiles.map(file => file.id === action.id ? {
|
|
46
|
+
...file,
|
|
47
|
+
progress: action.progress,
|
|
48
|
+
showReUpload: false,
|
|
49
|
+
successMessage: undefined,
|
|
50
|
+
rejectReason: undefined
|
|
51
|
+
} : file),
|
|
52
|
+
rejectedFiles: state.rejectedFiles.map(file => file.id === action.id ? {
|
|
53
|
+
...file,
|
|
54
|
+
progress: action.progress,
|
|
55
|
+
showReUpload: false,
|
|
56
|
+
successMessage: undefined,
|
|
57
|
+
rejectReason: undefined
|
|
58
|
+
} : file)
|
|
59
|
+
};
|
|
60
|
+
case 'SET_FILE_RE_UPLOAD':
|
|
61
|
+
return {
|
|
62
|
+
...state,
|
|
63
|
+
validFiles: state.validFiles.map(file => file.id === action.id ? {
|
|
64
|
+
...file,
|
|
65
|
+
progress: undefined,
|
|
66
|
+
showReUpload: action.showReUpload
|
|
67
|
+
} : file),
|
|
68
|
+
rejectedFiles: state.rejectedFiles.map(file => file.id === action.id ? {
|
|
69
|
+
...file,
|
|
70
|
+
progress: undefined,
|
|
71
|
+
showReUpload: action.showReUpload
|
|
72
|
+
} : file)
|
|
73
|
+
};
|
|
74
|
+
case 'SET_FILE_SUCCESS':
|
|
75
|
+
{
|
|
76
|
+
// Note: When a file is accepted manually we would move a file from rejected files(if found) to valid files first
|
|
77
|
+
const fileIndex = state.rejectedFiles.findIndex(file => file.id === action.id);
|
|
78
|
+
let validFiles = [...state.validFiles];
|
|
79
|
+
const rejectedFiles = [...state.rejectedFiles];
|
|
80
|
+
if (fileIndex !== -1) {
|
|
81
|
+
const file = rejectedFiles[fileIndex];
|
|
82
|
+
rejectedFiles.splice(fileIndex, 1);
|
|
83
|
+
validFiles = [...validFiles, {
|
|
84
|
+
...file
|
|
85
|
+
}];
|
|
86
|
+
}
|
|
87
|
+
validFiles = validFiles.map(file => file.id === action.id ? {
|
|
88
|
+
...file,
|
|
89
|
+
success: true,
|
|
90
|
+
successMessage: action.successMessage,
|
|
91
|
+
reject: false,
|
|
92
|
+
rejectReason: undefined,
|
|
93
|
+
progress: undefined,
|
|
94
|
+
showReUpload: false
|
|
95
|
+
} : file);
|
|
96
|
+
return {
|
|
97
|
+
...state,
|
|
98
|
+
validFiles,
|
|
99
|
+
rejectedFiles
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
case 'SET_FILE_REJECT':
|
|
103
|
+
{
|
|
104
|
+
// Note: When a file is rejected manually we would move a file from valid files(if found) to rejected files first
|
|
105
|
+
const fileIndex = state.validFiles.findIndex(file => file.id === action.id);
|
|
106
|
+
const validFiles = [...state.validFiles];
|
|
107
|
+
let rejectedFiles = [...state.rejectedFiles];
|
|
108
|
+
if (fileIndex !== -1) {
|
|
109
|
+
const file = validFiles[fileIndex];
|
|
110
|
+
validFiles.splice(fileIndex, 1);
|
|
111
|
+
rejectedFiles = [...rejectedFiles, {
|
|
112
|
+
...file
|
|
113
|
+
}];
|
|
114
|
+
}
|
|
115
|
+
rejectedFiles = rejectedFiles.map(file => file.id === action.id ? {
|
|
116
|
+
...file,
|
|
117
|
+
reject: true,
|
|
118
|
+
rejectReason: action.rejectReason,
|
|
119
|
+
success: false,
|
|
120
|
+
successMessage: undefined,
|
|
121
|
+
progress: undefined,
|
|
122
|
+
showReUpload: false
|
|
123
|
+
} : file);
|
|
124
|
+
return {
|
|
125
|
+
...state,
|
|
126
|
+
validFiles,
|
|
127
|
+
rejectedFiles
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
default:
|
|
131
|
+
return state;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// This is a map of error codes returned by react-dropzone and their corresponding error messages
|
|
136
|
+
const DROPZONE_ERROR_MESSAGES = {
|
|
137
|
+
'file-too-large': 'File exceeds maximum size',
|
|
138
|
+
'file-invalid-type': 'Wrong file type',
|
|
139
|
+
'too-many-files': 'Too many files',
|
|
140
|
+
'file-too-small': 'File is too small'
|
|
141
|
+
};
|
|
142
|
+
const useFileUpload = _ref => {
|
|
143
|
+
let {
|
|
144
|
+
maxFiles = 1,
|
|
145
|
+
maxSize,
|
|
146
|
+
accept,
|
|
147
|
+
disabled,
|
|
148
|
+
onValidFilesDrop,
|
|
149
|
+
onRejectedFilesDrop,
|
|
150
|
+
onFileClear,
|
|
151
|
+
onClear
|
|
152
|
+
} = _ref;
|
|
153
|
+
const [state, dispatch] = React.useReducer(reducer, initialState);
|
|
154
|
+
|
|
155
|
+
// Callbacks for when files are dropped / selected and are valid
|
|
156
|
+
const handleDropAccepted = acceptedFiles => {
|
|
157
|
+
const validFiles = acceptedFiles.map(file => ({
|
|
158
|
+
file,
|
|
159
|
+
id: (0, _helpers.uuid)(),
|
|
160
|
+
reject: false,
|
|
161
|
+
rejectReason: undefined,
|
|
162
|
+
success: true,
|
|
163
|
+
successMessage: undefined,
|
|
164
|
+
progress: undefined,
|
|
165
|
+
showReUpload: false
|
|
166
|
+
}));
|
|
167
|
+
dispatch({
|
|
168
|
+
type: 'ADD_VALID_FILES',
|
|
169
|
+
files: validFiles
|
|
170
|
+
});
|
|
171
|
+
onValidFilesDrop?.(validFiles);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// Callbacks for when files are dropped / selected and are invalid
|
|
175
|
+
const handleDropRejected = fileRejections => {
|
|
176
|
+
const rejectedFiles = fileRejections.map(_ref2 => {
|
|
177
|
+
let {
|
|
178
|
+
file,
|
|
179
|
+
errors
|
|
180
|
+
} = _ref2;
|
|
181
|
+
return {
|
|
182
|
+
file,
|
|
183
|
+
id: (0, _helpers.uuid)(),
|
|
184
|
+
reject: true,
|
|
185
|
+
rejectReason: DROPZONE_ERROR_MESSAGES[errors[0].code] || 'Some error occurred uploading this file',
|
|
186
|
+
success: false,
|
|
187
|
+
successMessage: undefined,
|
|
188
|
+
progress: undefined,
|
|
189
|
+
showReUpload: false
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
dispatch({
|
|
193
|
+
type: 'ADD_REJECTED_FILES',
|
|
194
|
+
files: rejectedFiles
|
|
195
|
+
});
|
|
196
|
+
onRejectedFilesDrop?.(rejectedFiles);
|
|
197
|
+
};
|
|
198
|
+
const handleFileClear = id => {
|
|
199
|
+
dispatch({
|
|
200
|
+
type: 'REMOVE_FILE',
|
|
201
|
+
id
|
|
202
|
+
});
|
|
203
|
+
onFileClear?.(id);
|
|
204
|
+
};
|
|
205
|
+
const handleClear = () => {
|
|
206
|
+
dispatch({
|
|
207
|
+
type: 'CLEAR_FILES'
|
|
208
|
+
});
|
|
209
|
+
onClear?.();
|
|
210
|
+
};
|
|
211
|
+
const moveFileToProgress = (id, progress) => {
|
|
212
|
+
dispatch({
|
|
213
|
+
type: 'UPDATE_FILE_PROGRESS',
|
|
214
|
+
id,
|
|
215
|
+
progress
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Note(Nishant): If the file is found in rejected files, we move it to valid files first in the reducer
|
|
220
|
+
const moveFileToSuccess = (id, successMessage) => {
|
|
221
|
+
dispatch({
|
|
222
|
+
type: 'SET_FILE_SUCCESS',
|
|
223
|
+
id,
|
|
224
|
+
successMessage
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Note(Nishant): If the file is found in valid files, we move it to rejected files first in the reducer
|
|
229
|
+
const moveFileToReject = (id, rejectReason) => {
|
|
230
|
+
dispatch({
|
|
231
|
+
type: 'SET_FILE_REJECT',
|
|
232
|
+
id,
|
|
233
|
+
rejectReason
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// Note: This is used to show the re-upload button on the file
|
|
238
|
+
const setShowReUpload = (id, showReUpload) => {
|
|
239
|
+
dispatch({
|
|
240
|
+
type: 'SET_FILE_RE_UPLOAD',
|
|
241
|
+
id,
|
|
242
|
+
showReUpload
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
const totalFiles = state.validFiles.length + state.rejectedFiles.length;
|
|
246
|
+
const shouldAcceptFiles = !disabled && (maxFiles === 0 || totalFiles < maxFiles);
|
|
247
|
+
|
|
248
|
+
// We are using react-dropzone's useDropzone hook to get the drag and drop props
|
|
249
|
+
const {
|
|
250
|
+
isDragActive,
|
|
251
|
+
getRootProps,
|
|
252
|
+
getInputProps
|
|
253
|
+
} = (0, _reactDropzone.useDropzone)({
|
|
254
|
+
maxFiles,
|
|
255
|
+
multiple: maxFiles > 1 || maxFiles === 0,
|
|
256
|
+
maxSize,
|
|
257
|
+
accept,
|
|
258
|
+
disabled,
|
|
259
|
+
noClick: !shouldAcceptFiles,
|
|
260
|
+
noDrag: !shouldAcceptFiles,
|
|
261
|
+
onDropAccepted: handleDropAccepted,
|
|
262
|
+
onDropRejected: handleDropRejected
|
|
263
|
+
});
|
|
264
|
+
return {
|
|
265
|
+
validFiles: state.validFiles,
|
|
266
|
+
rejectedFiles: state.rejectedFiles,
|
|
267
|
+
shouldAcceptFiles,
|
|
268
|
+
isDragActive,
|
|
269
|
+
getRootProps,
|
|
270
|
+
getInputProps,
|
|
271
|
+
handleFileClear,
|
|
272
|
+
handleClear,
|
|
273
|
+
moveFileToProgress,
|
|
274
|
+
moveFileToSuccess,
|
|
275
|
+
moveFileToReject,
|
|
276
|
+
setShowReUpload
|
|
277
|
+
};
|
|
278
|
+
};
|
|
279
|
+
exports.useFileUpload = useFileUpload;
|