Skip to content

Commit

Permalink
FEAT: Added field warning component to all fields (#2698)
Browse files Browse the repository at this point in the history
* feat: added field warning component to all fields

* fix: update dependencies

* Update .changeset/fair-cooks-press.md

Co-authored-by: Carlos Cortizas <97907068+CarlosCortizasCT@users.noreply.github.com>

* fix: deprecate render default warning function

* fix: fix date range border issue

* Update packages/components/fields/date-field/src/date-field.visualroute.jsx

Co-authored-by: Carlos Cortizas <97907068+CarlosCortizasCT@users.noreply.github.com>

* Update packages/components/fields/multiline-text-field/src/multiline-text-field.visualroute.jsx

Co-authored-by: Carlos Cortizas <97907068+CarlosCortizasCT@users.noreply.github.com>

* Update packages/components/fields/date-time-field/src/date-time-field.visualroute.jsx

Co-authored-by: Carlos Cortizas <97907068+CarlosCortizasCT@users.noreply.github.com>

* Update packages/components/fields/money-field/src/money-field.visualroute.jsx

Co-authored-by: Carlos Cortizas <97907068+CarlosCortizasCT@users.noreply.github.com>

* Update packages/components/fields/localized-multiline-text-field/src/localized-multiline-text-field.visualroute.jsx

Co-authored-by: Carlos Cortizas <97907068+CarlosCortizasCT@users.noreply.github.com>

* Update packages/components/fields/localized-text-field/src/localized-text-field.visualroute.jsx

Co-authored-by: Carlos Cortizas <97907068+CarlosCortizasCT@users.noreply.github.com>

* Update .changeset/fair-cooks-press.md

Co-authored-by: Kacper Krzywiec <49066275+kark@users.noreply.github.com>

* fix: keep the hasWarning prop in select fields

* fix: update jsdoc of select fields components

* fix: undo all deleted hasWarning spec

* fix: fix time input border color precedence

---------

Co-authored-by: Carlos Cortizas <97907068+CarlosCortizasCT@users.noreply.github.com>
Co-authored-by: Kacper Krzywiec <49066275+kark@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 29, 2024
1 parent cb410cd commit d263f01
Show file tree
Hide file tree
Showing 106 changed files with 3,899 additions and 3,013 deletions.
26 changes: 26 additions & 0 deletions .changeset/fair-cooks-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
'@commercetools-uikit/localized-multiline-text-field': minor
'@commercetools-uikit/async-creatable-select-field': minor
'@commercetools-uikit/selectable-search-input': minor
'@commercetools-uikit/creatable-select-field': minor
'@commercetools-uikit/localized-text-field': minor
'@commercetools-uikit/multiline-text-field': minor
'@commercetools-uikit/search-select-field': minor
'@commercetools-uikit/async-select-field': minor
'@commercetools-uikit/date-range-field': minor
'@commercetools-uikit/date-time-field': minor
'@commercetools-uikit/password-field': minor
'@commercetools-uikit/number-field': minor
'@commercetools-uikit/select-field': minor
'@commercetools-uikit/money-field': minor
'@commercetools-uikit/radio-field': minor
'@commercetools-uikit/collapsible-panel': minor
'@commercetools-uikit/date-field': minor
'@commercetools-uikit/text-field': minor
'@commercetools-uikit/time-field': minor
---

We've included a new property in all `*Field` components so consumers can not only render errors (below the input) but also warnings.
The main difference between them is the color used for the text.

Please take a look at the README files of the fields components to learn how to use this new property.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export default Example;
| `horizontalConstraint` | `union`<br/>Possible values:<br/>`, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 'scale', 'auto'` | | `'scale'` | Horizontal size limit of the input fields. |
| `errors` | `Record` | | | A map of errors. Error messages for known errors are rendered automatically.&#xA;<br />&#xA;Unknown errors will be forwarded to `renderError` |
| `renderError` | `Function`<br/>[See signature.](#signature-renderError) | | | Called with custom errors. This function can return a message which will be wrapped in an ErrorMessage. It can also return null to show no error. |
| `warnings` | `Record` | | | A map of warnings. Warning messages for known warnings are rendered automatically.&#xA;<br />&#xA;Unknown warnings will be forwarded to `renderWarning` |
| `renderWarning` | `Function`<br/>[See signature.](#signature-renderWarning) | | | Called with custom warnings. This function can return a message which will be wrapped in an WarningMessage. It can also return null to show no warning. |
| `isRequired` | `boolean` | | | Indicates if the value is required. Shows an the "required asterisk" if so. |
| `touched` | `union`<br/>Possible values:<br/>`boolean[] , boolean` | | | Indicates whether the field was touched. Errors will only be shown when the field was touched. |
| `aria-label` | `AsyncCreatableProps['aria-label']` | | | Aria label (for assistive tech)&#xA;<br>&#xA;[Props from React select was used](https://react-select.com/props) |
Expand All @@ -73,7 +75,7 @@ export default Example;
| `isOptionDisabled` | `AsyncCreatableProps['isOptionDisabled']` | | | Override the built-in logic to detect whether an option is disabled&#xA;<br>&#xA;[Props from React select was used](https://react-select.com/props) |
| `isMulti` | `AsyncCreatableProps['isMulti']` | | | Support multiple selected options&#xA;<br>&#xA;[Props from React select was used](https://react-select.com/props) |
| `isSearchable` | `AsyncCreatableProps['isSearchable']` | | | Whether to enable search functionality&#xA;<br>&#xA;[Props from React select was used](https://react-select.com/props) |
| `hasWarning` | `boolean` | | | Indicates the input field has a warning |
| `hasWarning` | `boolean` | | | Indicates the input field has a warning&#xA;@deprecated Please use the `warnings` prop instead so users know the reason why the field is in warning state. |
| `maxMenuHeight` | `AsyncCreatableProps['maxMenuHeight']` | | | Maximum height of the menu before scrolling&#xA;<br>&#xA;[Props from React select was used](https://react-select.com/props) |
| `menuPortalTarget` | `AsyncCreatableProps['menuPortalTarget']` | | | Dom element to portal the select menu to&#xA;<br>&#xA;[Props from React select was used](https://react-select.com/props) |
| `menuPortalZIndex` | `number` | | | z-index value for the menu portal&#xA;<br>&#xA;Use in conjunction with `menuPortalTarget` |
Expand Down Expand Up @@ -114,6 +116,12 @@ export default Example;
(key: string, error?: boolean) => ReactNode;
```

### Signature `renderWarning`

```ts
(key: string, warning?: boolean) => ReactNode;
```

### Signature `onBlur`

```ts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@commercetools-uikit/design-system": "17.0.1",
"@commercetools-uikit/field-errors": "17.0.1",
"@commercetools-uikit/field-label": "17.0.1",
"@commercetools-uikit/field-warnings": "17.0.1",
"@commercetools-uikit/spacings": "17.0.1",
"@commercetools-uikit/utils": "17.0.1",
"@emotion/react": "^11.10.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,16 @@ describe('when field is touched and has errors', () => {
});
});
});

