Skip to content

Commit 23d02b1

Browse files
author
Eric Olkowski
committed
Updated examples and tests
1 parent f5df2ac commit 23d02b1

File tree

10 files changed

+93
-74
lines changed

10 files changed

+93
-74
lines changed

packages/react-core/src/components/HelperText/HelperTextItem.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,39 @@ import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/excl
66
import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon';
77
import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
88

9+
export enum HelperTextItemVariant {
10+
default = 'default',
11+
warning = 'warning',
12+
error = 'error',
13+
success = 'success'
14+
}
15+
916
export interface HelperTextItemProps extends React.HTMLProps<HTMLDivElement | HTMLLIElement> {
1017
/** Content rendered inside the helper text item. */
1118
children?: React.ReactNode;
1219
/** Additional classes applied to the helper text item. */
1320
className?: string;
1421
/** Sets the component type of the helper text item. */
1522
component?: 'div' | 'li';
16-
/** Status styling of the helper text item. Will also render a default icon, which can be overridden
23+
/** Variant styling of the helper text item. Will also render a default icon, which can be overridden
1724
* with the icon prop.
1825
*/
19-
status?: 'indeterminate' | 'warning' | 'success' | 'error';
20-
/** Custom icon prefixing the helper text. This property will override the default icon when the status property is passed in. */
26+
variant?: 'default' | 'indeterminate' | 'warning' | 'success' | 'error';
27+
/** Custom icon prefixing the helper text. This property will override the default icon when the variant property is passed in. */
2128
icon?: React.ReactNode;
2229
/** ID for the helper text item. The value of this prop can be passed into a form component's
2330
* aria-describedby prop when you intend for only specific helper text items to be announced to
2431
* assistive technologies.
2532
*/
2633
id?: string;
27-
/** Text that is only accessible to screen readers in order to announce the status of a helper text item.
28-
* This prop can only be used when the status prop is also passed in.
34+
/** Text that is only accessible to screen readers in order to announce the variant of a helper text item.
35+
* This prop can only be used when the variant prop has a value other than "default".
2936
*/
3037
screenReaderText?: string;
3138
}
3239

