Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(forms): add help property to ArraySelection field #3694

Merged
merged 1 commit into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,18 @@ export const CheckboxError = () => (
</ComponentBox>
)

export const CheckboxWithHelp = () => (
<ComponentBox>
<Field.ArraySelection
label="Label text"
help={{ title: 'Help title', content: 'Help content' }}
>
<Field.Option value="foo" title="Foo!" />
<Field.Option value="bar" title="Baar!" />
</Field.ArraySelection>
</ComponentBox>
)

// Button

export const ButtonEmpty = () => (
Expand Down Expand Up @@ -318,3 +330,16 @@ export const ButtonError = () => (
</Field.ArraySelection>
</ComponentBox>
)

export const ButtonWithHelp = () => (
<ComponentBox>
<Field.ArraySelection
variant="button"
label="Label text"
help={{ title: 'Help title', content: 'Help content' }}
>
<Field.Option value="foo" title="Foo!" />
<Field.Option value="bar" title="Baar!" />
</Field.ArraySelection>
</ComponentBox>
)
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ import * as Examples from './Examples'

<Examples.CheckboxHorizontalLayoutAndHorizontalOptionsLayout />

#### Checkbox with help

<Examples.CheckboxWithHelp />

#### Checkbox disabled

<Examples.CheckboxDisabled />
Expand Down Expand Up @@ -78,6 +82,10 @@ import * as Examples from './Examples'

<Examples.ButtonHorizontalLayoutAndHorizontalOptionsLayout />

#### Button with help

<Examples.ButtonWithHelp />

#### Button disabled

<Examples.ButtonDisabled />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,15 @@ export const ButtonsError = () => {
</ComponentBox>
)
}

