Skip to content

Commit fa99f82

Browse files
committed
new control UploadFiles
1 parent f28e4d4 commit fa99f82

File tree

18 files changed

+433
-336
lines changed

18 files changed

+433
-336
lines changed
702 KB
Loading
589 KB
Loading

docs/documentation/docs/controls/UploadFiles.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# UploadFiles
22

3-
This control allows to drag and drop files and manage files before upload.
3+
This control allows to drag and drop files and manage files before upload.
44

55
## How to use this control in your solutions
66

@@ -17,7 +17,7 @@ import {
1717

1818
```jsx
1919
<UploadFiles
20-
pageSize={30}
20+
pageSize={20}
2121
context={context}
2222
title="Upload Files"
2323
onUploadFiles={(files) => {
@@ -28,15 +28,17 @@ import {
2828
```
2929

3030

31-
![Custom html with drag and drop](../assets/UploadFiles.gif)
32-
31+
![uploadFiles](../assets/UploadFiles.gif)
32+
![uploadFiles](../assets/UploadFiles02.png)
33+
![uploadFiles](../assets/UploadFiles01.png)
34+
3335
## Implementation
3436

3537
The `UploadFiles` can be configured with the following properties:
3638

3739
| Property | Type | Required | Description |
3840
| ---- | ---- | ---- | ---- |
39-
| pageSize | number | no | number of files to show per page base on this value the height is calculate |
41+
| pageSize | number | no | number of files to show per page base on this value the height of control is calculate, default 15 |
4042
| context | WebPartContext | yes | webPartContext |
4143
| title | string | yes | title |
4244
| onUploadFiles | (files: File[]) => void; | yes | Method that returns all Files[] |

src/controls/uploadFiles/components/DocumentList/DocumentList.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ import { useDocumentListStyles } from './useDocumentListStyles';
2828
export const DocumentList: React.FunctionComponent<IDocumentListProps> = (
2929
props: React.PropsWithChildren<IDocumentListProps>
3030
) => {
31-
const { documentListStyles, scollableContainerStyles } = useDocumentListStyles();
31+
const { documentListStyles, scollableContainerStyles, bootomContainerStyles } = useDocumentListStyles();
3232
const [appGlobalState, setGlobalState] = useAtom(globalState);
3333
const [renderFiles, setRenderFiles] = React.useState<React.ReactNode[]>([]);
34-
const { selectedFiles, files, containerWidth } = appGlobalState;
34+
const { selectedFiles, files, containerWidth, themeVariant } = appGlobalState;
3535
const currentPage = React.useRef<number>(0);
3636
const currentFiles = React.useRef<File[]>([]);
3737
const { onUploadFiles } = props;
@@ -88,7 +88,7 @@ export const DocumentList: React.FunctionComponent<IDocumentListProps> = (
8888
return { ...prevState, files: newsFiles };
8989
});
9090
},
91-
[files]
91+
[files, themeVariant]
9292
);
9393

