@patternfly/react-core 4.221.15 → 4.222.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/CHANGELOG.md +27 -0
- package/dist/esm/components/CalendarMonth/CalendarMonth.d.ts.map +1 -1
- package/dist/esm/components/CalendarMonth/CalendarMonth.js +35 -30
- package/dist/esm/components/CalendarMonth/CalendarMonth.js.map +1 -1
- package/dist/esm/components/Form/FormGroup.d.ts +4 -0
- package/dist/esm/components/Form/FormGroup.d.ts.map +1 -1
- package/dist/esm/components/Form/FormGroup.js +6 -4
- package/dist/esm/components/Form/FormGroup.js.map +1 -1
- package/dist/esm/components/Form/FormSection.d.ts.map +1 -1
- package/dist/esm/components/Form/FormSection.js +4 -3
- package/dist/esm/components/Form/FormSection.js.map +1 -1
- package/dist/esm/components/Form/InternalFormFieldGroup.d.ts.map +1 -1
- package/dist/esm/components/Form/InternalFormFieldGroup.js +1 -1
- package/dist/esm/components/Form/InternalFormFieldGroup.js.map +1 -1
- package/dist/js/components/CalendarMonth/CalendarMonth.d.ts.map +1 -1
- package/dist/js/components/CalendarMonth/CalendarMonth.js +35 -30
- package/dist/js/components/CalendarMonth/CalendarMonth.js.map +1 -1
- package/dist/js/components/Form/FormGroup.d.ts +4 -0
- package/dist/js/components/Form/FormGroup.d.ts.map +1 -1
- package/dist/js/components/Form/FormGroup.js +6 -4
- package/dist/js/components/Form/FormGroup.js.map +1 -1
- package/dist/js/components/Form/FormSection.d.ts.map +1 -1
- package/dist/js/components/Form/FormSection.js +4 -3
- package/dist/js/components/Form/FormSection.js.map +1 -1
- package/dist/js/components/Form/InternalFormFieldGroup.d.ts.map +1 -1
- package/dist/js/components/Form/InternalFormFieldGroup.js +1 -1
- package/dist/js/components/Form/InternalFormFieldGroup.js.map +1 -1
- package/dist/umd/react-core.css +34 -34
- package/dist/umd/react-core.js +287 -294
- package/dist/umd/react-core.min.js +4 -4
- package/package.json +5 -5
- package/src/components/CalendarMonth/CalendarMonth.tsx +57 -51
- package/src/components/FileUpload/examples/FileUpload.md +6 -270
- package/src/components/FileUpload/examples/FileUploadCustomPreview.tsx +40 -0
- package/src/components/FileUpload/examples/FileUploadCustomUpload.tsx +116 -0
- package/src/components/FileUpload/examples/FileUploadSimpleFile.tsx +31 -0
- package/src/components/FileUpload/examples/FileUploadSimpleText.tsx +51 -0
- package/src/components/FileUpload/examples/FileUploadTextWithEdits.tsx +51 -0
- package/src/components/FileUpload/examples/FileUploadTextWithRestrictions.tsx +71 -0
- package/src/components/Form/FormGroup.tsx +17 -3
- package/src/components/Form/FormSection.tsx +18 -4
- package/src/components/Form/InternalFormFieldGroup.tsx +2 -0
- package/src/components/Form/__tests__/FormFieldGroup.test.tsx +23 -1
- package/src/components/Form/__tests__/FormGroup.test.tsx +89 -0
- package/src/components/Form/__tests__/FormSection.test.tsx +13 -1
- package/src/components/Form/__tests__/__snapshots__/FormFieldGroup.test.tsx.snap +4 -0
- package/src/components/Form/__tests__/__snapshots__/FormSection.test.tsx.snap +4 -0
- package/src/components/Form/examples/Form.md +45 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/react-core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.222.0",
|
|
4
4
|
"description": "This library provides a set of common React components for use with the PatternFly reference implementation.",
|
|
5
5
|
"main": "dist/js/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"generate": "node scripts/copyStyles.js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@patternfly/react-icons": "^4.
|
|
38
|
-
"@patternfly/react-styles": "^4.
|
|
39
|
-
"@patternfly/react-tokens": "^4.
|
|
37
|
+
"@patternfly/react-icons": "^4.73.0",
|
|
38
|
+
"@patternfly/react-styles": "^4.72.0",
|
|
39
|
+
"@patternfly/react-tokens": "^4.74.0",
|
|
40
40
|
"focus-trap": "6.9.2",
|
|
41
41
|
"react-dropzone": "9.0.0",
|
|
42
42
|
"tippy.js": "5.1.2",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"react": "^16.8.0 || ^17.0.0",
|
|
61
61
|
"react-dom": "^16.8.0 || ^17.0.0"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "9c5a0c99d957bafa3548e1fd4db410a74f7f7ad8"
|
|
64
64
|
}
|
|
@@ -2,8 +2,9 @@ import React, { useEffect } from 'react';
|
|
|
2
2
|
import { TextInput } from '../TextInput/TextInput';
|
|
3
3
|
import { Button } from '../Button/Button';
|
|
4
4
|
import { Select, SelectOption } from '../Select';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import { InputGroup } from '../InputGroup';
|
|
6
|
+
import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';
|
|
7
|
+
import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';
|
|
7
8
|
import { css } from '@patternfly/react-styles';
|
|
8
9
|
import styles from '@patternfly/react-styles/css/components/CalendarMonth/calendar-month';
|
|
9
10
|
import { getUniqueId } from '../../helpers/util';
|
|
@@ -63,7 +64,7 @@ const buildCalendar = (year: number, month: number, weekStart: number, validator
|
|
|
63
64
|
const defaultDate = new Date(year, month);
|
|
64
65
|
const firstDayOfWeek = new Date(defaultDate);
|
|
65
66
|
firstDayOfWeek.setDate(firstDayOfWeek.getDate() - firstDayOfWeek.getDay() + weekStart);
|
|
66
|
-
// We will
|
|
67
|
+
// We will show a maximum of 6 weeks like Google calendar
|
|
67
68
|
// Assume we just want the numbers for now...
|
|
68
69
|
const calendarWeeks = [];
|
|
69
70
|
for (let i = 0; i < 6; i++) {
|
|
@@ -77,6 +78,9 @@ const buildCalendar = (year: number, month: number, weekStart: number, validator
|
|
|
77
78
|
firstDayOfWeek.setDate(firstDayOfWeek.getDate() + 1);
|
|
78
79
|
}
|
|
79
80
|
calendarWeeks.push(week);
|
|
81
|
+
if (firstDayOfWeek.getMonth() !== defaultDate.getMonth()) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
return calendarWeeks;
|
|
@@ -204,62 +208,64 @@ export const CalendarMonth = ({
|
|
|
204
208
|
<div className={styles.calendarMonthHeader}>
|
|
205
209
|
<div className={css(styles.calendarMonthHeaderNavControl, styles.modifiers.prevMonth)}>
|
|
206
210
|
<Button variant="plain" aria-label={prevMonthAriaLabel} onClick={() => onMonthClick(prevMonth)}>
|
|
207
|
-
<
|
|
211
|
+
<AngleLeftIcon aria-hidden={true} />
|
|
208
212
|
</Button>
|
|
209
213
|
</div>
|
|
210
|
-
<
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
214
|
+
<InputGroup>
|
|
215
|
+
<div className={styles.calendarMonthHeaderMonth}>
|
|
216
|
+
<span id={hiddenMonthId} hidden>
|
|
217
|
+
Month
|
|
218
|
+
</span>
|
|
219
|
+
<Select
|
|
220
|
+
// Max width with "September"
|
|
221
|
+
width="140px"
|
|
222
|
+
aria-labelledby={hiddenMonthId}
|
|
223
|
+
isOpen={isSelectOpen}
|
|
224
|
+
onToggle={() => {
|
|
225
|
+
setIsSelectOpen(!isSelectOpen);
|
|
226
|
+
onSelectToggle(!isSelectOpen);
|
|
227
|
+
}}
|
|
228
|
+
onSelect={(_ev, monthNum) => {
|
|
229
|
+
// When we put CalendarMonth in a Popover we want the Popover's onDocumentClick
|
|
230
|
+
// to see the SelectOption as a child so it doesn't close the Popover.
|
|
231
|
+
setTimeout(() => {
|
|
232
|
+
setIsSelectOpen(false);
|
|
233
|
+
onSelectToggle(false);
|
|
234
|
+
const newDate = new Date(focusedDate);
|
|
235
|
+
newDate.setMonth(Number(monthNum as string));
|
|
236
|
+
setFocusedDate(newDate);
|
|
237
|
+
setHoveredDate(newDate);
|
|
238
|
+
setShouldFocus(false);
|
|
239
|
+
}, 0);
|
|
240
|
+
}}
|
|
241
|
+
variant="single"
|
|
242
|
+
selections={monthFormatted}
|
|
243
|
+
>
|
|
244
|
+
{longMonths.map((longMonth, index) => (
|
|
245
|
+
<SelectOption key={index} value={index} isSelected={longMonth === monthFormatted}>
|
|
246
|
+
{longMonth}
|
|
247
|
+
</SelectOption>
|
|
248
|
+
))}
|
|
249
|
+
</Select>
|
|
250
|
+
</div>
|
|
251
|
+
<div className={styles.calendarMonthHeaderYear}>
|
|
252
|
+
<TextInput
|
|
253
|
+
aria-label={yearInputAriaLabel}
|
|
254
|
+
type="number"
|
|
255
|
+
value={yearFormatted}
|
|
256
|
+
onChange={year => {
|
|
229
257
|
const newDate = new Date(focusedDate);
|
|
230
|
-
newDate.
|
|
258
|
+
newDate.setFullYear(+year);
|
|
231
259
|
setFocusedDate(newDate);
|
|
232
260
|
setHoveredDate(newDate);
|
|
233
261
|
setShouldFocus(false);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
>
|
|
239
|
-
{longMonths.map((longMonth, index) => (
|
|
240
|
-
<SelectOption key={index} value={index} isSelected={longMonth === monthFormatted}>
|
|
241
|
-
{longMonth}
|
|
242
|
-
</SelectOption>
|
|
243
|
-
))}
|
|
244
|
-
</Select>
|
|
245
|
-
</div>
|
|
246
|
-
<div className={styles.calendarMonthHeaderYear}>
|
|
247
|
-
<TextInput
|
|
248
|
-
aria-label={yearInputAriaLabel}
|
|
249
|
-
type="number"
|
|
250
|
-
value={yearFormatted}
|
|
251
|
-
onChange={year => {
|
|
252
|
-
const newDate = new Date(focusedDate);
|
|
253
|
-
newDate.setFullYear(+year);
|
|
254
|
-
setFocusedDate(newDate);
|
|
255
|
-
setHoveredDate(newDate);
|
|
256
|
-
setShouldFocus(false);
|
|
257
|
-
}}
|
|
258
|
-
/>
|
|
259
|
-
</div>
|
|
262
|
+
}}
|
|
263
|
+
/>
|
|
264
|
+
</div>
|
|
265
|
+
</InputGroup>
|
|
260
266
|
<div className={css(styles.calendarMonthHeaderNavControl, styles.modifiers.nextMonth)}>
|
|
261
267
|
<Button variant="plain" aria-label={nextMonthAriaLabel} onClick={() => onMonthClick(nextMonth)}>
|
|
262
|
-
<
|
|
268
|
+
<AngleRightIcon aria-hidden={true} />
|
|
263
269
|
</Button>
|
|
264
270
|
</div>
|
|
265
271
|
</div>
|
|
@@ -18,42 +18,7 @@ Pressing _Clear_ button triggers `onClearClick` event.
|
|
|
18
18
|
|
|
19
19
|
### Simple text file
|
|
20
20
|
|
|
21
|
-
```
|
|
22
|
-
import React from 'react';
|
|
23
|
-
import { FileUpload } from '@patternfly/react-core';
|
|
24
|
-
|
|
25
|
-
class SimpleTextFileUpload extends React.Component {
|
|
26
|
-
constructor(props) {
|
|
27
|
-
super(props);
|
|
28
|
-
this.state = { value: '', filename: '', isLoading: false };
|
|
29
|
-
this.handleFileInputChange = (event, file) => this.setState({ filename: file.name });
|
|
30
|
-
this.handleTextOrDataChange = value => this.setState({ value });
|
|
31
|
-
this.handleClear = event => this.setState({ filename: '', value: '' });
|
|
32
|
-
this.handleFileReadStarted = fileHandle => this.setState({ isLoading: true });
|
|
33
|
-
this.handleFileReadFinished = fileHandle => this.setState({ isLoading: false });
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
render() {
|
|
37
|
-
const { value, filename, isLoading } = this.state;
|
|
38
|
-
return (
|
|
39
|
-
<FileUpload
|
|
40
|
-
id="simple-text-file"
|
|
41
|
-
type="text"
|
|
42
|
-
value={value}
|
|
43
|
-
filename={filename}
|
|
44
|
-
filenamePlaceholder="Drag and drop a file or upload one"
|
|
45
|
-
onFileInputChange={this.handleFileInputChange}
|
|
46
|
-
onDataChange={this.handleTextOrDataChange}
|
|
47
|
-
onTextChange={this.handleTextOrDataChange}
|
|
48
|
-
onReadStarted={this.handleFileReadStarted}
|
|
49
|
-
onReadFinished={this.handleFileReadFinished}
|
|
50
|
-
onClearClick={this.handleClear}
|
|
51
|
-
isLoading={isLoading}
|
|
52
|
-
browseButtonText="Upload"
|
|
53
|
-
/>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
21
|
+
```ts file="./FileUploadSimpleText.tsx"
|
|
57
22
|
```
|
|
58
23
|
|
|
59
24
|
A user can always type instead of selecting a file, but by default, once a user selects a text file from their disk they are not allowed to edit it (to prevent unintended changes to a format-sensitive file). This behavior can be changed with the `allowEditingUploadedText` prop.
|
|
@@ -61,43 +26,7 @@ Typing/pasting text in the box will call `onTextChange` with a string, and a str
|
|
|
61
26
|
|
|
62
27
|
### Text file with edits allowed
|
|
63
28
|
|
|
64
|
-
```
|
|
65
|
-
import React from 'react';
|
|
66
|
-
import { FileUpload } from '@patternfly/react-core';
|
|
67
|
-
|
|
68
|
-
class TextFileWithEditsAllowed extends React.Component {
|
|
69
|
-
constructor(props) {
|
|
70
|
-
super(props);
|
|
71
|
-
this.state = { value: '', filename: '', isLoading: false };
|
|
72
|
-
this.handleFileInputChange = (event, file) => this.setState({ filename: file.name });
|
|
73
|
-
this.handleTextOrDataChange = value => this.setState({ value });
|
|
74
|
-
this.handleClear = event => this.setState({ filename: '', value: '' });
|
|
75
|
-
this.handleFileReadStarted = fileHandle => this.setState({ isLoading: true });
|
|
76
|
-
this.handleFileReadFinished = fileHandle => this.setState({ isLoading: false });
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
render() {
|
|
80
|
-
const { value, filename, isLoading } = this.state;
|
|
81
|
-
return (
|
|
82
|
-
<FileUpload
|
|
83
|
-
id="text-file-with-edits-allowed"
|
|
84
|
-
type="text"
|
|
85
|
-
value={value}
|
|
86
|
-
filename={filename}
|
|
87
|
-
filenamePlaceholder="Drag and drop a file or upload one"
|
|
88
|
-
onFileInputChange={this.handleFileInputChange}
|
|
89
|
-
onDataChange={this.handleTextOrDataChange}
|
|
90
|
-
onClearClick={this.handleClear}
|
|
91
|
-
onTextChange={this.handleTextOrDataChange}
|
|
92
|
-
onReadStarted={this.handleFileReadStarted}
|
|
93
|
-
onReadFinished={this.handleFileReadFinished}
|
|
94
|
-
isLoading={isLoading}
|
|
95
|
-
allowEditingUploadedText
|
|
96
|
-
browseButtonText="Upload"
|
|
97
|
-
/>
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
29
|
+
```ts file="./FileUploadTextWithEdits.tsx"
|
|
101
30
|
```
|
|
102
31
|
|
|
103
32
|
### Restricting file size and type
|
|
@@ -110,58 +39,7 @@ Restricting file sizes and types in this way is for user convenience only, and i
|
|
|
110
39
|
|
|
111
40
|
### Text file with restrictions
|
|
112
41
|
|
|
113
|
-
```
|
|
114
|
-
import React from 'react';
|
|
115
|
-
import { FileUpload, Form, FormGroup } from '@patternfly/react-core';
|
|
116
|
-
|
|
117
|
-
class TextFileUploadWithRestrictions extends React.Component {
|
|
118
|
-
constructor(props) {
|
|
119
|
-
super(props);
|
|
120
|
-
this.state = { value: '', filename: '', isLoading: false, isRejected: false };
|
|
121
|
-
this.handleFileInputChange = (event, file) => this.setState({ filename: file.name });
|
|
122
|
-
this.handleTextOrDataChange = value => this.setState({ value });
|
|
123
|
-
this.handleClear = event => this.setState({ filename: '', value: '', isRejected: false });
|
|
124
|
-
this.handleFileRejected = (rejectedFiles, event) => this.setState({ isRejected: true });
|
|
125
|
-
this.handleFileReadStarted = fileHandle => this.setState({ isLoading: true });
|
|
126
|
-
this.handleFileReadFinished = fileHandle => this.setState({ isLoading: false });
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
render() {
|
|
130
|
-
const { value, filename, isLoading, isRejected } = this.state;
|
|
131
|
-
return (
|
|
132
|
-
<Form>
|
|
133
|
-
<FormGroup
|
|
134
|
-
fieldId="text-file-with-restrictions"
|
|
135
|
-
helperText="Upload a CSV file"
|
|
136
|
-
helperTextInvalid="Must be a CSV file no larger than 1 KB"
|
|
137
|
-
validated={isRejected ? 'error' : 'default'}
|
|
138
|
-
>
|
|
139
|
-
<FileUpload
|
|
140
|
-
id="text-file-with-restrictions"
|
|
141
|
-
type="text"
|
|
142
|
-
value={value}
|
|
143
|
-
filename={filename}
|
|
144
|
-
filenamePlaceholder="Drag and drop a file or upload one"
|
|
145
|
-
onFileInputChange={this.handleFileInputChange}
|
|
146
|
-
onDataChange={this.handleTextOrDataChange}
|
|
147
|
-
onTextChange={this.handleTextOrDataChange}
|
|
148
|
-
onClearClick={this.handleClear}
|
|
149
|
-
onReadStarted={this.handleFileReadStarted}
|
|
150
|
-
onReadFinished={this.handleFileReadFinished}
|
|
151
|
-
isLoading={isLoading}
|
|
152
|
-
dropzoneProps={{
|
|
153
|
-
accept: '.csv',
|
|
154
|
-
maxSize: 1024,
|
|
155
|
-
onDropRejected: this.handleFileRejected
|
|
156
|
-
}}
|
|
157
|
-
validated={isRejected ? 'error' : 'default'}
|
|
158
|
-
browseButtonText="Upload"
|
|
159
|
-
/>
|
|
160
|
-
</FormGroup>
|
|
161
|
-
</Form>
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
42
|
+
```ts file="./FileUploadTextWithRestrictions.tsx"
|
|
165
43
|
```
|
|
166
44
|
|
|
167
45
|
### Other file types
|
|
@@ -170,35 +48,7 @@ If no `type` prop is specified, the component will not read files directly. When
|
|
|
170
48
|
|
|
171
49
|
### Simple file of any format
|
|
172
50
|
|
|
173
|
-
```
|
|
174
|
-
import React from 'react';
|
|
175
|
-
import { FileUpload } from '@patternfly/react-core';
|
|
176
|
-
|
|
177
|
-
class SimpleFileUpload extends React.Component {
|
|
178
|
-
constructor(props) {
|
|
179
|
-
super(props);
|
|
180
|
-
this.state = { value: null, filename: '' };
|
|
181
|
-
this.handleFileInputChange = (event, file) => {
|
|
182
|
-
this.setState({ filename: file.name });
|
|
183
|
-
};
|
|
184
|
-
this.handleClear = event => this.setState({ filename: '', value: '' });
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
render() {
|
|
188
|
-
const { value, filename } = this.state;
|
|
189
|
-
return (
|
|
190
|
-
<FileUpload
|
|
191
|
-
id="simple-file"
|
|
192
|
-
value={value}
|
|
193
|
-
filename={filename}
|
|
194
|
-
filenamePlaceholder="Drag and drop a file or upload one"
|
|
195
|
-
browseButtonText="Upload"
|
|
196
|
-
onFileInputChange={this.handleFileInputChange}
|
|
197
|
-
onClearClick={this.handleClear}
|
|
198
|
-
/>
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
51
|
+
```ts file="./FileUploadSimpleFile.tsx"
|
|
202
52
|
```
|
|
203
53
|
|
|
204
54
|
### Customizing the file preview
|
|
@@ -207,43 +57,7 @@ Regardless of `type`, the preview area (the TextArea, or any future implementati
|
|
|
207
57
|
|
|
208
58
|
### Custom file preview
|
|
209
59
|
|
|
210
|
-
```
|
|
211
|
-
import React from 'react';
|
|
212
|
-
import { FileUpload } from '@patternfly/react-core';
|
|
213
|
-
import FileUploadIcon from '@patternfly/react-icons/dist/esm/icons/file-upload-icon';
|
|
214
|
-
|
|
215
|
-
class CustomPreviewFileUpload extends React.Component {
|
|
216
|
-
constructor(props) {
|
|
217
|
-
super(props);
|
|
218
|
-
this.state = { value: null, filename: '' };
|
|
219
|
-
this.handleFileInputChange = (event, file) => {
|
|
220
|
-
this.setState({ value: file, filename: file.name });
|
|
221
|
-
};
|
|
222
|
-
this.handleClear = event => this.setState({ filename: '', value: '' });
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
render() {
|
|
226
|
-
const { value, filename, isLoading } = this.state;
|
|
227
|
-
return (
|
|
228
|
-
<FileUpload
|
|
229
|
-
id="customized-preview-file"
|
|
230
|
-
value={value}
|
|
231
|
-
filename={filename}
|
|
232
|
-
filenamePlaceholder="Drag and drop a file or upload one"
|
|
233
|
-
onFileInputChange={this.handleFileInputChange}
|
|
234
|
-
onClearClick={this.handleClear}
|
|
235
|
-
hideDefaultPreview
|
|
236
|
-
browseButtonText="Upload"
|
|
237
|
-
>
|
|
238
|
-
{value && (
|
|
239
|
-
<div className="pf-u-m-md">
|
|
240
|
-
<FileUploadIcon size="lg" /> Custom preview here for your {value.size}-byte file named {value.name}
|
|
241
|
-
</div>
|
|
242
|
-
)}
|
|
243
|
-
</FileUpload>
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
60
|
+
```ts file="./FileUploadCustomPreview.tsx"
|
|
247
61
|
```
|
|
248
62
|
|
|
249
63
|
### Bringing your own file browse logic
|
|
@@ -254,83 +68,5 @@ Note that the `isLoading` prop is styled to position the spinner dead center abo
|
|
|
254
68
|
|
|
255
69
|
### Custom file upload
|
|
256
70
|
|
|
257
|
-
```
|
|
258
|
-
import React from 'react';
|
|
259
|
-
import { FileUploadField, Checkbox } from '@patternfly/react-core';
|
|
260
|
-
|
|
261
|
-
class CustomFileUpload extends React.Component {
|
|
262
|
-
constructor(props) {
|
|
263
|
-
super(props);
|
|
264
|
-
this.state = {
|
|
265
|
-
value: '',
|
|
266
|
-
filename: false,
|
|
267
|
-
isClearButtonDisabled: true,
|
|
268
|
-
isLoading: false,
|
|
269
|
-
isDragActive: false,
|
|
270
|
-
hideDefaultPreview: false,
|
|
271
|
-
children: false,
|
|
272
|
-
hasPlaceholderText: false
|
|
273
|
-
};
|
|
274
|
-
this.handleTextAreaChange = value => {
|
|
275
|
-
this.setState({ value });
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
render() {
|
|
280
|
-
const {
|
|
281
|
-
value,
|
|
282
|
-
filename,
|
|
283
|
-
isClearButtonDisabled,
|
|
284
|
-
isLoading,
|
|
285
|
-
isDragActive,
|
|
286
|
-
hideDefaultPreview,
|
|
287
|
-
children,
|
|
288
|
-
hasPlaceholderText
|
|
289
|
-
} = this.state;
|
|
290
|
-
return (
|
|
291
|
-
<div>
|
|
292
|
-
{['filename', 'isClearButtonDisabled', 'isDragActive', 'isLoading', 'hideDefaultPreview', 'children', 'hasPlaceholderText'].map(
|
|
293
|
-
stateKey => (
|
|
294
|
-
<Checkbox
|
|
295
|
-
key={stateKey}
|
|
296
|
-
id={stateKey}
|
|
297
|
-
label={stateKey}
|
|
298
|
-
aria-label={stateKey}
|
|
299
|
-
isChecked={this.state[stateKey]}
|
|
300
|
-
onChange={checked =>
|
|
301
|
-
this.setState({
|
|
302
|
-
[stateKey]: checked,
|
|
303
|
-
// See notes above this example
|
|
304
|
-
...(stateKey === 'isLoading' && checked && { hideDefaultPreview: false }),
|
|
305
|
-
...(stateKey === 'hideDefaultPreview' && checked && { isLoading: false })
|
|
306
|
-
})
|
|
307
|
-
}
|
|
308
|
-
/>
|
|
309
|
-
)
|
|
310
|
-
)}
|
|
311
|
-
<br />
|
|
312
|
-
<FileUploadField
|
|
313
|
-
id="custom-file-upload"
|
|
314
|
-
type="text"
|
|
315
|
-
value={value}
|
|
316
|
-
filename={filename ? 'example-filename.txt' : ''}
|
|
317
|
-
onTextChange={this.handleTextAreaChange}
|
|
318
|
-
filenamePlaceholder="Do something custom with this!"
|
|
319
|
-
onBrowseButtonClick={() => alert('Browse button clicked!')}
|
|
320
|
-
onClearButtonClick={() => alert('Clear button clicked!')}
|
|
321
|
-
isClearButtonDisabled={isClearButtonDisabled}
|
|
322
|
-
isLoading={isLoading}
|
|
323
|
-
isDragActive={isDragActive}
|
|
324
|
-
hideDefaultPreview={hideDefaultPreview}
|
|
325
|
-
browseButtonText="Upload"
|
|
326
|
-
textAreaPlaceholder={hasPlaceholderText ? "File preview" : ''}
|
|
327
|
-
>
|
|
328
|
-
{children && (
|
|
329
|
-
<div className="pf-u-m-md">(A custom preview of the uploaded file can be passed as children)</div>
|
|
330
|
-
)}
|
|
331
|
-
</FileUploadField>
|
|
332
|
-
</div>
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
71
|
+
```ts file="./FileUploadCustomUpload.tsx"
|
|
336
72
|
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FileUpload } from '@patternfly/react-core';
|
|
3
|
+
import FileUploadIcon from '@patternfly/react-icons/dist/esm/icons/file-upload-icon';
|
|
4
|
+
|
|
5
|
+
export const CustomPreviewFileUpload: React.FunctionComponent = () => {
|
|
6
|
+
const [value, setValue] = React.useState(null);
|
|
7
|
+
const [filename, setFilename] = React.useState('');
|
|
8
|
+
|
|
9
|
+
const handleFileInputChange = (
|
|
10
|
+
_event: React.ChangeEvent<HTMLInputElement> | React.DragEvent<HTMLElement>,
|
|
11
|
+
file: File
|
|
12
|
+
) => {
|
|
13
|
+
setValue(file);
|
|
14
|
+
setFilename(file.name);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const handleClear = (_event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
18
|
+
setFilename('');
|
|
19
|
+
setValue('');
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<FileUpload
|
|
24
|
+
id="customized-preview-file"
|
|
25
|
+
value={value}
|
|
26
|
+
filename={filename}
|
|
27
|
+
filenamePlaceholder="Drag and drop a file or upload one"
|
|
28
|
+
onFileInputChange={handleFileInputChange}
|
|
29
|
+
onClearClick={handleClear}
|
|
30
|
+
hideDefaultPreview
|
|
31
|
+
browseButtonText="Upload"
|
|
32
|
+
>
|
|
33
|
+
{value && (
|
|
34
|
+
<div className="pf-u-m-md">
|
|
35
|
+
<FileUploadIcon size="lg" /> Custom preview here for your {value.size}-byte file named {value.name}
|
|
36
|
+
</div>
|
|
37
|
+
)}
|
|
38
|
+
</FileUpload>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FileUploadField, Checkbox } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const CustomPreviewFileUpload: React.FunctionComponent = () => {
|
|
5
|
+
const properties = [
|
|
6
|
+
'filename',
|
|
7
|
+
'isClearButtonDisabled',
|
|
8
|
+
'isDragActive',
|
|
9
|
+
'isLoading',
|
|
10
|
+
'hideDefaultPreview',
|
|
11
|
+
'children',
|
|
12
|
+
'hasPlaceholderText'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const [value, setValue] = React.useState('');
|
|
16
|
+
const [filename, setFilename] = React.useState(false);
|
|
17
|
+
const [isClearButtonDisabled, setIsClearButtonDisabled] = React.useState(true);
|
|
18
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
19
|
+
const [isDragActive, setIsDragActive] = React.useState(false);
|
|
20
|
+
const [hideDefaultPreview, setHideDefaultPreview] = React.useState(false);
|
|
21
|
+
const [children, setChildren] = React.useState(false);
|
|
22
|
+
const [hasPlaceholderText, setHasPlaceholderText] = React.useState(false);
|
|
23
|
+
const [checkedState, setCheckedState] = React.useState([
|
|
24
|
+
filename,
|
|
25
|
+
isClearButtonDisabled,
|
|
26
|
+
isLoading,
|
|
27
|
+
isDragActive,
|
|
28
|
+
hideDefaultPreview,
|
|
29
|
+
children,
|
|
30
|
+
hasPlaceholderText
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
const handleTextAreaChange = (value: string) => {
|
|
34
|
+
setValue(value);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const handleOnChange = (checked: boolean, stateKey: string, index: number) => {
|
|
38
|
+
const updatedCheckedState = [...checkedState];
|
|
39
|
+
switch (stateKey) {
|
|
40
|
+
case 'filename':
|
|
41
|
+
checked ? setFilename(true) : setFilename(false);
|
|
42
|
+
break;
|
|
43
|
+
|
|
44
|
+
case 'isClearButtonDisabled':
|
|
45
|
+
checked ? setIsClearButtonDisabled(true) : setIsClearButtonDisabled(false);
|
|
46
|
+
break;
|
|
47
|
+
|
|
48
|
+
case 'isDragActive':
|
|
49
|
+
checked ? setIsDragActive(true) : setIsDragActive(false);
|
|
50
|
+
break;
|
|
51
|
+
|
|
52
|
+
case 'isLoading':
|
|
53
|
+
checked ? setIsLoading(true) : setIsLoading(false);
|
|
54
|
+
// See notes above this example
|
|
55
|
+
if (checked) {
|
|
56
|
+
updatedCheckedState[properties.indexOf('hideDefaultPreview')] = false;
|
|
57
|
+
setHideDefaultPreview(false);
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
|
|
61
|
+
case 'hideDefaultPreview':
|
|
62
|
+
checked ? setHideDefaultPreview(true) : setHideDefaultPreview(false);
|
|
63
|
+
// See notes above this example
|
|
64
|
+
if (checked) {
|
|
65
|
+
updatedCheckedState[properties.indexOf('isLoading')] = false;
|
|
66
|
+
setIsLoading(false);
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
|
|
70
|
+
case 'children':
|
|
71
|
+
checked ? setChildren(true) : setChildren(false);
|
|
72
|
+
break;
|
|
73
|
+
|
|
74
|
+
case 'hasPlaceholderText':
|
|
75
|
+
checked ? setHasPlaceholderText(true) : setHasPlaceholderText(false);
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
updatedCheckedState[index] = checked;
|
|
79
|
+
setCheckedState(updatedCheckedState);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div>
|
|
84
|
+
{properties.map((stateKey, index) => (
|
|
85
|
+
<Checkbox
|
|
86
|
+
name={stateKey}
|
|
87
|
+
key={stateKey}
|
|
88
|
+
id={stateKey}
|
|
89
|
+
label={stateKey}
|
|
90
|
+
aria-label={stateKey}
|
|
91
|
+
isChecked={checkedState[index]}
|
|
92
|
+
onChange={checked => handleOnChange(checked, stateKey, index)}
|
|
93
|
+
/>
|
|
94
|
+
))}
|
|
95
|
+
<br />
|
|
96
|
+
<FileUploadField
|
|
97
|
+
id="custom-file-upload"
|
|
98
|
+
type="text"
|
|
99
|
+
value={value}
|
|
100
|
+
filename={filename ? 'example-filename.txt' : ''}
|
|
101
|
+
onTextChange={handleTextAreaChange}
|
|
102
|
+
filenamePlaceholder="Do something custom with this!"
|
|
103
|
+
onBrowseButtonClick={() => alert('Browse button clicked!')}
|
|
104
|
+
onClearButtonClick={() => alert('Clear button clicked!')}
|
|
105
|
+
isClearButtonDisabled={isClearButtonDisabled}
|
|
106
|
+
isLoading={isLoading}
|
|
107
|
+
isDragActive={isDragActive}
|
|
108
|
+
hideDefaultPreview={hideDefaultPreview}
|
|
109
|
+
browseButtonText="Upload"
|
|
110
|
+
textAreaPlaceholder={hasPlaceholderText ? 'File preview' : ''}
|
|
111
|
+
>
|
|
112
|
+
{children && <div className="pf-u-m-md">(A custom preview of the uploaded file can be passed as children)</div>}
|
|
113
|
+
</FileUploadField>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FileUpload } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const SimpleFileUpload: React.FunctionComponent = () => {
|
|
5
|
+
const [value, setValue] = React.useState(null);
|
|
6
|
+
const [filename, setFilename] = React.useState('');
|
|
7
|
+
|
|
8
|
+
const handleFileInputChange = (
|
|
9
|
+
_event: React.ChangeEvent<HTMLInputElement> | React.DragEvent<HTMLElement>,
|
|
10
|
+
file: File
|
|
11
|
+
) => {
|
|
12
|
+
setFilename(file.name);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const handleClear = (_event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
16
|
+
setFilename('');
|
|
17
|
+
setValue('');
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<FileUpload
|
|
22
|
+
id="simple-file"
|
|
23
|
+
value={value}
|
|
24
|
+
filename={filename}
|
|
25
|
+
filenamePlaceholder="Drag and drop a file or upload one"
|
|
26
|
+
onFileInputChange={handleFileInputChange}
|
|
27
|
+
onClearClick={handleClear}
|
|
28
|
+
browseButtonText="Upload"
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|