Skip to content

Commit 724258e

Browse files
feat(SimpleFileUpload): consumed Penta updates (#10026)
* feat(SimpleFileUpload): consumed Penta updates * Wrote unit tests for FileUploadHelperText * Added helper text example, updated custom upload example * Updated various a11y * Updated FileUpload snapshot
1 parent 71af427 commit 724258e

14 files changed

+207
-30
lines changed

packages/react-core/src/components/FileUpload/FileUpload.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export interface FileUploadProps
1616
'aria-label'?: string;
1717
/** Text for the browse button. */
1818
browseButtonText?: string;
19+
/** ID or ID's of elements that describe the browse button. Typically this should refer
20+
* to elements such as helper text when there are file restrictions.
21+
*/
22+
browseButtonAriaDescribedby?: string;
1923
/** Additional children to render after (or instead of) the file preview. */
2024
children?: React.ReactNode;
2125
/** Additional classes added to the file upload container element. */

packages/react-core/src/components/FileUpload/FileUploadField.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ export interface FileUploadFieldProps extends Omit<React.HTMLProps<HTMLDivElemen
1919
'aria-label'?: string;
2020
/** Text for the browse button. */
2121
browseButtonText?: string;
22+
/** ID or ID's of elements that describe the browse button. Typically this should refer
23+
* to elements such as helper text when there are file restrictions.
24+
*/
25+
browseButtonAriaDescribedby?: string;
2226
/** Additional children to render after (or instead of) the file preview. */
2327
children?: React.ReactNode;
2428
/** Additional classes added to the file upload field container element. */
@@ -108,6 +112,7 @@ export const FileUploadField: React.FunctionComponent<FileUploadFieldProps> = ({
108112
filenamePlaceholder = 'Drag a file here or browse to upload',
109113
filenameAriaLabel = filename ? 'Read only filename' : filenamePlaceholder,
110114
browseButtonText = 'Browse...',
115+
browseButtonAriaDescribedby,
111116
clearButtonText = 'Clear',
112117
isClearButtonDisabled = !filename && !value,
113118
containerRef = null as React.Ref<HTMLDivElement>,
@@ -141,16 +146,15 @@ export const FileUploadField: React.FunctionComponent<FileUploadFieldProps> = ({
141146
name={name || `${id}-filename`}
142147
aria-label={filenameAriaLabel}
143148
placeholder={filenamePlaceholder}
144-
aria-describedby={`${id}-browse-button`}
145149
value={filename}
146150
/>
147151
</InputGroupItem>
148152
<InputGroupItem>
149153
<Button
150-
id={`${id}-browse-button`}
151154
variant={ButtonVariant.control}
152155
onClick={onBrowseButtonClick}
153156
isDisabled={isDisabled}
157+
aria-describedby={browseButtonAriaDescribedby}
154158
>
155159
{browseButtonText}
156160
</Button>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from 'react';
2+
import styles from '@patternfly/react-styles/css/components/FileUpload/file-upload';
3+
import { css } from '@patternfly/react-styles';
4+
5+
/** A container for helper text content. This sub-component should be passed as a child to
6+
* the main file upload or file upload field component.
7+
*/
8+
9+
export interface FileUploadHelperTextProps extends React.HTMLProps<HTMLDivElement> {
10+
/** Content to render inside the file upload helper text container. Typically this will be
11+
* the helper text component.
12+
*/
13+
children: React.ReactNode;
14+
/** Additional classes added to the file upload helper text container element. */
15+
className?: string;
16+
}
17+
18+
export const FileUploadHelperText: React.FunctionComponent<FileUploadHelperTextProps> = ({
19+
children,
20+
className,
21+
...props
22+
}: FileUploadHelperTextProps) => (
23+
<div className={css(`${styles.fileUpload}__helper-text`, className)} {...props}>
24+
{children}
25+
</div>
26+
);
27+
FileUploadHelperText.displayName = 'FileUploadHelperText';

packages/react-core/src/components/FileUpload/__tests__/FileUploadField.test.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FileUploadField } from '../FileUploadField';
22
import * as React from 'react';
3-
import { render } from '@testing-library/react';
3+
import { render, screen } from '@testing-library/react';
44

55
test('simple fileuploadfield', () => {
66
const browserBtnClickHandler = jest.fn();
@@ -25,3 +25,19 @@ test('simple fileuploadfield', () => {
2525
);
2626
expect(asFragment()).toMatchSnapshot();
2727
});
28+
29+
test('Renders without aria-describedby on browse button by default', () => {
30+
render(<FileUploadField id="file-upload-field" browseButtonText="Upload" />);
31+
32+
expect(screen.getByRole('button', { name: 'Upload' })).not.toHaveAccessibleDescription();
33+
});
34+
35+
test('Renders without aria-describedby on browse button by default', () => {
36+
render(
37+
<FileUploadField id="file-upload-field" browseButtonText="Upload" browseButtonAriaDescribedby="helper-text">
38+
<div id="helper-text">Helper text</div>
39+
</FileUploadField>
40+
);
41+
42+
expect(screen.getByRole('button', { name: 'Upload' })).toHaveAccessibleDescription('Helper text');
43+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from 'react';
2+
import { FileUploadHelperText } from '../FileUploadHelperText';
3+
import { render, screen } from '@testing-library/react';
4+
import styles from '@patternfly/react-styles/css/components/FileUpload/file-upload';
5+
6+
test(`Renders only with class ${styles.fileUpload}__helper-text by default`, () => {
7+
render(<FileUploadHelperText>Content</FileUploadHelperText>);
8+
9+
expect(screen.getByText('Content')).toHaveClass(`${styles.fileUpload}__helper-text`, { exact: true });
10+
});
11+
12+
test(`Renders with custom class when className is passed in`, () => {
13+
render(<FileUploadHelperText className="test">Content</FileUploadHelperText>);
14+
15+
expect(screen.getByText('Content')).toHaveClass('test');
16+
});
17+
18+
test(`Spreads props when passed in`, () => {
19+
render(<FileUploadHelperText id="test-id">Content</FileUploadHelperText>);
20+
21+
expect(screen.getByText('Content')).toHaveAttribute('id', 'test-id');
22+
});
23+
24+
test('Matches the snapshot', () => {
25+
const { asFragment } = render(<FileUploadHelperText>Content</FileUploadHelperText>);
26+
expect(asFragment()).toMatchSnapshot();
27+
});

packages/react-core/src/components/FileUpload/__tests__/__snapshots__/FileUpload.test.tsx.snap

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ exports[`simple fileupload 1`] = `
1919
class="pf-v5-c-form-control pf-m-readonly"
2020
>
2121
<input
22-
aria-describedby="simple-text-file-browse-button"
2322
aria-invalid="false"
2423
aria-label="Drag a file here or browse to upload"
2524
data-ouia-component-id="OUIA-Generated-TextInputBase-1"
@@ -43,7 +42,6 @@ exports[`simple fileupload 1`] = `
4342
data-ouia-component-id="OUIA-Generated-Button-control-1"
4443
data-ouia-component-type="PF5/Button"
4544
data-ouia-safe="true"
46-
id="simple-text-file-browse-button"
4745
type="button"
4846
>
4947
Browse...

packages/react-core/src/components/FileUpload/__tests__/__snapshots__/FileUploadField.test.tsx.snap

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ exports[`simple fileuploadfield 1`] = `
1818
class="pf-v5-c-form-control pf-m-readonly"
1919
>
2020
<input
21-
aria-describedby="custom-file-upload-browse-button"
2221
aria-invalid="false"
2322
aria-label="Do something custom with this!"
2423
data-ouia-component-id="OUIA-Generated-TextInputBase-1"
@@ -42,7 +41,6 @@ exports[`simple fileuploadfield 1`] = `
4241
data-ouia-component-id="OUIA-Generated-Button-control-1"
4342
data-ouia-component-type="PF5/Button"
4443
data-ouia-safe="true"
45-
id="custom-file-upload-browse-button"
4644
type="button"
4745
>
4846
Browse...
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Matches the snapshot 1`] = `
4+
<DocumentFragment>
5+
<div
6+
class="pf-v5-c-file-upload__helper-text"
7+
>
8+
Content
9+
</div>
10+
</DocumentFragment>
11+
`;

packages/react-core/src/components/FileUpload/examples/FileUpload.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ subsection: file-upload
77
---
88

99
import FileUploadIcon from '@patternfly/react-icons/dist/esm/icons/file-upload-icon';
10+
import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
1011

1112
## Examples
1213

@@ -22,11 +23,18 @@ Pressing _Clear_ button triggers `onClearClick` event.
2223
```ts file="./FileUploadSimpleText.tsx"
2324
```
2425

25-
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.
26-
Typing/pasting text in the box will call `onTextChange` with a string, and a string value is expected for the `value` prop. :
26+
### With helper text
27+
28+
You can pass in the `<FileUploadHelperText` sub-component via the `children` property to `<FileUpload>`.
29+
30+
```ts file="./FileUploadWithHelperText.tsx"
31+
```
2732

2833
### Text file with edits allowed
2934

35+
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.
36+
Typing/pasting text in the box will call `onTextChange` with a string, and a string value is expected for the `value` prop. :
37+
3038
```ts file="./FileUploadTextWithEdits.tsx"
3139
```
3240

packages/react-core/src/components/FileUpload/examples/FileUploadCustomPreview.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React from 'react';
22
import { FileUpload } from '@patternfly/react-core';
33
import FileUploadIcon from '@patternfly/react-icons/dist/esm/icons/file-upload-icon';
4-
import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing';
54

65
export const CustomPreviewFileUpload: React.FunctionComponent = () => {
76
const [value, setValue] = React.useState<File>();
@@ -29,7 +28,7 @@ export const CustomPreviewFileUpload: React.FunctionComponent = () => {
2928
browseButtonText="Upload"
3029
>
3130
{value && (
32-
<div className={spacing.mMd}>
31+
<div>
3332
<FileUploadIcon width="2em" height="2em" /> Custom preview here for your {value.size}-byte file named{' '}
3433
{value.name}
3534
</div>

0 commit comments

Comments
 (0)