9494
const onDelete = React.useCallback(() => {
@@ -161,23 +161,26 @@ export const DocumentList: React.FunctionComponent<IDocumentListProps> = (
161161
<ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto} styles={scollableContainerStyles}>
162162
<div className={documentListStyles.documentList}>
163163
<DragDropFiles dropEffect="upload" enable={true} onDrop={onDrop}>
164-
<div style={{ padding: 20 }}>
164+
<Stack tokens={{ padding: 20 }}>
165165
{renderFiles.length ? (
166166
<div className={documentListStyles.filesContainerGrid}>{renderFiles}</div>
167167
) : (
168168
<NoDocuments />
169169
)}
170-
</div>
170+
</Stack>
171171
</DragDropFiles>
172172
</div>
173173
</ScrollablePane>
174-
<Stack horizontalAlign="end" tokens={{ childrenGap: 20, padding: 20 }}>
174+
<Stack styles={bootomContainerStyles} horizontalAlign="end" tokens={{ childrenGap: 20, }}>
175+
<div className={documentListStyles.separator} />
175176
{selectedFiles.length > 0 && (
176-
<PrimaryButton
177-
iconProps={{ iconName: "upload" }}
178-
text={strings.UploadFilesUploadButtonLabel}
179-
onClick={() => onUploadFiles(selectedFiles)}
180-
/>
177+
<>
178+
<PrimaryButton
179+
iconProps={{ iconName: "upload" }}
180+
text={strings.UploadFilesUploadButtonLabel}
181+
onClick={() => onUploadFiles(selectedFiles)}
182+
/>
183+
</>
181184
)}
182185
</Stack>
183186
</div>

src/controls/uploadFiles/components/DocumentList/useDocumentListStyles.ts

Lines changed: 93 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -6,90 +6,114 @@ import { useAtomValue } from 'jotai/utils';
66

77
import {
88
IScrollablePaneStyles,
9+
IStackStyles,
910
mergeStyles,
1011
mergeStyleSets,
1112
} from '@fluentui/react';
1213

14+
import { DEFAULT_PAGE_SIZE } from '../../constants/constants';
1315
import { globalState } from '../../jotai/atoms';
1416

15-
const DEFAULT_PAGE_SIZE = 15;
1617
/* eslint-disable @typescript-eslint/no-empty-function */
1718
export const useDocumentListStyles = () => {
18-
const appGlobalState = useAtomValue(globalState);
19-
const {themeVariant , containerWidth, pageSize, files} = appGlobalState;
19+
const appGlobalState = useAtomValue(globalState);
20+
const { themeVariant, containerWidth, pageSize, files } = appGlobalState;
2021

21-
const scollableContainerStyles: Partial<IScrollablePaneStyles> = React.useMemo(() => {
22-
return {
23-
/* root: { position: "relative", height: '100%', minHeight: 500, overflowY: 'auto', overflowX: 'hidden' */
24-
root: { position: "relative", height: containerWidth && files.length ? ((Math.ceil(pageSize ?? DEFAULT_PAGE_SIZE )/Math.ceil(containerWidth/180))) * 180 : 0 , minHeight: 500, overflowY: 'auto', overflowX: 'hidden'
25-
},
26-
contentContainer: { "::-webkit-scrollbar-thumb": {
22+
const containerHeight = React.useMemo(() => {
23+
return containerWidth && files.length
24+
? (Math.ceil(pageSize ?? DEFAULT_PAGE_SIZE) / Math.ceil(containerWidth / 180)) * 180
25+
: 0;
2726

28-
backgroundColor: themeVariant?.palette.themeLight},
29-
"::-webkit-scrollbar": {
30-
height: 10,
31-
width: 7,
27+
}, [containerWidth, pageSize, files]);
3228

33-
},
34-
"scrollbar-color": themeVariant?.semanticColors.bodyFrameBackground,
35-
"scrollbar-width": "thin", },
36-
};
37-
}, [themeVariant ,containerWidth, pageSize, files]);
29+
const bootomContainerStyles:IStackStyles = React.useMemo(() => {
30+
return {
31+
root: {
32+
paddingLeft: 20,
33+
paddingRight: 20,
34+
}
35+
}
36+
}, [themeVariant]);
37+
38+
const scollableContainerStyles: Partial<IScrollablePaneStyles> = React.useMemo(() => {
39+
return {
3840

39-
const documentListStyles = React.useMemo( () => { return mergeStyleSets({
40-
fileIconHeaderIcon: ({
41-
padding: 0,
42-
fontSize: "16px",
43-
}),
44-
fileIconCell: mergeStyles({
45-
textAlign: "center",
46-
selectors: {
47-
"&:before": {
48-
content: ".",
49-
display: "inline-block",
50-
verticalAlign: "middle",
51-
height: "100%",
52-
width: "0px",
53-
visibility: "hidden",
41+
root: {
42+
position: "relative",
43+
height: containerHeight,
44+
minHeight: 500,
45+
overflowY: "auto",
46+
overflowX: "hidden",
47+
},
48+
contentContainer: {
49+
"::-webkit-scrollbar-thumb": {
50+
backgroundColor: themeVariant?.palette.themeLight,
51+
},
52+
"::-webkit-scrollbar": {
53+
height: 10,
54+
width: 7,
5455
},
56+
"scrollbar-color": themeVariant?.semanticColors.bodyFrameBackground,
57+
"scrollbar-width": "thin",
5558
},
56-
}),
57-
fileIconImg: mergeStyles({
58-
verticalAlign: "middle",
59-
maxHeight: "16px",
60-
maxWidth: "16px",
61-
}),
62-
controlWrapper: mergeStyles({
63-
display: "flex",
64-
flexWrap: "wrap",
65-
}),
66-
67-
selectionDetails: mergeStyles({
68-
marginBottom: "20px",
69-
}),
70-
filesContainerGrid: mergeStyles({
71-
72-
width: "100%",
73-
display: "grid",
74-
gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 160px), 1fr))",
75-
columnGap: "15px",
76-
rowGap: 15,
77-
} ),
59+
};
60+
}, [themeVariant, containerHeight]);
7861

79-
noDataFoundStyles: {
80-
width: "300px", height: "300px",
81-
},
82-
separator: mergeStyles({
83-
height: "1px",
84-
backgroundColor: themeVariant?.palette?.neutralLight,
85-
opacity: themeVariant?.isInverted ? "0.2" : "1",
86-
}),
87-
documentList: mergeStyles({
88-
width: "100%",
62+
const documentListStyles = React.useMemo(() => {
63+
return mergeStyleSets({
64+
fileIconHeaderIcon: {
65+
padding: 0,
66+
fontSize: "16px",
67+
},
68+
fileIconCell: mergeStyles({
69+
textAlign: "center",
70+
selectors: {
71+
"&:before": {
72+
content: ".",
73+
display: "inline-block",
74+
verticalAlign: "middle",
75+
height: "100%",
76+
width: "0px",
77+
visibility: "hidden",
78+
},
79+
},
80+
}),
81+
fileIconImg: mergeStyles({
82+
verticalAlign: "middle",
83+
maxHeight: "16px",
84+
maxWidth: "16px",
85+
}),
86+
controlWrapper: mergeStyles({
87+
display: "flex",
88+
flexWrap: "wrap",
89+
}),
8990

91+
selectionDetails: mergeStyles({
92+
marginBottom: "20px",
93+
}),
94+
filesContainerGrid: mergeStyles({
95+
width: "100%",
96+
display: "grid",
97+
gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 160px), 1fr))",
98+
columnGap: "15px",
99+
rowGap: 15,
100+
}),
90101

102+
noDataFoundStyles: {
103+
width: "300px",
104+
height: "300px",
105+
},
106+
separator: mergeStyles({
107+
height: "1px",
108+
backgroundColor: themeVariant?.palette?.neutralLight,
109+
opacity: themeVariant?.isInverted ? "0.2" : "1",
110+
width: "100%",
91111

92-
}),
93-
})}, [themeVariant]);
94-
return { documentListStyles, scollableContainerStyles };
95-
}
112+
}),
113+
documentList: mergeStyles({
114+
width: "100%",
115+
}),
116+
});
117+
}, [themeVariant]);
118+
return {bootomContainerStyles, documentListStyles, scollableContainerStyles };
119+
};

