Skip to content

Commit

Permalink
BREAKING CHANGE(web-react): Rename message prop to validationText
Browse files Browse the repository at this point in the history
… in Form Fields #DS-676

 ## Migration Guide

- Instead of the `message` prop, use `validationText`.
- The `validationState` prop is now required when using `validationText`.
  If `validationState` is not set, `validationText` won't render.
- To show a permanent helper, use `helperText`.

- `<… validationState="danger" message="error" …>`
   → `<… validationState="danger" validationText="error" …>`
- `<… message="Check this field" …>` → `<… helperText="Check this field" …>`

List of affected components:
- Checkbox
- TextField
- TextArea
- TextFieldBase
- Select

Please refer back to these instructions or reach out to our team
if you encounter any issues during migration.
  • Loading branch information
crishpeen authored and literat committed Jul 21, 2023
1 parent 2782212 commit b80d336
Show file tree
Hide file tree
Showing 30 changed files with 116 additions and 127 deletions.
29 changes: 15 additions & 14 deletions packages/web-react/src/components/CheckboxField/CheckboxField.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { forwardRef, ForwardedRef } from 'react';
import classNames from 'classnames';
import { useDeprecationMessage, useStyleProps } from '../../hooks';
import { useStyleProps } from '../../hooks';
import { SpiritCheckboxFieldProps } from '../../types';
import { useValidationText } from '../Field';
import { useCheckboxFieldStyleProps } from './useCheckboxFieldStyleProps';
Expand All @@ -9,24 +9,25 @@ import { useCheckboxFieldStyleProps } from './useCheckboxFieldStyleProps';
/* eslint no-underscore-dangle: ['error', { allow: ['_CheckboxField'] }] */
const _CheckboxField = (props: SpiritCheckboxFieldProps, ref: ForwardedRef<HTMLInputElement>): JSX.Element => {
const { classProps, props: modifiedProps } = useCheckboxFieldStyleProps(props);
const { id, label, message, helperText, validationState, value, isDisabled, isRequired, isChecked, ...restProps } =
modifiedProps;
const {
id,
label,
validationText,
helperText,
validationState,
value,
isDisabled,
isRequired,
isChecked,
...restProps
} = modifiedProps;
const { styleProps, props: otherProps } = useStyleProps(restProps);

useDeprecationMessage({
method: 'custom',
trigger: !!(props?.message && !validationState),
componentName: 'CheckboxField',
customText:
'`message` prop without `validationState` prop will be unsupported in the next version. Use `helperText` instead.',
});

const renderValidationText = useValidationText({
validationTextClassName: classProps.message,
validationTextClassName: classProps.validationText,
validationState,
validationText: message,
validationText,
validationElementType: 'span',
requireValidationState: false,
});

return (
Expand Down
18 changes: 12 additions & 6 deletions packages/web-react/src/components/CheckboxField/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# CheckboxField

CheckboxField enables the user to check/uncheck choice. It has input, a label,
and an optional message. It could be disabled or have a validation state. The label could be hidden
and show if the input is required.
CheckboxField enables the user to check/uncheck choice. It has input, a label, and an optional helperText.
It could be disabled or have a validation state. The label could be hidden and show if the input is required.

```jsx
<CheckboxField id="example" name="example" isRequired isChecked validationState="danger" message="validation failed" />
<CheckboxField
id="example"
name="example"
isRequired
isChecked
validationState="danger"
validationText="validation failed"
/>
```

## Available props
Expand All @@ -16,8 +22,8 @@ and show if the input is required.
| `name` | `string` | - | no | Input name |
| `label` | `string` | - | no | Label text |
| `value` | `string` | - | no | Input value |
| `message` | `string`, `string[]` | - | no | Validation or help message |
| `validationState` | [Validation dictionary][dictionary-validation] | - | no | Type of validation state. |
| `validationText` | `string`, `string[]` | - | no | Validation text |
| `isDisabled` | `boolean` | - | no | Whether is field disabled |
| `isItem` | `boolean` | - | no | To render in [Item][item] mode |
| `isRequired` | `boolean` | - | no | Whether is field required |
Expand All @@ -39,7 +45,7 @@ const CustomCheckboxField = (props: SpiritCheckboxFieldProps): JSX.Element => {
<span className={styleProps.text}>
<span className={styleProps.label}>{props.label}</span>
<span className={styleProps.helperText}>{props.helperText}</span>
<span className={styleProps.message}>{props.message}</span>
<span className={styleProps.validationText}>{props.validationText}</span>
</span>
</label>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('CheckboxField', () => {

validationStatePropsTest(CheckboxField, 'CheckboxField--');

validationTextPropsTest(CheckboxField, '.CheckboxField__message');
validationTextPropsTest(CheckboxField, '.CheckboxField__validationText');

it('should have text classname', () => {
const dom = render(<CheckboxField id="checkbox" label="Label" />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('useCheckboxFieldStyleProps', () => {
text: 'CheckboxField__text',
input: 'CheckboxField__input',
label: 'CheckboxField__label',
message: 'CheckboxField__message',
validationText: 'CheckboxField__validationText',
helperText: 'CheckboxField__helperText',
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ const Story = () => (
label="Checkbox success"
name="example"
validationState="success"
message="Success validation message"
validationText="Success validation text"
/>
<CheckboxField
id="checkboxfield1"
label="Checkbox warning"
name="example"
validationState="warning"
message="Warning validation message"
validationText="Warning validation text"
/>
<CheckboxField
id="checkboxfield2"
label="Checkbox danger"
name="example"
validationState="danger"
message={['Danger validation message', 'Danger validation message']}
validationText={['Danger validation text', 'Danger validation text']}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ export default {
},
defaultValue: '',
},
message: {
validationText: {
control: {
type: 'object',
},
defaultValue: '',
description:
'The validation message. Use a string `"foo"` for single message or an array for multiple messages `["foo", "bar"]`.',
'The validation text. Only visible if validationState is set. Use a string `"foo"` for single validation text or an array for multiple validation texts `["foo", "bar"]`.',
},
helperText: {
control: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export interface CheckboxFieldStyles {
text: string;
label: string;
input: string;
message: string;
helperText: string;
validationText: string;
};
/** props to be passed to the input element */
props: CheckboxFieldProps;
Expand All @@ -28,14 +28,14 @@ export function useCheckboxFieldStyleProps(props: SpiritCheckboxFieldProps): Che
const checkboxFieldLabelClass = `${checkboxFieldClass}__label`;
const checkboxFieldLabelRequiredClass = `${checkboxFieldClass}__label--required`;
const checkboxFieldLabelHiddenClass = `${checkboxFieldClass}__label--hidden`;
const checkboxFieldMessageClass = `${checkboxFieldClass}__message`;
const checkboxFieldHelperTextClass = `${checkboxFieldClass}__helperText`;
const checkboxValidationClass = `${checkboxFieldClass}--${validationState}`;
const checkboxFieldValidationTextClass = `${checkboxFieldClass}__validationText`;
const checkboxFieldValidationClass = `${checkboxFieldClass}--${validationState}`;

const rootStyles = classNames(checkboxFieldClass, {
[checkboxFieldDisabledClass]: isDisabled,
[checkboxFieldItemClass]: isItem,
[checkboxValidationClass]: validationState,
[checkboxFieldValidationClass]: validationState,
});
const labelStyles = classNames(checkboxFieldLabelClass, {
[checkboxFieldLabelRequiredClass]: isRequired,
Expand All @@ -48,9 +48,12 @@ export function useCheckboxFieldStyleProps(props: SpiritCheckboxFieldProps): Che
text: checkboxFieldTextClass,
label: labelStyles,
input: checkboxFieldInputClass,
message: checkboxFieldMessageClass,
helperText: checkboxFieldHelperTextClass,
validationText: checkboxFieldValidationTextClass,
},
props: {
...restProps,
validationState,
},
props: restProps,
};
}
18 changes: 10 additions & 8 deletions packages/web-react/src/components/Field/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
# ValidationText
# Field

The validationText subcomponent displays validation messages for Field components like TextField, TextArea, CheckboxField, FileUploader, etc.
## ValidationText

The ValidationText subcomponent displays validation texts for Field components like TextField, TextArea, CheckboxField, FileUploader, etc.

```jsx
import { ValidationText } from '@lmc-eu/spirit-web-react/components';
```

```jsx
<ValidationText elementType="div" className="TextField__message" validationText="This field is required" />
<ValidationText elementType="div" className="TextField__validationText" validationText="This field is required" />
```

## ValidationText

**Available props**

| Name | Type | Default | Required | Description |
| ---------------- | -------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------- |
| `elementType` | `span`, `div` | `div` | no | Type of element used as main wrapper (applied only for single validation message, otherwise `ul`) |
| `className` | `string` | - | yes | Wrapper custom class name |
| `validationText` | `string`, `string[]` | - | yes | Validation message |
| Name | Type | Default | Required | Description |
| ---------------- | -------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------- |
| `elementType` | `span`, `div` | `div` | no | Type of element used as main wrapper (applied only for single validation text, otherwise `ul`) |
| `className` | `string` | - | yes | Wrapper custom class name |
| `validationText` | `string`, `string[]` | - | yes | Validation text |
5 changes: 2 additions & 3 deletions packages/web-react/src/components/Field/ValidationText.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React, { ElementType } from 'react';
import { ValidationTextType } from '../../types';
import { ValidationTextProp } from '../../types';

export interface ValidationTextProps {
export interface ValidationTextProps extends ValidationTextProp {
className?: string;
validationText: ValidationTextType;
elementType?: ElementType;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ import ValidationText from '../ValidationText';

describe('ValidationText', () => {
it('should render single validation text', () => {
const dom = render(<ValidationText className="ValidationText__message" validationText="validation message" />);
const dom = render(<ValidationText className="ValidationText__validationText" validationText="validation text" />);

const element = dom.container.querySelector('div') as HTMLElement;
expect(element.textContent).toBe('validation message');
expect(element.textContent).toBe('validation text');
});

it('should render multiple validation messages', () => {
it('should render multiple validation texts', () => {
const dom = render(
<ValidationText
className="ValidationText__message"
validationText={['validation message', 'another validation message']}
className="ValidationText__validationText"
validationText={['validation text', 'another validation text']}
/>,
);

const elements = dom.container.querySelectorAll('li') as NodeListOf<HTMLLIElement>;
expect(elements[0].textContent).toBe('validation message');
expect(elements[1].textContent).toBe('another validation message');
expect(elements[0].textContent).toBe('validation text');
expect(elements[1].textContent).toBe('another validation text');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@ import { renderHook } from '@testing-library/react-hooks';
import { useValidationText } from '../useValidationText';

describe('useValidationText', () => {
it('should return null', () => {
it('should return undefined', () => {
const { result } = renderHook(() => useValidationText({ validationTextClassName: '', validationState: undefined }));

expect(result.current).toBeNull();
expect(result.current).toBeUndefined();
});

it('should return ValidationText component', () => {
const { result } = renderHook(() =>
useValidationText({
validationTextClassName: 'TextField__message',
validationTextClassName: 'TextField__validationText',
validationState: 'danger',
validationText: 'required',
}),
);

expect(result.current).toMatchInlineSnapshot(`
<ValidationText
className="TextField__message"
className="TextField__validationText"
elementType="div"
validationText="required"
/>
Expand Down
16 changes: 4 additions & 12 deletions packages/web-react/src/components/Field/useValidationText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,21 @@ export interface UseValidationTextProps {
validationState?: ValidationState;
validationText?: ValidationTextType;
validationElementType?: ElementType;
/** @deprecated Will be removed in the next major version. */
requireValidationState?: boolean;
}

export const useValidationText = (props: UseValidationTextProps): ReactNode => {
const {
validationTextClassName,
validationState,
validationText,
validationElementType,
/** @deprecated Will be removed in the next major version. */
requireValidationState = true,
} = props;
const { validationTextClassName, validationState, validationText, validationElementType } = props;

return useMemo(
() =>
(requireValidationState && !validationState) || !validationText ? null : (
validationState &&
validationText && (
<ValidationText
className={validationTextClassName}
validationText={validationText}
elementType={validationElementType}
/>
),
[validationState, validationText, validationElementType, validationTextClassName, requireValidationState],
[validationState, validationText, validationElementType, validationTextClassName],
);
};
12 changes: 6 additions & 6 deletions packages/web-react/src/components/TextArea/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# TextArea

TextArea enables the user to add longer text to a form. It has textarea, label,
and an optional message. It could be disabled or have a validation state. The label could be hidden
and show if the textarea is required.
TextArea enables the user to add longer text to a form.
It could be disabled or have a validation state with validation text.
The label could be hidden and show if the textarea is required.

```jsx
<TextArea id="example" name="example" validationState="danger" message="validation failed" isRequired />
<TextArea id="example" name="example" validationState="danger" validationText="validation failed" isRequired />
```

## Textarea with Auto-Height Adjustment
Expand All @@ -24,10 +24,10 @@ and show if the textarea is required.
| `placeholder` | `string` | - | no | Textarea placeholder |
| `value` | `string` | - | no | Textarea value |
| `maxLength` | `number` | - | no | Maximum number of characters |
| `message` | `string`, `string[]` | - | no | Validation message |
| `rows` | `number` | - | no | Number of visible rows |
| `ref` | `ForwardedRef<HTMLTextAreaElement>` | - | no | Textarea element reference |
| `validationState` | [Validation dictionary][dictionary-validation] | - | no | Type of validation state. |
| `validationState` | [Validation dictionary][dictionary-validation] | - | no | Type of validation state |
| `validationText` | `string`, `string[]` | - | no | Validation text |
| `isAutoResizing` | `boolean` | - | no | Whether is field auto resizing which adjusts its height while typing |
| `isDisabled` | `boolean` | - | no | Whether is field disabled |
| `isRequired` | `boolean` | - | no | Whether is field required |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('TextArea', () => {

validationStatePropsTest(TextArea, 'TextArea--');

validationTextPropsTest(TextArea, '.TextArea__message');
validationTextPropsTest(TextArea, '.TextArea__validationText');

it('should have label classname', () => {
const dom = render(<TextArea id="textarea" label="Label" />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ const Story = (props: unknown) => (
id="textarea-success"
label="Validation success"
name="textarea-success"
message="Success message"
validationState="success"
validationText="Success validationText"
/>
<TextArea
id="textarea-warning"
label="Validation warning"
message="Warning message"
name="textarea-warning"
validationState="warning"
validationText="Warning validationText"
/>
<TextArea
id="textarea-danger"
label="Validation danger"
message={['Danger message', 'Second Danger message']}
name="textarea-danger"
validationState="danger"
validationText={['Danger validationText', 'Second Danger validationText']}
/>
</div>
);
Expand Down
Loading

0 comments on commit b80d336

Please sign in to comment.