Skip to content

Commit

Permalink
feat(Forms): add support for multiple info, warning and error message…
Browse files Browse the repository at this point in the history
…s given by an array (#4284)
  • Loading branch information
tujoworker authored Nov 15, 2024
1 parent 9ec7ab4 commit 78f2fe8
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,19 +153,26 @@ export const CreateComposedFieldComponent = () => {
>
{() => {
const MyComposedField = (props) => {
const birthYear = useFieldProps({
const {
id,
value,
hasError,
handleChange,
handleFocus,
handleBlur,
} = useFieldProps({
path: '/birthYear',
})

const handleBirthYearChange = React.useCallback(
(sliderData) => {
birthYear.handleChange(sliderData.value)
handleChange(sliderData.value)
},
[birthYear],
[handleChange],
)

return (
<FieldBlock label={props.label ?? 'Name and age'}>
<FieldBlock id={id} label={props.label ?? 'Name and age'}>
<Flex.Horizontal>
<Field.Name.First
path="/firstName"
Expand All @@ -184,11 +191,11 @@ export const CreateComposedFieldComponent = () => {
step={1}
label="Birth year"
label_direction="vertical"
value={parseFloat(String(birthYear.value))}
value={parseFloat(String(value))}
on_change={handleBirthYearChange}
on_drag_start={birthYear.handleFocus}
on_drag_end={birthYear.handleBlur}
status={birthYear.error?.message}
on_drag_start={handleFocus}
on_drag_end={handleBlur}
status={hasError}
tooltip
/>
</FieldBlock>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ export const WithStatus = () => {
width="small"
warning="Aliqua eu aute id qui esse aliqua dolor in aute magna commodo anim enim et. Velit incididunt exercitation est magna ex irure dolore nisi eiusmod ea exercitation."
/>
<Field.String
label="Label text"
error={[
new Error('Error message A'),
new Error('Error message B'),
]}
warning={['Warning message A', 'Warning message B']}
info={['Info message A', 'Info message B']}
/>
</Card>
</ComponentBox>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { Checkbox, HelpButton, ToggleButton } from '../../../../components'
import classnames from 'classnames'
import FieldBlock, { Props as FieldBlockProps } from '../../FieldBlock'
import { useFieldProps } from '../../hooks'
import { ReturnAdditional } from '../../hooks/useFieldProps'
import { checkForError, ReturnAdditional } from '../../hooks/useFieldProps'
import {
DefaultErrorMessages,
FieldHelpProps,
FieldProps,
Path,
} from '../../types'
import { pickSpacingProps } from '../../../../components/flex/utils'
import { getStatus, mapOptions, Data } from '../Selection'
import { mapOptions, Data } from '../Selection'
import { HelpButtonProps } from '../../../../components/HelpButton'
import ToggleButtonGroupContext from '../../../../components/toggle-button/ToggleButtonGroupContext'
import DataContext from '../../DataContext/Context'
Expand Down Expand Up @@ -209,7 +209,6 @@ export function useCheckboxOrToggleOptions({
}

const label = title ?? children
const status = getStatus(error, info, warning)
const suffix = help ? (
<HelpButton size="small" title={help.title}>
{help.content}
Expand Down Expand Up @@ -246,7 +245,9 @@ export function useCheckboxOrToggleOptions({
value={value}
disabled={disabled}
checked={value?.includes(active)}
status={(hasError || status) && 'error'}
status={
(hasError || checkForError([error, info, warning])) && 'error'
}
suffix={suffix}
on_change={handleSelect}
{...htmlAttributes}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '../../../../components'
import OptionField, { Props as OptionFieldProps } from '../Option'
import { useFieldProps } from '../../hooks'
import { ReturnAdditional } from '../../hooks/useFieldProps'
import { checkForError, ReturnAdditional } from '../../hooks/useFieldProps'
import { pickSpacingProps } from '../../../../components/flex/utils'
import FieldBlock, {
Props as FieldBlockProps,
Expand Down Expand Up @@ -222,7 +222,6 @@ function Selection(props: Props) {

case 'autocomplete':
case 'dropdown': {
const status = getStatus(error, info, warning)
const data = renderDropdownItems(dataList)
.concat(makeOptions(children))
.filter(Boolean)
Expand All @@ -236,7 +235,8 @@ function Selection(props: Props) {
portal_class: 'dnb-forms-field-selection__portal',
title: placeholder,
value: String(value ?? ''),
status: (hasError || status) && 'error',
status:
(hasError || checkForError([error, info, warning])) && 'error',
disabled,
...htmlAttributes,
data,
Expand Down Expand Up @@ -276,22 +276,6 @@ function Selection(props: Props) {
}
}

export function getStatus(
error: Error | FormError | undefined,
info: React.ReactNode,
warning: React.ReactNode
) {
return (
error?.message ??
((warning instanceof Error && warning.message) ||
(warning instanceof FormError && warning.message) ||
warning?.toString() ||
(info instanceof Error && info.message) ||
(info instanceof FormError && info.message) ||
info?.toString())
)
}

type OptionProps = React.ComponentProps<
React.FC<{
value?: Props['value']
Expand Down Expand Up @@ -335,7 +319,6 @@ function renderRadioItems({
const { value, title, children, error, help, ...rest } = props

const label = title ?? children
const status = getStatus(error, info, warning)
const suffix = help ? (
<HelpButton size="small" title={help.title}>
{help.content}
Expand All @@ -355,7 +338,9 @@ function renderRadioItems({
label={variant === 'radio' ? label : undefined}
text={variant === 'button' ? label : undefined}
value={String(value ?? valueProp ?? '')}
status={(hasError || status) && 'error'}
status={
(hasError || checkForError([error, info, warning])) && 'error'
}
suffix={suffix}
{...htmlAttributes}
{...rest}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1493,6 +1493,17 @@ describe('Field.String', () => {
expect(ids[0]).toHaveClass('dnb-form-status--info')
expect(ids[0]).toHaveTextContent('Info message')
})

it('should render array in ul with title', () => {
const firstInfo = 'Info message A'
const secondInfo = 'Info message B'

render(<Field.String info={[firstInfo, secondInfo]} />)

expect(document.querySelector('.dnb-form-status').textContent).toBe(
nb.Field.stateSummary + firstInfo + secondInfo
)
})
})

describe('warning prop', () => {
Expand All @@ -1508,6 +1519,17 @@ describe('Field.String', () => {
expect(ids[0]).toHaveClass('dnb-form-status--warn')
expect(ids[0]).toHaveTextContent('Warning message')
})

it('should render array in ul with title', () => {
const firstWarning = 'Warning message A'
const secondWarning = 'Warning message B'

render(<Field.String warning={[firstWarning, secondWarning]} />)

expect(screen.queryByRole('alert').textContent).toBe(
nb.Field.stateSummary + firstWarning + secondWarning
)
})
})

describe('error prop', () => {
Expand All @@ -1525,6 +1547,21 @@ describe('Field.String', () => {
expect(status).toHaveClass('dnb-form-status--error')
expect(status).toHaveTextContent('Error message')
})

it('should render array in ul with title', () => {
const firstError = 'Error message A'
const secondError = 'Error message B'

render(
<Field.String
error={[new Error(firstError), new Error(secondError)]}
/>
)

expect(screen.queryByRole('alert').textContent).toBe(
nb.Field.errorSummary + firstError + secondError
)
})
})

describe('useFieldProps and FieldBlock', () => {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ export const String = () => {

<Field.String label="Label" width="large" />
<Field.String label="Label" multiline width="large" />

<Field.String
label="Label"
error={[
new Error('Error message A'),
new Error('Error message B'),
]}
warning={['Warning message A', 'Warning message B']}
info={['Info message A', 'Info message B']}
/>
</Flex.Stack>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -679,10 +679,20 @@ export function getMessagesFromError(
})
}

if (Array.isArray(content)) {
return content.map((content) => {
return content instanceof FormError || content instanceof Error
? content.message
: content
})
}

if (content instanceof FormError || content instanceof Error) {
return [content.message as StateMessage]
}

return [
((content instanceof Error && content.message) ||
(content instanceof FormError && content.message) ||
(React.isValidElement(content) ? content : content?.toString()) ||
((React.isValidElement(content) ? content : content?.toString()) ||
content) as StateMessage,
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ export const DataValueWritePropsProperties: PropertiesTableProps = {
},
info: {
doc: 'Info message shown below / after the field.',
type: 'React.Node',
type: ['React.Node', 'Array<React.Node>'],
status: 'optional',
},
warning: {
doc: 'Warning message shown below / after the field.',
type: 'React.Node',
type: ['React.Node', 'Array<React.Node>'],
status: 'optional',
},
error: {
doc: 'Error message shown below / after the field.',
type: 'Error',
type: ['Error', 'FormError', 'Array<Error | FormError>'],
status: 'optional',
},
disabled: {
Expand Down
Loading

0 comments on commit 78f2fe8

Please sign in to comment.