33-
const defaultStatusIcons = {
40+
const defaultVariantIcons = {
41+
default: <></>,
3442
indeterminate: <MinusIcon />,
3543
warning: <ExclamationTriangleIcon />,
3644
success: <CheckCircleIcon />,
@@ -41,24 +49,29 @@ export const HelperTextItem: React.FunctionComponent<HelperTextItemProps> = ({
4149
children,
4250
className,
4351
component = 'div',
44-
status,
52+
variant = 'default',
4553
icon,
4654
id,
47-
screenReaderText = `${status} status`,
55+
screenReaderText = `${variant} status`,
4856
...props
4957
}: HelperTextItemProps) => {
5058
const Component = component as any;
59+
const isNotDefaultVariant = variant !== 'default';
5160
return (
52-
<Component className={css(styles.helperTextItem, styles.modifiers[status], className)} id={id} {...props}>
53-
{(status || icon) && (
61+
<Component
62+
className={css(styles.helperTextItem, isNotDefaultVariant && styles.modifiers[variant], className)}
63+
id={id}
64+
{...props}
65+
>
66+
{(isNotDefaultVariant || icon) && (
5467
<span className={css(styles.helperTextItemIcon)} aria-hidden>
55-
{icon || defaultStatusIcons[status]}
68+
{icon || defaultVariantIcons[variant]}
5669
</span>
5770
)}
5871

5972
<span className={css(styles.helperTextItemText)}>
6073
{children}
61-
{status && <span className="pf-v5-screen-reader">: {screenReaderText};</span>}
74+
{isNotDefaultVariant && <span className="pf-v5-screen-reader">: {screenReaderText};</span>}
6275
</span>
6376
</Component>
6477
);

packages/react-core/src/components/HelperText/__tests__/HelperTextItem.test.tsx

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ test('Renders custom className', () => {
3030
expect(screen.getByText('help test text 1').parentElement).toHaveClass('custom');
3131
});
3232

33+
test('Does not render screen reader text by default', () => {
34+
render(<HelperTextItem>help test text 1</HelperTextItem>);
35+
36+
expect(screen.queryByText('help test text 1')?.querySelector('.pf-v5-screen-reader')).not.toBeInTheDocument();
37+
});
38+
3339
Object.values(['indeterminate', 'warning', 'success', 'error']).forEach((variant) => {
3440
test(`Renders with class ${styles.modifiers[variant]} when variant = ${variant}`, () => {
3541
render(
@@ -39,6 +45,15 @@ Object.values(['indeterminate', 'warning', 'success', 'error']).forEach((variant
3945
);
4046
expect(screen.getByText('text').parentElement).toHaveClass(styles.modifiers[variant]);
4147
});
48+
49+
test(`Renders default screenreader text when variant = ${variant}`, () => {
50+
render(
51+
<HelperTextItem variant={variant as 'default' | 'indeterminate' | 'warning' | 'success' | 'error'}>
52+
text
53+
</HelperTextItem>
54+
);
55+
expect(screen.getByText('text').querySelector('span')).toHaveTextContent(`: ${variant} status;`);
56+
});
4257
});
4358

4459
test('Renders id when id is passed', () => {
@@ -56,38 +71,26 @@ test('Renders with element passed to component prop', () => {
5671
expect(screen.getByText('help test text 1').parentElement?.tagName).toBe('LI');
5772
});
5873

59-
test('Renders custom icon', () => {
60-
render(<HelperTextItem icon={<div>test</div>}>help test text</HelperTextItem>);
61-
expect(screen.getByText('test').parentElement).toHaveClass(styles.helperTextItemIcon);
62-
});
63-
64-
test('Renders default icon when hasIcon = true and icon is not passed', () => {
65-
render(<HelperTextItem hasIcon>help test text</HelperTextItem>);
66-
expect(screen.getByText('help test text').parentElement?.querySelector('span')).toHaveClass(
67-
styles.helperTextItemIcon
68-
);
74+
test('Does not render an icon by default', () => {
75+
render(<HelperTextItem>help test text</HelperTextItem>);
76+
expect(screen.queryByText('help test text')?.previousSibling).not.toBeInTheDocument();
6977
});
7078

71-
test('Renders custom icon when icon is passed and hasIcon = true', () => {
72-
render(
73-
<HelperTextItem hasIcon icon={<div>test</div>}>
74-
help test text
75-
</HelperTextItem>
76-
);
77-
expect(screen.getByText('test').parentElement).toHaveClass(styles.helperTextItemIcon);
79+
test('Renders a default icon when variant is passed and icon is not passed', () => {
80+
render(<HelperTextItem variant="success">help test text</HelperTextItem>);
81+
expect(screen.getByText('help test text').previousSibling).toHaveClass(styles.helperTextItemIcon);
7882
});
7983

80-
test('Renders dynamic helper text', () => {
81-
render(<HelperTextItem isDynamic>help test text</HelperTextItem>);
82-
expect(screen.getByText('help test text').parentElement).toHaveClass(styles.modifiers.dynamic);
83-
expect(screen.getByText('help test text').querySelector('span')).toHaveClass('pf-v5-screen-reader');
84+
test('Renders custom icon when icon prop is passed', () => {
85+
render(<HelperTextItem icon={<div>icon content</div>}>help test text</HelperTextItem>);
86+
expect(screen.getByText('icon content').parentElement).toHaveClass(styles.helperTextItemIcon);
8487
});
8588

86-
test('Renders custom screenreader text when isDynamic = true and screenReaderText is passed', () => {
89+
test('Renders custom icon instead of variant icon when icon and variant are passed', () => {
8790
render(
88-
<HelperTextItem isDynamic screenReaderText="sr test">
91+
<HelperTextItem icon={<div>icon content</div>} variant="success">
8992
help test text
9093
</HelperTextItem>
9194
);
92-
expect(screen.getByText('help test text').querySelector('span')).toHaveTextContent('sr test');
95+
expect(screen.getByText('icon content').parentElement).toHaveClass(styles.helperTextItemIcon);
9396
});

packages/react-core/src/components/HelperText/examples/HelperTextBasic.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ export const HelperTextBasic: React.FunctionComponent = () => (
77
<HelperTextItem>This is default helper text</HelperTextItem>
88
</HelperText>
99
<HelperText>
10-
<HelperTextItem status="indeterminate">This is indeterminate helper text</HelperTextItem>
10+
<HelperTextItem variant="indeterminate">This is indeterminate helper text</HelperTextItem>
1111
</HelperText>
1212
<HelperText>
13-
<HelperTextItem status="warning">This is warning helper text</HelperTextItem>
13+
<HelperTextItem variant="warning">This is warning helper text</HelperTextItem>
1414
</HelperText>
1515
<HelperText>
16-
<HelperTextItem status="success">This is success helper text</HelperTextItem>
16+
<HelperTextItem variant="success">This is success helper text</HelperTextItem>
1717
</HelperText>
1818
<HelperText>
19-
<HelperTextItem status="error">This is error helper text</HelperTextItem>
19+
<HelperTextItem variant="error">This is error helper text</HelperTextItem>
2020
</HelperText>
2121
</React.Fragment>
2222
);

packages/react-core/src/components/HelperText/examples/HelperTextWithCustomIcon.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@ export const HelperTextWithCustomIcon: React.FunctionComponent = () => (
1212
<HelperTextItem icon={<InfoIcon />}>This is default helper text</HelperTextItem>
1313
</HelperText>
1414
<HelperText>
15-
<HelperTextItem status="indeterminate" icon={<QuestionIcon />}>
15+
<HelperTextItem variant="indeterminate" icon={<QuestionIcon />}>
1616
This is indeterminate helper text
1717
</HelperTextItem>
1818
</HelperText>
1919
<HelperText>
20-
<HelperTextItem status="warning" icon={<ExclamationIcon />}>
20+
<HelperTextItem variant="warning" icon={<ExclamationIcon />}>
2121
This is warning helper text
2222
</HelperTextItem>
2323
</HelperText>
2424
<HelperText>
25-
<HelperTextItem status="success" icon={<CheckIcon />}>
25+
<HelperTextItem variant="success" icon={<CheckIcon />}>
2626
This is success helper text
2727
</HelperTextItem>
2828
</HelperText>
2929
<HelperText>
30-
<HelperTextItem status="error" icon={<TimesIcon />}>
30+
<HelperTextItem variant="error" icon={<TimesIcon />}>
3131
This is error helper text
3232
</HelperTextItem>
3333
</HelperText>

packages/react-core/src/components/MultipleFileUpload/examples/MultipleFileUploadBasic.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const MultipleFileUploadBasic: React.FunctionComponent = () => {
6363
if (fileUploadShouldFail) {
6464
const corruptedFiles = files.map((file) => ({ ...file, lastModified: 'foo' as unknown as number }));
6565
// eslint-disable-next-line
66-
setCurrentFiles((prevFiles) => [...prevFiles, ...corruptedFiles as any]);
66+
setCurrentFiles((prevFiles) => [...prevFiles, ...(corruptedFiles as any)]);
6767
} else {
6868
setCurrentFiles((prevFiles) => [...prevFiles, ...files]);
6969
}
@@ -101,7 +101,7 @@ export const MultipleFileUploadBasic: React.FunctionComponent = () => {
101101
if (fileResult?.loadError) {
102102
return (
103103
<HelperText isLiveRegion>
104-
<HelperTextItem variant={'error'}>{fileResult.loadError.toString()}</HelperTextItem>
104+
<HelperTextItem variant="error">{fileResult.loadError.toString()}</HelperTextItem>
105105
</HelperText>
106106
);
107107
}

packages/react-core/src/demos/HelperText.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,40 @@ import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';
1212

1313
## Demos
1414

15-
### Static variant with static text
15+
### Static helper text
1616

17-
In this demo, the static variant of the helper text item component (the default) is used, and the text itself will always be visible to users and will never change.
17+
In this demo the text content of the helper text item will always be visible to users and will never change.
1818

1919
The `aria-describedby` attribute is passed into the text input component and is linked to the `id` of the helper text component. This allows assistive technologies to notify users of the helper text content when the input receives focus, which can be helpful if a user navigates away from and then back to the input.
2020

2121
Note that this demo does not validate the text input component. When it would need to be validated, there are other steps that would need to be taken to make it accessible, such as passing in `aria-invalid` and `aria-live` attributes to the appropriate components.
2222

23-
```ts file='./examples/HelperText/HelperTextStaticVariantStaticText.tsx'
23+
```ts file='./examples/HelperText/HelperTextStatic.tsx'
24+
2425
```
2526

26-
### Static variant with dynamic text
27+
### Dynamic helper text
2728

28-
In this demo, the static variant of the helper text item component (the default) is used with the `hasIcon` prop passed in when there is an error, and the text itself dynamically updates based on the input value. When the input has a value of `johndoe`, an error is rendered to simulate a username already being taken, while an empty input renders other helper text. When the input is valid, no helper text is rendered.
29+
In this demo the text content of the helper text item dynamically updates based on the input value. When the input has a value of `johndoe`, an error is rendered to simulate a username already being taken, while an empty input renders default text. When the input is valid, no helper text is rendered.
2930

3031
The `aria-describedby` attribute is passed into the text input component and is linked to the `id` of the helper text component. Similar to the static variant with static text demo, this allows assistive technologies to notify users of the helper text content when the navigating to the input.
3132

3233
An `aria-live` region is passed into the helper text component, which allows assistive technologies to announce to users when any dynamic content within it updates, such as when the text content changes or gets rendered. Without this attribute, a user would have to navigate out of and back into the input field multiple times to check the status of their input.
3334

3435
The `aria-invalid` attribute is also passed into the text input, which allows assistive technologies to notify users that an input is invalid. When this attribute is true, it's important that users are notified of what is causing the input to be invalid; in this case, `aria-describedby` and `aria-live` help accomplish this.
3536

36-
```ts file='./examples/HelperText/HelperTextStaticVariantDynamicText.tsx'
37+
```ts file='./examples/HelperText/HelperTextDynamic.tsx'
38+
3739
```
3840

39-
### Dynamic variant with static text
41+
### Static text and dynamic status
42+
43+
In this demo the text content of the helper text item remains static and never changes, but the icons and styling will change as the validation of the input changes.
4044

41-
In this demo, the helper text item components have the `isDynamic` prop passed in. While the text content of the components is static, the icons and styling will change as the validation of the input changes.
45+
The `aria-describedby` attribute is passed into the text input component and is linked to the `id` attribute of a helper text item that results in an invalid input. This will allow assistive technologies to only be notified of any outstanding criteria that has not been met when the input receives focus.
4246

43-
The `aria-describedby` attribute is passed into the text input component and is linked to the id attribute of a helper text item that results in an invalid input. This will allow assistive technologies to only be notified of any outstanding criteria that has not been met when the input receives focus.
47+
Similar to the [with dynamic text example](/components/helper-text/react-demos#with-dynamic-text), the `aria-invalid` attribute is passed in, allowing assistive technologies to announce to users when at least 1 item is causing the input to be invalid.
4448

45-
Similar to the static variant with dynamic text example, the `aria-invalid` attribute is passed in, allowing assistive technologies to announce to users when at least 1 item is causing the input to be invalid.
49+
```ts file='./examples/HelperText/HelperTextStaticTextDynamicVariant.tsx'
4650

47-
```ts file='./examples/HelperText/HelperTextDynamicVariantStaticText.tsx'
4851
```
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { Form, FormGroup, FormHelperText, TextInput, HelperText, HelperTextItem } from '@patternfly/react-core';
33

4-
export const HelperTextStaticVariantDynamicText: React.FunctionComponent = () => {
4+
export const HelperTextDynamic: React.FunctionComponent = () => {
55
const [value, setValue] = React.useState('');
66
const [inputValidation, setInputValidation] = React.useState('default');
77

@@ -35,7 +35,7 @@ export const HelperTextStaticVariantDynamicText: React.FunctionComponent = () =>
3535
<FormHelperText>
3636
<HelperText id="helper-text2" aria-live="polite">
3737
{inputValidation !== 'success' && (
38-
<HelperTextItem variant={inputValidation as any} hasIcon={inputValidation === 'error'}>
38+
<HelperTextItem variant={inputValidation as any}>
3939
{inputValidation === 'default' ? 'Please enter a username' : 'Username already exists'}
4040
</HelperTextItem>
4141
)}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { Form, FormGroup, FormHelperText, TextInput, HelperText, HelperTextItem } from '@patternfly/react-core';
33

4-
export const HelperTextStaticVariantStaticText: React.FunctionComponent = () => {
4+
export const HelperTextStaticText: React.FunctionComponent = () => {
55
const [value, setValue] = React.useState('');
66

77
const handleInputChange = (_event, inputValue: string) => {
@@ -21,7 +21,7 @@ export const HelperTextStaticVariantStaticText: React.FunctionComponent = () =>
2121
/>
2222
<FormHelperText>
2323
<HelperText id="helper-text1">
24-
<HelperTextItem variant={'default'}>Enter your middle name or your middle initial</HelperTextItem>
24+
<HelperTextItem>Enter your middle name or your middle initial</HelperTextItem>
2525
</HelperText>
2626
</FormHelperText>
2727
</FormGroup>
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { Form, FormGroup, FormHelperText, TextInput, HelperText, HelperTextItem } from '@patternfly/react-core';
33

4-
export const HelperTextDynamicVariantDynamicText: React.FunctionComponent = () => {
4+
export const HelperTextStaticTextDynamicVariant: React.FunctionComponent = () => {
55
const [value, setValue] = React.useState('');
66
const [inputValidation, setInputValidation] = React.useState({
77
ruleLength: 'indeterminate',
@@ -10,8 +10,8 @@ export const HelperTextDynamicVariantDynamicText: React.FunctionComponent = () =
1010
const { ruleLength, ruleCharacterTypes } = inputValidation;
1111

1212
React.useEffect(() => {
13-
let lengthStatus = ruleLength;
14-
let typeStatus = ruleCharacterTypes;
13+
let lengthVariant = ruleLength;
14+
let typeVariant = ruleCharacterTypes;
1515

1616
if (value === '') {
1717
setInputValidation({
@@ -22,18 +22,18 @@ export const HelperTextDynamicVariantDynamicText: React.FunctionComponent = () =
2222
}
2323

2424
if (!/\d/g.test(value)) {
25-
typeStatus = 'error';
25+
typeVariant = 'error';
2626
} else {
27-
typeStatus = 'success';
27+
typeVariant = 'success';
2828
}
2929

3030
if (value.length < 5) {
31-
lengthStatus = 'error';
31+
lengthVariant = 'error';
3232
} else {
33-
lengthStatus = 'success';
33+
lengthVariant = 'success';
3434
}
3535

36-
setInputValidation({ ruleLength: lengthStatus, ruleCharacterTypes: typeStatus });
36+
setInputValidation({ ruleLength: lengthVariant, ruleCharacterTypes: typeVariant });
3737
}, [value, ruleLength, ruleCharacterTypes]);
3838

3939
const handleInputChange = (_event, inputValue: string) => {
@@ -57,10 +57,10 @@ export const HelperTextDynamicVariantDynamicText: React.FunctionComponent = () =
5757
/>
5858
<FormHelperText>
5959
<HelperText component="ul">
60-
<HelperTextItem component="li" id="ruleLength" status={ruleLength as any}>
60+
<HelperTextItem component="li" id="ruleLength" variant={ruleLength as any}>
6161
Must be at least 5 characters in length
6262
</HelperTextItem>
63-
<HelperTextItem component="li" id="ruleCharacterTypes" status={ruleCharacterTypes as any}>
63+
<HelperTextItem component="li" id="ruleCharacterTypes" variant={ruleCharacterTypes as any}>
6464
Must include at least 1 number
6565
</HelperTextItem>
6666
</HelperText>

0 commit comments

Comments
 (0)