describe('when field is touched and has warnings', () => {
describe('when there is a custom warning', () => {
it('should render the custom warning message', async () => {
const { findByText } = renderAsyncCreatableSelectField({
touched: true,
warnings: { customWarning: true },
renderWarning: () => 'Custom warning',
});
expect(await findByText('Custom warning')).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,17 @@ storiesOf('Components|Fields/SelectFields', module)
return null;
}
}}
warnings={object('warnings', {
customWarning: true,
})}
renderWarning={(key) => {
switch (key) {
case 'customWarning':
return 'A custom warning.';
default:
return null;
}
}}
isRequired={boolean('isRequired', false)}
touched={boolean('touched', false)}
aria-label={text('aria-label', '')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Spacings from '@commercetools-uikit/spacings';
import FieldLabel from '@commercetools-uikit/field-label';
import AsyncCreatableSelectInput from '@commercetools-uikit/async-creatable-select-input';
import FieldErrors from '@commercetools-uikit/field-errors';
import FieldWarnings from '@commercetools-uikit/field-warnings';

type ReactSelectAsyncCreatableProps = AsyncCreatableProps<
unknown,
Expand All @@ -26,6 +27,7 @@ type ReactSelectAsyncCreatableProps = AsyncCreatableProps<

type TErrorRenderer = (key: string, error?: boolean) => ReactNode;
type TFieldErrors = Record<string, boolean>;
type TFieldWarnings = Record<string, boolean>;
// Similar shape of `FormikErrors` but values are `TFieldErrors` objects.
type TCustomFormErrors<Values> = {
[K in keyof Values]?: TFieldErrors;
Expand All @@ -35,10 +37,16 @@ const sequentialId = createSequentialId('async-creatable-select-field-');
const sequentialErrorsId = createSequentialId(
'async-creatable-select-field-error-'
)();
const sequentialWarningsId = createSequentialId(
'async-creatable-select-field-warning-'
)();

const hasErrors = (errors?: TFieldErrors) =>
errors && Object.values(errors).some(Boolean);

const hasWarnings = (warnings?: TFieldWarnings) =>
warnings && Object.values(warnings).some(Boolean);

type TCustomEvent = {
target: {
id?: string;
Expand Down Expand Up @@ -86,6 +94,16 @@ export type TAsyncCreatableSelectFieldProps = {
* Called with custom errors. This function can return a message which will be wrapped in an ErrorMessage. It can also return null to show no error.
*/
renderError?: TErrorRenderer;
/**
* A map of warnings. Warning messages for known warnings are rendered automatically.
* <br />
* Unknown warnings will be forwarded to `renderWarning`
*/
warnings?: TFieldWarnings;
/**
* Called with custom warnings. This function can return a message which will be wrapped in an WarningMessage. It can also return null to show no warning.
*/
renderWarning?: (key: string, warning?: boolean) => ReactNode;
/**
* Indicates if the value is required. Shows an the "required asterisk" if so.
*/
Expand Down Expand Up @@ -171,6 +189,7 @@ export type TAsyncCreatableSelectFieldProps = {
isSearchable?: ReactSelectAsyncCreatableProps['isSearchable'];
/**
* Indicates the input field has a warning
* @deprecated Please use the `warnings` prop instead so users know the reason why the field is in warning state.
*/
hasWarning?: boolean;
/**
Expand Down Expand Up @@ -408,6 +427,11 @@ export default class AsyncCreatableSelectField extends Component<
AsyncCreatableSelectInput.isTouched(this.props.touched) &&
hasErrors(this.props.errors);

const hasWarning =
this.props.hasWarning ||
(AsyncCreatableSelectInput.isTouched(this.props.touched) &&
hasWarnings(this.props.warnings));

if (!this.props.isReadOnly) {
warning(
typeof this.props.onChange === 'function',
Expand Down Expand Up @@ -467,7 +491,7 @@ export default class AsyncCreatableSelectField extends Component<
isOptionDisabled={this.props.isOptionDisabled}
isMulti={this.props.isMulti}
isSearchable={this.props.isSearchable}
hasWarning={this.props.hasWarning}
hasWarning={hasWarning}
maxMenuHeight={this.props.maxMenuHeight}
menuPortalTarget={this.props.menuPortalTarget}
menuPortalZIndex={this.props.menuPortalZIndex}
Expand Down Expand Up @@ -503,6 +527,12 @@ export default class AsyncCreatableSelectField extends Component<
isVisible={hasError}
renderError={this.props.renderError}
/>
<FieldWarnings
id={sequentialWarningsId}
warnings={this.props.warnings}
isVisible={hasWarning}
renderWarning={this.props.renderWarning}
/>
</Spacings.Stack>
</Constraints.Horizontal>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,29 @@ const DefaultRoute = () => (
hasWarning={true}
/>
</Spec>
<Spec label="with warning when not touched">
<AsyncCreatableSelectField
title="State"
value={value}
onChange={() => {}}
loadOptions={loadOptions}
horizontalConstraint={7}
warnings={{ customWarning: true }}
renderWarning={() => 'Custom warning'}
/>
</Spec>
<Spec label="with warning when touched">
<AsyncCreatableSelectField
title="State"
value={value}
onChange={() => {}}
loadOptions={loadOptions}
horizontalConstraint={7}
warnings={{ customWarning: true }}
touched={true}
renderWarning={() => 'Custom warning'}
/>
</Spec>
</Suite>
);

Expand Down
Loading

1 comment on commit d263f01

@vercel
Copy link

@vercel vercel bot commented on d263f01 Jan 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.