@onewelcome/react-lib-components 1.6.0 → 1.8.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/README.md +4 -4
- package/dist/Form/FileUpload/FileItem/FileItem.d.ts +17 -0
- package/dist/Form/FileUpload/FileUpload.d.ts +26 -0
- package/dist/Icon/Icon.d.ts +4 -1
- package/dist/ProgressBar/ProgressBar.d.ts +2 -1
- package/dist/Typography/Typography.d.ts +1 -1
- package/dist/_BaseStyling_/BaseStyling.d.ts +23 -0
- package/dist/hooks/useUploadFile.d.ts +22 -0
- package/dist/react-lib-components.cjs.development.js +130 -98
- package/dist/react-lib-components.cjs.development.js.map +1 -1
- package/dist/react-lib-components.cjs.production.min.js +1 -1
- package/dist/react-lib-components.cjs.production.min.js.map +1 -1
- package/dist/react-lib-components.esm.js +130 -98
- package/dist/react-lib-components.esm.js.map +1 -1
- package/dist/util/helper.d.ts +7 -0
- package/package.json +24 -21
- package/src/Breadcrumbs/Breadcrumbs.module.scss +2 -2
- package/src/Button/Button.module.scss +14 -2
- package/src/ContextMenu/ContextMenuItem.module.scss +1 -0
- package/src/DataGrid/DataGridHeader/DataGridHeader.module.scss +1 -1
- package/src/DataGrid/DataGridHeader/DataGridHeaderCell.module.scss +1 -1
- package/src/Form/Fieldset/Fieldset.module.scss +8 -1
- package/src/Form/FileUpload/FileItem/FileItem.modules.scss +75 -0
- package/src/Form/FileUpload/FileItem/FileItem.test.tsx +103 -0
- package/src/Form/FileUpload/FileItem/FileItem.tsx +141 -0
- package/src/Form/FileUpload/FileUpload.module.scss +106 -0
- package/src/Form/FileUpload/FileUpload.test.tsx +374 -0
- package/src/Form/FileUpload/FileUpload.tsx +251 -0
- package/src/Form/Input/Input.module.scss +9 -3
- package/src/Form/Select/Select.module.scss +26 -3
- package/src/Form/Wrapper/InputWrapper/InputWrapper.tsx +3 -1
- package/src/Form/Wrapper/SelectWrapper/SelectWrapper.module.scss +9 -1
- package/src/Form/Wrapper/Wrapper/Wrapper.module.scss +11 -2
- package/src/Icon/Icon.module.scss +12 -0
- package/src/Icon/Icon.tsx +4 -1
- package/src/Link/Link.module.scss +1 -1
- package/src/Notifications/Banner/Banner.module.scss +2 -2
- package/src/Pagination/Pagination.module.scss +1 -0
- package/src/ProgressBar/ProgressBar.module.scss +11 -9
- package/src/ProgressBar/ProgressBar.test.tsx +21 -0
- package/src/ProgressBar/ProgressBar.tsx +7 -2
- package/src/Tabs/TabButton.module.scss +3 -3
- package/src/Tabs/Tabs.module.scss +1 -0
- package/src/Typography/Typography.module.scss +4 -4
- package/src/Typography/Typography.tsx +1 -1
- package/src/Wizard/BaseWizardSteps/BaseWizardSteps.module.scss +17 -7
- package/src/_BaseStyling_/BaseStyling.tsx +73 -27
- package/src/hooks/useUploadFile.test.ts +211 -0
- package/src/hooks/useUploadFile.tsx +136 -0
- package/src/mixins.module.scss +26 -7
- package/src/util/helper.test.tsx +188 -16
- package/src/util/helper.tsx +38 -0
- package/src/variables.scss +18 -0
package/dist/util/helper.d.ts
CHANGED
|
@@ -5,4 +5,11 @@ export declare const generateID: (length?: number, stringToWeaveIn?: string) =>
|
|
|
5
5
|
export declare const filterProps: (props: any, regexPattern: RegExp, returnFiltered?: boolean) => KeyValuePair;
|
|
6
6
|
export declare const debounce: (fn: (...args: unknown[]) => unknown, delay: number) => (...args: unknown[]) => void;
|
|
7
7
|
export declare const throttle: (fn: (...args: unknown[]) => unknown, delay: number) => () => void;
|
|
8
|
+
export declare const isEqual: (x: any, y: any) => boolean;
|
|
9
|
+
export declare const areArraysDifferent: (arr1: Record<string, any>[], arr2: Record<string, any>[], key: string) => boolean;
|
|
10
|
+
export declare const getValueByPath: (obj: {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}, path: string) => any;
|
|
13
|
+
/** Source: https://stackoverflow.com/a/42769683/5084110 */
|
|
14
|
+
export declare const remToPx: (rem: number) => number;
|
|
8
15
|
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"homepage": "http://onewelcome.github.io/react-lib-components",
|
|
3
3
|
"name": "@onewelcome/react-lib-components",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.8.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "OneWelcome B.V.",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"analyze": "size-limit --why",
|
|
23
23
|
"build": "dts build",
|
|
24
24
|
"build-storybook": "build-storybook",
|
|
25
|
+
"chromatic": "chromatic --exit-zero-on-changes",
|
|
25
26
|
"dev": "npm-run-all -p start test:watch storybook",
|
|
26
27
|
"lint": "eslint '**/*.{ts,tsx}'",
|
|
27
28
|
"prepare": "husky install && dts build",
|
|
@@ -52,20 +53,20 @@
|
|
|
52
53
|
}
|
|
53
54
|
],
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@babel/core": "^7.
|
|
56
|
+
"@babel/core": "^7.21.0",
|
|
56
57
|
"@mdx-js/react": "^1.6.22",
|
|
57
58
|
"@onewelcome/eslint-config-shared-codestyle": "^9.0.3",
|
|
58
|
-
"@size-limit/preset-small-lib": "^8.
|
|
59
|
-
"@storybook/addon-a11y": "^6.5.
|
|
60
|
-
"@storybook/addon-docs": "^6.5.
|
|
61
|
-
"@storybook/addon-essentials": "^6.5.
|
|
62
|
-
"@storybook/addon-links": "^6.5.
|
|
63
|
-
"@storybook/addons": "^6.5.
|
|
64
|
-
"@storybook/builder-webpack5": "^6.5.
|
|
65
|
-
"@storybook/manager-webpack5": "^6.5.
|
|
59
|
+
"@size-limit/preset-small-lib": "^8.2.4",
|
|
60
|
+
"@storybook/addon-a11y": "^6.5.16",
|
|
61
|
+
"@storybook/addon-docs": "^6.5.16",
|
|
62
|
+
"@storybook/addon-essentials": "^6.5.16",
|
|
63
|
+
"@storybook/addon-links": "^6.5.16",
|
|
64
|
+
"@storybook/addons": "^6.5.16",
|
|
65
|
+
"@storybook/builder-webpack5": "^6.5.16",
|
|
66
|
+
"@storybook/manager-webpack5": "^6.5.16",
|
|
66
67
|
"@storybook/preset-scss": "^1.0.3",
|
|
67
|
-
"@storybook/react": "^6.5.
|
|
68
|
-
"@storybook/theming": "^6.5.
|
|
68
|
+
"@storybook/react": "^6.5.16",
|
|
69
|
+
"@storybook/theming": "^6.5.16",
|
|
69
70
|
"@testing-library/dom": "^8.20.0",
|
|
70
71
|
"@testing-library/jest-dom": "^5.16.5",
|
|
71
72
|
"@testing-library/react": "^12.1.5",
|
|
@@ -79,11 +80,12 @@
|
|
|
79
80
|
"@types/react-dom": "^17.0.18",
|
|
80
81
|
"@types/react-router": "^5.1.20",
|
|
81
82
|
"@types/react-router-dom": "^5.3.3",
|
|
82
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
83
|
-
"@typescript-eslint/parser": "^5.
|
|
83
|
+
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
|
84
|
+
"@typescript-eslint/parser": "^5.53.0",
|
|
84
85
|
"babel-loader": "^9.1.2",
|
|
86
|
+
"chromatic": "^6.17.1",
|
|
85
87
|
"dts-cli": "^1.6.3",
|
|
86
|
-
"eslint": "^8.
|
|
88
|
+
"eslint": "^8.34.0",
|
|
87
89
|
"eslint-config-prettier": "^8.6.0",
|
|
88
90
|
"eslint-plugin-cypress": "^2.12.1",
|
|
89
91
|
"eslint-plugin-jest": "^27.2.1",
|
|
@@ -93,19 +95,20 @@
|
|
|
93
95
|
"husky": "^8.0.3",
|
|
94
96
|
"identity-obj-proxy": "^3.0.0",
|
|
95
97
|
"jest-junit": "^15.0.0",
|
|
96
|
-
"lint-staged": "^13.1.
|
|
98
|
+
"lint-staged": "^13.1.2",
|
|
97
99
|
"npm-run-all": "^4.1.5",
|
|
98
|
-
"prettier": "^2.8.
|
|
100
|
+
"prettier": "^2.8.4",
|
|
99
101
|
"react": "^17.0.2",
|
|
100
102
|
"react-dom": "^17.0.2",
|
|
101
103
|
"react-is": "^18.2.0",
|
|
102
104
|
"react-router": "^6.6.2",
|
|
103
|
-
"react-router-dom": "^6.
|
|
105
|
+
"react-router-dom": "^6.8.2",
|
|
104
106
|
"rollup-plugin-cleanup": "^3.2.1",
|
|
105
107
|
"rollup-plugin-styles": "^4.0.0",
|
|
106
|
-
"sass": "^1.
|
|
108
|
+
"sass": "^1.58.3",
|
|
107
109
|
"size-limit": "^8.1.1",
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
+
"style-loader": "^3.3.1",
|
|
111
|
+
"tslib": "^2.5.0",
|
|
112
|
+
"typescript": "^4.9.5"
|
|
110
113
|
}
|
|
111
114
|
}
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
|
|
17
17
|
.breadcrumbs {
|
|
18
18
|
.last {
|
|
19
|
-
color: var(--
|
|
19
|
+
color: var(--color-primary);
|
|
20
20
|
margin: 0;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
.icon {
|
|
24
|
-
color: var(--
|
|
24
|
+
color: var(--color-primary);
|
|
25
25
|
font-size: 0.75rem;
|
|
26
26
|
line-height: 1.5rem;
|
|
27
27
|
margin-left: 0.375rem;
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
align-items: center;
|
|
34
34
|
|
|
35
35
|
&.start-icon {
|
|
36
|
-
padding-left:
|
|
36
|
+
padding-left: 0.75rem;
|
|
37
37
|
padding-right: 1.25rem;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
&.end-icon {
|
|
41
41
|
padding-left: 1.25rem;
|
|
42
|
-
padding-right:
|
|
42
|
+
padding-right: 0.75rem;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
i {
|
|
@@ -51,3 +51,15 @@
|
|
|
51
51
|
margin-right: 0.25rem;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
@media only screen and (min-width: 30em) {
|
|
56
|
+
.has-icon {
|
|
57
|
+
&.start-icon {
|
|
58
|
+
padding-left: 1rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&.end-icon {
|
|
62
|
+
padding-right: 1rem;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
@use "src/variables";
|
|
18
|
+
|
|
17
19
|
.fieldset {
|
|
18
20
|
border: 0;
|
|
19
|
-
padding: 1rem
|
|
21
|
+
padding: 1rem variables.$form-element-horizontal-padding-mobile;
|
|
20
22
|
border-radius: 0.5rem;
|
|
21
23
|
margin: 0;
|
|
22
24
|
|
|
@@ -43,3 +45,8 @@
|
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
}
|
|
48
|
+
@media only screen and (min-width: 30em) {
|
|
49
|
+
.fieldset {
|
|
50
|
+
padding: 1rem variables.$form-element-horizontal-padding-desktop;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
@import "../../../mixins.module.scss";
|
|
18
|
+
|
|
19
|
+
.file-item-wrapper {
|
|
20
|
+
padding: 0.5rem 1.25rem;
|
|
21
|
+
border-radius: var(--input-border-radius);
|
|
22
|
+
background-color: var(--input-background-color);
|
|
23
|
+
@include transition(all, 0.2s, ease-in-out);
|
|
24
|
+
|
|
25
|
+
[class*="icon"] {
|
|
26
|
+
font-size: 1.25rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.progress-bar {
|
|
30
|
+
background-color: var(--light-pink);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
span[class*="bar--"] {
|
|
34
|
+
border-radius: var(--input-border-radius);
|
|
35
|
+
height: 1rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.file-name {
|
|
39
|
+
margin: 0;
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
.friendly-name {
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
text-overflow: ellipsis;
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.action-icon {
|
|
50
|
+
margin-left: auto;
|
|
51
|
+
color: var(--color-primary);
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
padding-left: 1.25rem;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.file-icon {
|
|
57
|
+
margin-right: 0.5rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.file-subtitle,
|
|
61
|
+
.progress-bar {
|
|
62
|
+
display: block;
|
|
63
|
+
margin: 0.3125rem 1.75rem;
|
|
64
|
+
padding: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.error,
|
|
68
|
+
.retry {
|
|
69
|
+
color: var(--error);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.readonly {
|
|
73
|
+
color: var(--greyed-out);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FILE_ACTION, FileItem, Props } from "./FileItem";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import user from "@testing-library/user-event";
|
|
5
|
+
|
|
6
|
+
const defaultParams: Props = {
|
|
7
|
+
name: "Test.txt"
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const createFileItem = (params?: (defaultParams: Props) => Props) => {
|
|
11
|
+
let parameters: Props = defaultParams;
|
|
12
|
+
if (params) {
|
|
13
|
+
parameters = params(defaultParams);
|
|
14
|
+
}
|
|
15
|
+
const queries = render(<FileItem {...parameters} />);
|
|
16
|
+
const component = queries.getByLabelText(`${parameters.name}-wrapper`);
|
|
17
|
+
const title = component.querySelector(".file-name");
|
|
18
|
+
const fileIcon = component.querySelector(".file-icon");
|
|
19
|
+
const actionIcon = component.querySelector(".action-icon");
|
|
20
|
+
const errorSubtitle = component.querySelector(".file-subtitle");
|
|
21
|
+
const progressBar = component.querySelector(".progress-bar");
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
...queries,
|
|
25
|
+
component,
|
|
26
|
+
title,
|
|
27
|
+
fileIcon,
|
|
28
|
+
actionIcon,
|
|
29
|
+
errorSubtitle,
|
|
30
|
+
progressBar
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
describe("component should render", () => {
|
|
35
|
+
it("renders without crashing", () => {
|
|
36
|
+
const { component } = createFileItem();
|
|
37
|
+
|
|
38
|
+
expect(component).toBeDefined();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("component should change display the correct style and elements according to the status", () => {
|
|
43
|
+
it("should show the correct details for completed", () => {
|
|
44
|
+
const { actionIcon, title } = createFileItem(defaultParams => ({
|
|
45
|
+
...defaultParams,
|
|
46
|
+
status: "completed"
|
|
47
|
+
}));
|
|
48
|
+
expect(title).toHaveClass("completed");
|
|
49
|
+
expect(actionIcon).toHaveAttribute("title", FILE_ACTION.DELETE);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should show the correct details for uploading", () => {
|
|
53
|
+
const { actionIcon, title, progressBar } = createFileItem(defaultParams => ({
|
|
54
|
+
...defaultParams,
|
|
55
|
+
status: "uploading"
|
|
56
|
+
}));
|
|
57
|
+
expect(title).toHaveClass("uploading");
|
|
58
|
+
expect(actionIcon).toHaveAttribute("title", FILE_ACTION.ABORT);
|
|
59
|
+
expect(progressBar).toBeDefined();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should show the correct details for readonly", () => {
|
|
63
|
+
const { actionIcon, title } = createFileItem(defaultParams => ({
|
|
64
|
+
...defaultParams,
|
|
65
|
+
status: "readonly"
|
|
66
|
+
}));
|
|
67
|
+
expect(title).toHaveClass("readonly");
|
|
68
|
+
expect(actionIcon).toBeNull();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should show the correct details for error", () => {
|
|
72
|
+
const { actionIcon, title, errorSubtitle } = createFileItem(defaultParams => ({
|
|
73
|
+
...defaultParams,
|
|
74
|
+
status: "error"
|
|
75
|
+
}));
|
|
76
|
+
expect(title).toHaveClass("error");
|
|
77
|
+
expect(actionIcon).toHaveAttribute("title", FILE_ACTION.REMOVE);
|
|
78
|
+
expect(errorSubtitle).toBeDefined();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should show the correct details for retry", () => {
|
|
82
|
+
const { actionIcon, title } = createFileItem(defaultParams => ({
|
|
83
|
+
...defaultParams,
|
|
84
|
+
status: "retry"
|
|
85
|
+
}));
|
|
86
|
+
expect(title).toHaveClass("retry");
|
|
87
|
+
expect(actionIcon).toHaveAttribute("title", FILE_ACTION.RETRY);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("component should transmit the correct message upwards when a file action icon is clicked", () => {
|
|
92
|
+
it("should call retry action", () => {
|
|
93
|
+
const onRequestedFileAction = jest.fn();
|
|
94
|
+
const { actionIcon } = createFileItem(defaultParams => ({
|
|
95
|
+
...defaultParams,
|
|
96
|
+
status: "retry",
|
|
97
|
+
onRequestedFileAction
|
|
98
|
+
}));
|
|
99
|
+
|
|
100
|
+
user.click(actionIcon as Element);
|
|
101
|
+
expect(onRequestedFileAction).toHaveBeenNthCalledWith(1, FILE_ACTION.RETRY, defaultParams.name);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import React, { ComponentPropsWithRef, ForwardRefRenderFunction } from "react";
|
|
18
|
+
import classes from "./FileItem.modules.scss";
|
|
19
|
+
import { Typography } from "../../../Typography/Typography";
|
|
20
|
+
import { Icon, Icons } from "../../../Icon/Icon";
|
|
21
|
+
import { ProgressBar } from "../../../ProgressBar/ProgressBar";
|
|
22
|
+
import { FileType } from "../FileUpload";
|
|
23
|
+
|
|
24
|
+
export type UploadProgress = "uploading" | "completed" | "error" | "readonly" | "retry";
|
|
25
|
+
|
|
26
|
+
export interface Props extends ComponentPropsWithRef<"div"> {
|
|
27
|
+
name: string;
|
|
28
|
+
status?: UploadProgress;
|
|
29
|
+
progress?: number;
|
|
30
|
+
error?: string;
|
|
31
|
+
onRequestedFileAction?: (action: FILE_ACTION, name: FileType["name"]) => void;
|
|
32
|
+
}
|
|
33
|
+
interface FileItemIcons {
|
|
34
|
+
fileIcon: Icons;
|
|
35
|
+
actionIcon?: { type: Icons; action: FILE_ACTION };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export enum FILE_ACTION {
|
|
39
|
+
DELETE = "delete",
|
|
40
|
+
REMOVE = "remove",
|
|
41
|
+
ABORT = "abort",
|
|
42
|
+
RETRY = "retry"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const FileItemComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
46
|
+
{ name, status, error, progress, onRequestedFileAction }: Props,
|
|
47
|
+
ref
|
|
48
|
+
) => {
|
|
49
|
+
const determineIcons = (status?: UploadProgress): FileItemIcons => {
|
|
50
|
+
switch (status) {
|
|
51
|
+
case "completed":
|
|
52
|
+
return {
|
|
53
|
+
fileIcon: Icons.FileOutline,
|
|
54
|
+
actionIcon: {
|
|
55
|
+
type: Icons.Trash,
|
|
56
|
+
action: FILE_ACTION.DELETE
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
case "error":
|
|
60
|
+
return {
|
|
61
|
+
fileIcon: Icons.InfoCircle,
|
|
62
|
+
actionIcon: {
|
|
63
|
+
type: Icons.Times,
|
|
64
|
+
action: FILE_ACTION.REMOVE
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
case "uploading":
|
|
68
|
+
return {
|
|
69
|
+
fileIcon: Icons.FileUpload,
|
|
70
|
+
actionIcon: {
|
|
71
|
+
type: Icons.Times,
|
|
72
|
+
action: FILE_ACTION.ABORT
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
case "retry":
|
|
76
|
+
return {
|
|
77
|
+
fileIcon: Icons.InfoCircle,
|
|
78
|
+
actionIcon: {
|
|
79
|
+
type: Icons.Refresh,
|
|
80
|
+
action: FILE_ACTION.RETRY
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
case "readonly":
|
|
84
|
+
default:
|
|
85
|
+
return { fileIcon: Icons.FileOutline };
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const icons = determineIcons(status);
|
|
90
|
+
|
|
91
|
+
const getFriendlyNameAndExtension = (name: string) => {
|
|
92
|
+
const index = name.indexOf(".");
|
|
93
|
+
return { friendlyName: name.slice(0, index), extension: name.slice(index + 1) };
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const { friendlyName, extension } = getFriendlyNameAndExtension(name);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<div ref={ref} className={classes["file-item-wrapper"]} aria-label={`${name}-wrapper`}>
|
|
100
|
+
<Typography
|
|
101
|
+
variant={"body"}
|
|
102
|
+
title={name}
|
|
103
|
+
className={`${classes["file-name"]} ${status ? classes[status] : ""}`}
|
|
104
|
+
>
|
|
105
|
+
<Icon icon={icons.fileIcon} className={classes["file-icon"]} />
|
|
106
|
+
<span className={classes["friendly-name"]}>{friendlyName}</span>.<span>{extension}</span>
|
|
107
|
+
{icons.actionIcon && (
|
|
108
|
+
<Icon
|
|
109
|
+
title={icons.actionIcon.action}
|
|
110
|
+
icon={icons.actionIcon.type}
|
|
111
|
+
className={classes["action-icon"]}
|
|
112
|
+
onClick={() =>
|
|
113
|
+
icons.actionIcon &&
|
|
114
|
+
onRequestedFileAction &&
|
|
115
|
+
onRequestedFileAction(icons.actionIcon.action, name)
|
|
116
|
+
}
|
|
117
|
+
/>
|
|
118
|
+
)}
|
|
119
|
+
</Typography>
|
|
120
|
+
{error && (
|
|
121
|
+
<Typography
|
|
122
|
+
variant={"sub-text"}
|
|
123
|
+
className={`${classes["file-subtitle"]} ${status ? classes[status] : ""}`}
|
|
124
|
+
>
|
|
125
|
+
{error}
|
|
126
|
+
</Typography>
|
|
127
|
+
)}
|
|
128
|
+
{status === "uploading" ? (
|
|
129
|
+
<ProgressBar
|
|
130
|
+
className={classes["progress-bar"]}
|
|
131
|
+
placeholderText={""}
|
|
132
|
+
completed={progress}
|
|
133
|
+
/>
|
|
134
|
+
) : (
|
|
135
|
+
""
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const FileItem = React.forwardRef(FileItemComponent);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
@import "../../mixins.module.scss";
|
|
18
|
+
|
|
19
|
+
.file-upload-wrapper {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.file-dropzone {
|
|
25
|
+
border-radius: var(--input-border-radius);
|
|
26
|
+
background-color: var(--input-background-color);
|
|
27
|
+
padding: 1.25rem;
|
|
28
|
+
position: relative;
|
|
29
|
+
@include transition(all, 0.2s, ease-in-out);
|
|
30
|
+
&.drag-active {
|
|
31
|
+
@include outline(
|
|
32
|
+
var(--color-primary),
|
|
33
|
+
var(--drag-border-style),
|
|
34
|
+
var(--input-border-width),
|
|
35
|
+
var(--input-border-radius),
|
|
36
|
+
var(--drag-background-color)
|
|
37
|
+
);
|
|
38
|
+
@include outlineStates;
|
|
39
|
+
}
|
|
40
|
+
&.error {
|
|
41
|
+
span[data-icon-status],
|
|
42
|
+
.file-upload-title,
|
|
43
|
+
.file-selector-sub-text {
|
|
44
|
+
color: var(--error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
&.success {
|
|
48
|
+
span[data-icon-status] {
|
|
49
|
+
color: var(--success);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&.disabled {
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
background-color: var(--disabled);
|
|
56
|
+
color: var(--greyed-out);
|
|
57
|
+
}
|
|
58
|
+
span[data-icon-status] {
|
|
59
|
+
font-size: 1.25rem;
|
|
60
|
+
position: absolute;
|
|
61
|
+
top: 2.74rem;
|
|
62
|
+
right: 1.375rem;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.file-select {
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
[class*="file"] {
|
|
71
|
+
font-size: 1.25rem;
|
|
72
|
+
}
|
|
73
|
+
[class*="typography"] {
|
|
74
|
+
margin-bottom: 0.625rem;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.upload-input {
|
|
79
|
+
display: block;
|
|
80
|
+
width: 100%;
|
|
81
|
+
border: none;
|
|
82
|
+
text-transform: none;
|
|
83
|
+
position: absolute;
|
|
84
|
+
top: 0;
|
|
85
|
+
left: 0;
|
|
86
|
+
right: 0;
|
|
87
|
+
bottom: 0;
|
|
88
|
+
opacity: 0;
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
&:focus {
|
|
91
|
+
outline: none;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.file-upload-btn {
|
|
96
|
+
position: relative;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.file-list {
|
|
100
|
+
list-style: none;
|
|
101
|
+
padding: 0;
|
|
102
|
+
margin: 0.75rem 0;
|
|
103
|
+
li:not(:last-child) {
|
|
104
|
+
margin-bottom: 0.5rem;
|
|
105
|
+
}
|
|
106
|
+
}
|