src/controls/uploadFiles/components/File/FileInfo.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
import * as React from 'react';
22

33
import { format } from 'date-fns';
4+
import { useAtomValue } from 'jotai';
5+
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
46
import {
5-
Checkbox,
67
DocumentCard,
78
DocumentCardDetails,
89
DocumentCardImage,
9-
IIconProps,
10-
ImageFit,
11-
Stack,
12-
Text,
13-
} from 'office-ui-fabric-react';
10+
} from 'office-ui-fabric-react/lib/DocumentCard';
11+
import { IIconProps } from 'office-ui-fabric-react/lib/Icon';
12+
import { ImageFit } from 'office-ui-fabric-react/lib/Image';
13+
import { Stack } from 'office-ui-fabric-react/lib/Stack';
14+
import { Text } from 'office-ui-fabric-react/lib/Text';
1415

1516
import {
1617
getFileTypeIconProps,
1718
initializeFileTypeIcons,
1819
} from '@fluentui/react-file-type-icons';
1920

2021
import { useUtils } from '../../hooks/useUtils';
22+
import { globalState } from '../../jotai/atoms';
2123
import { useFileStyles } from './useFileStyles';
2224

2325
initializeFileTypeIcons();
@@ -31,13 +33,14 @@ export const FileInfo: React.FunctionComponent<IFileInfoProps> = (props: React.P
3133
const { fileInfo, onSelected, isSelected } = props;
3234
const { name, size, lastModified } = fileInfo;
3335

34-
const { checkBoxStyles, documentCardStyles, stackCheckboxStyles, fileNameStyles } = useFileStyles();
36+
const { checkBoxStyles, documentCardStyles, stackCheckboxStyles, fileNameStyles,documentImageStyles } = useFileStyles();
3537
const { getShortText, getFileExtension, getFileSize } = useUtils();
3638
const fileSize = getFileSize(size);
3739
const fileExtension = getFileExtension(name);
3840
const fileModified = format(new Date(lastModified), "dd, MMM yyyy");
3941
const [isChecked, setIsChecked] = React.useState<boolean>(false);
40-
42+
const appGlobalState = useAtomValue(globalState);
43+
const { themeVariant, } = appGlobalState;
4144
const fileIcon: IIconProps = React.useMemo(() => {
4245
return {
4346
...getFileTypeIconProps({ extension: fileExtension, size: 48, imageFileType: "svg" }),
@@ -61,16 +64,17 @@ export const FileInfo: React.FunctionComponent<IFileInfoProps> = (props: React.P
6164
const renderNormalCard = React.useCallback(() => {
6265
return (
6366
<>
67+
6468
<Stack>
6569
<DocumentCard styles={documentCardStyles} title={name}>
66-
<DocumentCardImage height={100} imageFit={ImageFit.cover} iconProps={fileIcon} />
70+
<DocumentCardImage height={100} imageFit={ImageFit.cover} iconProps={fileIcon} styles={documentImageStyles} />
6771
<Stack
6872
horizontal
6973
horizontalAlign="end"
7074
tokens={{ childrenGap: 5, padding: 7 }}
7175
styles={stackCheckboxStyles}
7276
>
73-
<Checkbox styles={checkBoxStyles} checked={isChecked} onChange={onCheckboxChange} />
77+
<Checkbox styles={checkBoxStyles} checked={isChecked} onChange={onCheckboxChange} />
7478
</Stack>
7579

7680
<DocumentCardDetails>
@@ -86,9 +90,10 @@ export const FileInfo: React.FunctionComponent<IFileInfoProps> = (props: React.P
8690
</DocumentCardDetails>
8791
</DocumentCard>
8892
</Stack>
93+
8994
</>
9095
);
91-
}, [isChecked, fileIcon, fileSize, fileModified, getShortText, name, onCheckboxChange]);
96+
}, [isChecked, fileIcon, fileSize, fileModified, getShortText, name, onCheckboxChange, themeVariant]);
9297

9398
return <>{renderNormalCard()}</>;
9499
};

0 commit comments

Comments
 (0)