@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.
Files changed (48) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/esm/components/CalendarMonth/CalendarMonth.d.ts.map +1 -1
  3. package/dist/esm/components/CalendarMonth/CalendarMonth.js +35 -30
  4. package/dist/esm/components/CalendarMonth/CalendarMonth.js.map +1 -1
  5. package/dist/esm/components/Form/FormGroup.d.ts +4 -0
  6. package/dist/esm/components/Form/FormGroup.d.ts.map +1 -1
  7. package/dist/esm/components/Form/FormGroup.js +6 -4
  8. package/dist/esm/components/Form/FormGroup.js.map +1 -1
  9. package/dist/esm/components/Form/FormSection.d.ts.map +1 -1
  10. package/dist/esm/components/Form/FormSection.js +4 -3
  11. package/dist/esm/components/Form/FormSection.js.map +1 -1
  12. package/dist/esm/components/Form/InternalFormFieldGroup.d.ts.map +1 -1
  13. package/dist/esm/components/Form/InternalFormFieldGroup.js +1 -1
  14. package/dist/esm/components/Form/InternalFormFieldGroup.js.map +1 -1
  15. package/dist/js/components/CalendarMonth/CalendarMonth.d.ts.map +1 -1
  16. package/dist/js/components/CalendarMonth/CalendarMonth.js +35 -30
  17. package/dist/js/components/CalendarMonth/CalendarMonth.js.map +1 -1
  18. package/dist/js/components/Form/FormGroup.d.ts +4 -0
  19. package/dist/js/components/Form/FormGroup.d.ts.map +1 -1
  20. package/dist/js/components/Form/FormGroup.js +6 -4
  21. package/dist/js/components/Form/FormGroup.js.map +1 -1
  22. package/dist/js/components/Form/FormSection.d.ts.map +1 -1
  23. package/dist/js/components/Form/FormSection.js +4 -3
  24. package/dist/js/components/Form/FormSection.js.map +1 -1
  25. package/dist/js/components/Form/InternalFormFieldGroup.d.ts.map +1 -1
  26. package/dist/js/components/Form/InternalFormFieldGroup.js +1 -1
  27. package/dist/js/components/Form/InternalFormFieldGroup.js.map +1 -1
  28. package/dist/umd/react-core.css +34 -34
  29. package/dist/umd/react-core.js +287 -294
  30. package/dist/umd/react-core.min.js +4 -4
  31. package/package.json +5 -5
  32. package/src/components/CalendarMonth/CalendarMonth.tsx +57 -51
  33. package/src/components/FileUpload/examples/FileUpload.md +6 -270
  34. package/src/components/FileUpload/examples/FileUploadCustomPreview.tsx +40 -0
  35. package/src/components/FileUpload/examples/FileUploadCustomUpload.tsx +116 -0
  36. package/src/components/FileUpload/examples/FileUploadSimpleFile.tsx +31 -0
  37. package/src/components/FileUpload/examples/FileUploadSimpleText.tsx +51 -0
  38. package/src/components/FileUpload/examples/FileUploadTextWithEdits.tsx +51 -0
  39. package/src/components/FileUpload/examples/FileUploadTextWithRestrictions.tsx +71 -0
  40. package/src/components/Form/FormGroup.tsx +17 -3
  41. package/src/components/Form/FormSection.tsx +18 -4
  42. package/src/components/Form/InternalFormFieldGroup.tsx +2 -0
  43. package/src/components/Form/__tests__/FormFieldGroup.test.tsx +23 -1
  44. package/src/components/Form/__tests__/FormGroup.test.tsx +89 -0
  45. package/src/components/Form/__tests__/FormSection.test.tsx +13 -1
  46. package/src/components/Form/__tests__/__snapshots__/FormFieldGroup.test.tsx.snap +4 -0
  47. package/src/components/Form/__tests__/__snapshots__/FormSection.test.tsx.snap +4 -0
  48. 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.221.15",
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.72.15",
38
- "@patternfly/react-styles": "^4.71.15",
39
- "@patternfly/react-tokens": "^4.73.15",
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": "7ede2a5922f4ef870dd305ee1df3426e42eb1fe4"
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 ArrowLeftIcon from '@patternfly/react-icons/dist/esm/icons/arrow-left-icon';
6
- import ArrowRightIcon from '@patternfly/react-icons/dist/esm/icons/arrow-right-icon';
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 always show 6 weeks like google calendar
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
- <ArrowLeftIcon aria-hidden={true} />
211
+ <AngleLeftIcon aria-hidden={true} />
208
212
  </Button>
209
213
  </div>
210
- <div className={styles.calendarMonthHeaderMonth}>
211
- <span id={hiddenMonthId} hidden>
212
- Month
213
- </span>
214
- <Select
215
- // Max width with "September"
216
- width="140px"
217
- aria-labelledby={hiddenMonthId}
218
- isOpen={isSelectOpen}
219
- onToggle={() => {
220
- setIsSelectOpen(!isSelectOpen);
221
- onSelectToggle(!isSelectOpen);
222
- }}
223
- onSelect={(_ev, monthNum) => {
224
- // When we put CalendarMonth in a Popover we want the Popover's onDocumentClick
225
- // to see the SelectOption as a child so it doesn't close the Popover.
226
- setTimeout(() => {
227
- setIsSelectOpen(false);
228
- onSelectToggle(false);
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.setMonth(Number(monthNum as string));
258
+ newDate.setFullYear(+year);
231
259
  setFocusedDate(newDate);
232
260
  setHoveredDate(newDate);
233
261
  setShouldFocus(false);
234
- }, 0);
235
- }}
236
- variant="single"
237
- selections={monthFormatted}
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
- <ArrowRightIcon aria-hidden={true} />
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
- ```js
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
- ```js
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
- ```js
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
- ```js
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
- ```js
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
- ```js
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
+ };