Skip to content

Commit

Permalink
feat(FormGroup, FormSelect, TextInput, TextArea): Add warning state (#…
Browse files Browse the repository at this point in the history
…4554)

* Add warning state to FormGroup, TextInput, TextArea and FormSelect

* fix lint error

* update FormSelect Example

* bump core versions

Co-authored-by: Titani <tlabaj@redaht.com>
  • Loading branch information
tlabaj and Titani committed Jul 16, 2020
1 parent 8e45351 commit 4e7f69a
Show file tree
Hide file tree
Showing 33 changed files with 236 additions and 39 deletions.
2 changes: 1 addition & 1 deletion packages/react-catalog-view-extension/package.json
Expand Up @@ -35,7 +35,7 @@
"clean": "rimraf dist"
},
"dependencies": {
"@patternfly/patternfly": "4.23.1",
"@patternfly/patternfly": "4.23.3",
"@patternfly/react-core": "^4.31.4",
"@patternfly/react-styles": "^4.4.6",
"classnames": "^2.2.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-charts/package.json
Expand Up @@ -29,7 +29,7 @@
},
"homepage": "https://github.com/patternfly/patternfly-react#readme",
"dependencies": {
"@patternfly/patternfly": "4.23.1",
"@patternfly/patternfly": "4.23.3",
"@patternfly/react-styles": "^4.4.6",
"@patternfly/react-tokens": "^4.5.3",
"hoist-non-react-statics": "^3.3.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-core/package.json
Expand Up @@ -45,7 +45,7 @@
"tslib": "^1.11.1"
},
"devDependencies": {
"@patternfly/patternfly": "4.23.1",
"@patternfly/patternfly": "4.23.3",
"@rollup/plugin-commonjs": "^11.0.2",
"@rollup/plugin-node-resolve": "^7.1.1",
"@rollup/plugin-replace": "^2.3.1",
Expand Down
13 changes: 9 additions & 4 deletions packages/react-core/src/components/Form/FormGroup.tsx
Expand Up @@ -17,9 +17,10 @@ export interface FormGroupProps extends Omit<React.HTMLProps<HTMLDivElement>, 'l
isRequired?: boolean;
/**
* Sets the FormGroup validated. If you set to success, text color of helper text will be modified to indicate valid state.
* If set to error, text color of helper text will be modified to indicate error state.
* If set to error, text color of helper text will be modified to indicate error state.
* If set to warning, text color of helper text will be modified to indicate warning state.
*/
validated?: 'success' | 'error' | 'default';
validated?: 'success' | 'warning' | 'error' | 'default';
/** Sets the FormGroup isInline. */
isInline?: boolean;
/** Removes top spacer from label. */
Expand Down Expand Up @@ -57,7 +58,11 @@ export const FormGroup: React.FunctionComponent<FormGroupProps> = ({
helperText
) : (
<div
className={css(styles.formHelperText, validated === ValidatedOptions.success && styles.modifiers.success)}
className={css(
styles.formHelperText,
validated === ValidatedOptions.success && styles.modifiers.success,
validated === ValidatedOptions.warning && styles.modifiers.warning
)}
id={`${fieldId}-helper`}
aria-live="polite"
>
Expand All @@ -76,7 +81,7 @@ export const FormGroup: React.FunctionComponent<FormGroupProps> = ({
</div>
);

const showValidHelperTxt = (validationType: 'success' | 'error' | 'default') =>
const showValidHelperTxt = (validationType: 'success' | 'warning' | 'error' | 'default') =>
validationType !== ValidatedOptions.error && helperText ? validHelperText : '';

return (
Expand Down
Expand Up @@ -137,6 +137,16 @@ describe('FormGroup component', () => {
expect(view).toMatchSnapshot();
});

test('should render form group validated warning variant', () => {
const view = mount(
<FormGroup label="label" fieldId="label-id" validated={ValidatedOptions.warning} helperText="Validated FormGroup">
<input id="id" />
</FormGroup>
);
expect(view.find('.pf-c-form__helper-text.pf-m-warning').length).toBe(1);
expect(view).toMatchSnapshot();
});

test('should render correctly when label is not a string with Children = Array', () => {
const view = mount(
<FormGroup fieldId="id" label={returnFunction()}>
Expand Down
Expand Up @@ -250,6 +250,49 @@ exports[`FormGroup component should render form group validated success variant
</FormGroup>
`;

exports[`FormGroup component should render form group validated warning variant 1`] = `
<FormGroup
fieldId="label-id"
helperText="Validated FormGroup"
label="label"
validated="warning"
>
<div
className="pf-c-form__group"
>
<div
className="pf-c-form__group-label"
>
<label
className="pf-c-form__label"
htmlFor="label-id"
>
<span
className="pf-c-form__label-text"
>
label
</span>
</label>
</div>
<div
className="pf-c-form__group-control"
>
<input
id="id"
/>
<div
aria-live="polite"
className="pf-c-form__helper-text pf-m-warning"
id="label-id-helper"
>
Validated FormGroup
</div>
</div>
</div>
</FormGroup>
`;

exports[`FormGroup component should render form group variant with function helperText 1`] = `
<FormGroup
fieldId="label-id"
Expand Down
2 changes: 1 addition & 1 deletion packages/react-core/src/components/Form/examples/Form.md
Expand Up @@ -359,7 +359,7 @@ class InvalidForm extends React.Component {
if (parseInt(value, 10) >= 21) {
this.setState({ validated: 'success', helperText: 'Enjoy your stay' });
} else {
this.setState({ validated: 'error', invalidText: 'You must be at least 21 to continue' });
this.setState({ validated: 'warning', helperText: 'You must be at least 21 to continue' });
}
} else {
this.setState({ validated: 'error', invalidText: 'Age has to be a number' });
Expand Down
5 changes: 3 additions & 2 deletions packages/react-core/src/components/FormSelect/FormSelect.tsx
Expand Up @@ -18,7 +18,7 @@ export interface FormSelectProps
* If set to success, select will be modified to indicate valid state.
* If set to error, select will be modified to indicate error state.
*/
validated?: 'success' | 'error' | 'default';
validated?: 'success' | 'warning' | 'error' | 'default';
/** Flag indicating the FormSelect is disabled */
isDisabled?: boolean;
/** Sets the FormSelectrequired. */
Expand Down Expand Up @@ -67,7 +67,8 @@ export class FormSelect extends React.Component<FormSelectProps> {
className={css(
styles.formControl,
className,
validated === ValidatedOptions.success && styles.modifiers.success
validated === ValidatedOptions.success && styles.modifiers.success,
validated === ValidatedOptions.warning && styles.modifiers.warning
)}
aria-invalid={validated === ValidatedOptions.error}
{...getOUIAProps(FormSelect.displayName, ouiaId, ouiaSafe)}
Expand Down
Expand Up @@ -147,6 +147,17 @@ test('validated error FormSelect input', () => {
expect(view).toMatchSnapshot();
});

test('validated warning FormSelect input', () => {
const view = shallow(
<FormSelect validated={ValidatedOptions.warning} aria-label="validated FormSelect">
<FormSelectOption key={1} value={props.options[1].value} label={props.options[1].label} />
</FormSelect>
);
expect(view.find('.pf-c-form-control.pf-m-warning').length).toBe(1);
expect(view).toMatchSnapshot();
});


test('required FormSelect input', () => {
const view = shallow(
<FormSelect required aria-label="required FormSelect">
Expand Down
Expand Up @@ -251,7 +251,7 @@ exports[`required FormSelect input 1`] = `
aria-invalid={false}
aria-label="required FormSelect"
className="pf-c-form-control"
data-ouia-component-id={9}
data-ouia-component-id={10}
data-ouia-component-type="PF4/FormSelect"
data-ouia-safe={true}
disabled={false}
Expand Down Expand Up @@ -314,3 +314,26 @@ exports[`validated success FormSelect input 1`] = `
/>
</select>
`;

exports[`validated warning FormSelect input 1`] = `
<select
aria-invalid={false}
aria-label="validated FormSelect"
className="pf-c-form-control pf-m-warning"
data-ouia-component-id={9}
data-ouia-component-type="PF4/FormSelect"
data-ouia-safe={true}
disabled={false}
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
required={false}
value=""
>
<FormSelectOption
key="1"
label="Mr"
value="mr"
/>
</select>
`;
Expand Up @@ -114,6 +114,8 @@ class FormSelectInputInvalid extends React.Component {
this.simulateNetworkCall(() => {
if (value === '3') {
this.setState({ validated: ValidatedOptions.success, helperText: 'You chose wisely' });
} else if (value === '') {
this.setState({ validated: ValidatedOptions.warning, helperText: 'You must select a value' });
} else {
this.setState({ validated: ValidatedOptions.error, invalidText: 'You must chose Three (thought that was obvious)' });
}
Expand Down
5 changes: 3 additions & 2 deletions packages/react-core/src/components/TextArea/TextArea.tsx
Expand Up @@ -19,7 +19,7 @@ export interface TextAreaProps extends Omit<HTMLProps<HTMLTextAreaElement>, 'onC
* If set to success, textarea will be modified to indicate valid state.
* If set to error, textarea will be modified to indicate error state.
*/
validated?: 'success' | 'error' | 'default';
validated?: 'success' | 'warning' | 'error' | 'default';
/** Value of the TextArea. */
value?: string | number;
/** A callback for when the TextArea value changes. */
Expand Down Expand Up @@ -64,7 +64,8 @@ export class TextArea extends React.Component<TextAreaProps> {
styles.formControl,
className,
resizeOrientation !== TextAreResizeOrientation.both && styles.modifiers[orientation],
validated === ValidatedOptions.success && styles.modifiers.success
validated === ValidatedOptions.success && styles.modifiers.success,
validated === ValidatedOptions.warning && styles.modifiers.warning
)}
onChange={this.handleChange}
{...(typeof this.props.defaultValue !== 'string' && { value })}
Expand Down
Expand Up @@ -36,6 +36,14 @@ test('validated text area success', () => {
expect(view).toMatchSnapshot();
});

test('validated text area warning', () => {
const view = shallow(
<TextArea {...props} required validated={ValidatedOptions.warning} aria-label="validated textarea" />
);
expect(view.find('.pf-c-form-control.pf-m-warning').length).toBe(1);
expect(view).toMatchSnapshot();
});

test('validated text area error', () => {
const view = shallow(
<TextArea {...props} required validated={ValidatedOptions.error} aria-label="validated textarea" />
Expand Down
Expand Up @@ -55,6 +55,17 @@ exports[`validated text area success 1`] = `
/>
`;

exports[`validated text area warning 1`] = `
<textarea
aria-invalid={false}
aria-label="validated textarea"
className="pf-c-form-control pf-m-warning"
onChange={[Function]}
required={true}
value="test textarea"
/>
`;

exports[`vertically resizable text area 1`] = `
<textarea
aria-invalid={false}
Expand Down
Expand Up @@ -92,14 +92,14 @@ class InvalidTextArea extends React.Component {
},
this.simulateNetworkCall(() => {
if (value && value.length > 0) {
if (value.length > 10) {
if (value.length >= 10) {
this.setState({validated: 'success', helperText: 'Thanks for your comments!'});
} else {
this.setState({validated: 'error', invalidText: 'Your being too brief, please enter at least 10 characters.'});
}
}
else {
this.setState({validated: 'error', invalidText: 'You must have something to say'});
this.setState({validated: 'warning', helperText: 'You must have something to say'});
}
})
);
Expand Down
5 changes: 3 additions & 2 deletions packages/react-core/src/components/TextInput/TextInput.tsx
Expand Up @@ -30,7 +30,7 @@ export interface TextInputProps extends Omit<React.HTMLProps<HTMLInputElement>,
* If set to success, input will be modified to indicate valid state.
* If set to error, input will be modified to indicate error state.
*/
validated?: 'success' | 'error' | 'default';
validated?: 'success' | 'warning' | 'error' | 'default';
/** A callback for when the input value changes. */
onChange?: (value: string, event: React.FormEvent<HTMLInputElement>) => void;
/** Type that the input accepts. */
Expand Down Expand Up @@ -60,7 +60,7 @@ export class TextInputBase extends React.Component<TextInputProps> {
'aria-label': null,
className: '',
isRequired: false,
validated: 'default' as 'success' | 'error' | 'default',
validated: 'default' as 'success' | 'warning' | 'error' | 'default',
isDisabled: false,
isReadOnly: false,
type: TextInputTypes.text,
Expand Down Expand Up @@ -101,6 +101,7 @@ export class TextInputBase extends React.Component<TextInputProps> {
className={css(
styles.formControl,
validated === ValidatedOptions.success && styles.modifiers.success,
validated === ValidatedOptions.warning && styles.modifiers.warning,
className
)}
onChange={this.handleChange}
Expand Down
Expand Up @@ -46,6 +46,15 @@ test('validated text input success', () => {
expect(view).toMatchSnapshot();
});

test('validated text input success', () => {
const view = mount(
<TextInput {...props} required validated={ValidatedOptions.warning} aria-label="validated text input" />
);
expect(view.find('.pf-c-form-control.pf-m-warning').length).toBe(1);
expect(view).toMatchSnapshot();
});


test('validated text input', () => {
const view = shallow(
<TextInput {...props} required validated={ValidatedOptions.error} aria-label="validated text input" />
Expand Down
Expand Up @@ -106,3 +106,39 @@ exports[`validated text input success 1`] = `
</TextInputBase>
</ForwardRef>
`;

exports[`validated text input success 2`] = `
<ForwardRef
aria-label="validated text input"
onChange={[MockFunction]}
required={true}
validated="warning"
value="test input"
>
<TextInputBase
aria-label="validated text input"
className=""
innerRef={null}
isDisabled={false}
isReadOnly={false}
isRequired={false}
onChange={[MockFunction]}
required={true}
type="text"
validated="warning"
value="test input"
>
<input
aria-invalid={false}
aria-label="validated text input"
className="pf-c-form-control pf-m-warning"
disabled={false}
onChange={[Function]}
readOnly={false}
required={false}
type="text"
value="test input"
/>
</TextInputBase>
</ForwardRef>
`;
1 change: 1 addition & 0 deletions packages/react-core/src/helpers/constants.ts
Expand Up @@ -7,5 +7,6 @@ export const KEYHANDLER_DIRECTION = { UP: 'up', DOWN: 'down', RIGHT: 'right', LE
export enum ValidatedOptions {
success = 'success',
error = 'error',
warning = 'warning',
default = 'default'
}
2 changes: 1 addition & 1 deletion packages/react-docs/package.json
Expand Up @@ -25,7 +25,7 @@
"dependencies": {
"@mdx-js/mdx": "^1.1.5",
"@mdx-js/react": "^1.1.5",
"@patternfly/patternfly": "4.23.1",
"@patternfly/patternfly": "4.23.3",
"@patternfly/react-catalog-view-extension": "^4.4.27",
"@patternfly/react-charts": "^6.5.8",
"@patternfly/react-core": "^4.31.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-icons/package.json
Expand Up @@ -32,7 +32,7 @@
"@fortawesome/free-brands-svg-icons": "^5.7.2",
"@fortawesome/free-regular-svg-icons": "^5.7.2",
"@fortawesome/free-solid-svg-icons": "^5.7.2",
"@patternfly/patternfly": "4.23.1",
"@patternfly/patternfly": "4.23.3",
"fs-extra": "^6.0.1",
"glob": "^7.1.2",
"rimraf": "^2.6.2",
Expand Down

0 comments on commit 4e7f69a

Please sign in to comment.