export const VariantButtonsWithHelp = () => {
return (
<ComponentBox data-visual-test="boolean-variant-buttons-with-help">
<Field.Boolean
variant="buttons"
label="Buttons variant"
help={{ title: 'Help title', content: 'Help content' }}
/>
</ComponentBox>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ import * as Examples from './Examples'

<Examples.ButtonsRequired />

#### Buttons - With Help

<Examples.VariantButtonsWithHelp />

#### Buttons - Disabled

<Examples.ButtonsDisabled />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,14 @@ This document provides a set of best practices to follow when creating forms for
</Iterate.Array>
</Wizard.Container>
```

{/* prettier-ignore */}
<div align="center" aria-hidden>
{`
   🕯🕯🕯
  🍓🍓🍓🍓🍓🍓
 🎂🎂🎂🎂🎂🎂🎂
 🎂🎂🎂🎂🎂🎂🎂
🍰🍰🍰🍰🍰🍰🍰🍰🍰
tujoworker marked this conversation as resolved.
Show resolved Hide resolved
`.split('\n').map((line, i) => (<div key={i}>{line}</div>))}
</div>
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { useMemo } from 'react'
import { Checkbox, ToggleButton } from '../../../../components'
import { Checkbox, HelpButton, ToggleButton } from '../../../../components'
import classnames from 'classnames'
import OptionField from '../Option'
import FieldBlock from '../../FieldBlock'
import { useFieldProps } from '../../hooks'
import { FieldProps } from '../../types'
import { FieldHelpProps, FieldProps } from '../../types'
import { pickSpacingProps } from '../../../../components/flex/utils'
import ToggleButtonGroupContext from '../../../../components/toggle-button/ToggleButtonGroupContext'

Expand All @@ -14,11 +14,12 @@ interface IOption {
handleSelect: () => void
}

export type Props = FieldProps<Array<string | number> | undefined> & {
children?: React.ReactNode
variant?: 'checkbox' | 'button'
optionsLayout?: 'horizontal' | 'vertical'
}
export type Props = FieldHelpProps &
FieldProps<Array<string | number> | undefined> & {
children?: React.ReactNode
variant?: 'checkbox' | 'button'
optionsLayout?: 'horizontal' | 'vertical'
}

function ArraySelection(props: Props) {
const {
Expand All @@ -32,6 +33,7 @@ function ArraySelection(props: Props) {
value,
error,
hasError,
help,
info,
warning,
disabled,
Expand All @@ -49,12 +51,26 @@ function ArraySelection(props: Props) {
className
),
contentClassName: 'dnb-forms-field-array-selection__options',
help,
info,
warning,
error,
layout,
label,
labelDescription,
labelDescription: (
<>
{labelDescription}
{help ? (
<HelpButton
size="small"
left={labelDescription ? 'x-small' : false}
title={help.title}
>
{help.content}
</HelpButton>
) : undefined}
</>
),
...pickSpacingProps(props),
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,95 +3,118 @@ import { render, fireEvent, screen } from '@testing-library/react'
import { Field, FieldBlock } from '../../..'

describe('ArraySelection', () => {
it('renders correctly', () => {
render(
<Field.ArraySelection>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

expect(screen.getByText('Option 1')).toBeInTheDocument()
expect(screen.getByText('Option 2')).toBeInTheDocument()
})
describe('variant: checkbox', () => {
it('renders correctly', () => {
render(
<Field.ArraySelection>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

it('handles selection correctly', () => {
const handleChange = jest.fn()
render(
<Field.ArraySelection onChange={handleChange}>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)
expect(screen.getByText('Option 1')).toBeInTheDocument()
expect(screen.getByText('Option 2')).toBeInTheDocument()
})

fireEvent.click(screen.getByText('Option 1'))
expect(handleChange).toHaveBeenCalledWith(['option1'])
it('renders help', () => {
render(
<Field.ArraySelection
help={{ title: 'Help title', content: 'Help content' }}
>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)
expect(document.querySelectorAll('.dnb-help-button')).toHaveLength(1)
expect(
document
.querySelector('.dnb-help-button')
.getAttribute('aria-describedby')
).toBe(document.querySelector('.dnb-tooltip__content').id)
})

fireEvent.click(screen.getByText('Option 2'))
expect(handleChange).toHaveBeenCalledWith(['option1', 'option2'])
it('handles selection correctly', () => {
const handleChange = jest.fn()
render(
<Field.ArraySelection onChange={handleChange}>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

fireEvent.click(screen.getByText('Option 1'))
expect(handleChange).toHaveBeenCalledWith(['option2'])
})
fireEvent.click(screen.getByText('Option 1'))
expect(handleChange).toHaveBeenCalledWith(['option1'])

it('handles emptyValue correctly', () => {
const handleChange = jest.fn()
render(
<Field.ArraySelection onChange={handleChange} emptyValue="empty">
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

fireEvent.click(screen.getByText('Option 1'))
fireEvent.click(screen.getByText('Option 1'))
expect(handleChange).toHaveBeenCalledWith('empty')
})
fireEvent.click(screen.getByText('Option 2'))
expect(handleChange).toHaveBeenCalledWith(['option1', 'option2'])

it('displays error message when error prop is provided', () => {
const errorMessage = new Error('This is what is wrong...')
render(
<Field.ArraySelection error={errorMessage}>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)
fireEvent.click(screen.getByText('Option 1'))
expect(handleChange).toHaveBeenCalledWith(['option2'])
})

const element = document.querySelector('.dnb-form-status')
it('handles emptyValue correctly', () => {
const handleChange = jest.fn()
render(
<Field.ArraySelection onChange={handleChange} emptyValue="empty">
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

expect(element).toBeInTheDocument()
expect(element).toHaveClass('dnb-form-status--error')
expect(element).toHaveTextContent('This is what is wrong...')
})
fireEvent.click(screen.getByText('Option 1'))
fireEvent.click(screen.getByText('Option 1'))
expect(handleChange).toHaveBeenCalledWith('empty')
})

it('applies the correct layout class when layout prop is provided', () => {
const layout = 'horizontal'
render(
<Field.ArraySelection layout={layout}>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

const element = document.querySelector('.dnb-forms-field-block__grid')
expect(element).toHaveClass(`dnb-forms-field-block--layout-${layout}`)
})
it('displays error message when error prop is provided', () => {
const errorMessage = new Error('This is what is wrong...')
render(
<Field.ArraySelection error={errorMessage}>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

const element = document.querySelector('.dnb-form-status')

expect(element).toBeInTheDocument()
expect(element).toHaveClass('dnb-form-status--error')
expect(element).toHaveTextContent('This is what is wrong...')
})

it('applies the correct layout class when layout prop is provided', () => {
const layout = 'horizontal'
render(
<Field.ArraySelection layout={layout}>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

it('applies the correct layout class when optionsLayout prop is provided', () => {
const optionsLayout = 'horizontal'
render(
<Field.ArraySelection optionsLayout={optionsLayout}>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

const element = document.querySelector(
'.dnb-forms-field-array-selection'
)
expect(element).toHaveClass(
`dnb-forms-field-array-selection--options-layout-${optionsLayout}`
)
const element = document.querySelector(
'.dnb-forms-field-block__grid'
)
expect(element).toHaveClass(
`dnb-forms-field-block--layout-${layout}`
)
})

it('applies the correct layout class when optionsLayout prop is provided', () => {
const optionsLayout = 'horizontal'
render(
<Field.ArraySelection optionsLayout={optionsLayout}>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)

const element = document.querySelector(
'.dnb-forms-field-array-selection'
)
expect(element).toHaveClass(
`dnb-forms-field-array-selection--options-layout-${optionsLayout}`
)
})
})

describe('checkbox variant', () => {
Expand All @@ -111,6 +134,24 @@ describe('ArraySelection', () => {
expect(option2).toBeInTheDocument()
})

it('renders help', () => {
render(
<Field.ArraySelection
variant="checkbox"
help={{ title: 'Help title', content: 'Help content' }}
>
<Field.Option value="option1">Option 1</Field.Option>
<Field.Option value="option2">Option 2</Field.Option>
</Field.ArraySelection>
)
expect(document.querySelectorAll('.dnb-help-button')).toHaveLength(1)
expect(
document
.querySelector('.dnb-help-button')
.getAttribute('aria-describedby')
).toBe(document.querySelector('.dnb-tooltip__content').id)
})

it('disables all options when disabled prop is true', () => {
render(
<Field.ArraySelection disabled>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ function Toggle(props: Props) {
<ToggleButton
text={textOff ?? translations.no}
value="off"
// suffix={suffix}
{...htmlAttributes}
/>
</ToggleButtonGroupContext.Provider>
Expand Down
Loading