Skip to content

Commit

Permalink
feat(Checkbox): add indeterminate state (#3515)
Browse files Browse the repository at this point in the history
Visual changed for checkbox indeterminate state
  • Loading branch information
AadneRo committed May 14, 2024
1 parent 9320841 commit d1ba274
Show file tree
Hide file tree
Showing 45 changed files with 738 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ export const CheckboxBoundingArea = () => (
</ShowBoundingArea>
)

export const CheckboxIndeterminate = () => (
<ComponentBox data-visual-test="checkbox-indeterminate">
<Checkbox label="Checkbox" indeterminate />
</ComponentBox>
)

export const CheckboxIndeterminateLarge = () => {
return (
<ComponentBox data-visual-test="checkbox-indeterminate-large">
<Checkbox label="Checkbox" indeterminate size="large" />
</ComponentBox>
)
}

const ShowBoundingArea = styled.div`
.dnb-checkbox__input {
opacity: 0.5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
CheckboxDisabled,
CheckboxWithErrorStates,
CheckboxBoundingArea,
CheckboxIndeterminate,
CheckboxIndeterminateLarge,
} from 'Docs/uilib/components/checkbox/Examples'

## Demos
Expand Down Expand Up @@ -41,6 +43,14 @@ As for now, there are two sizes. `medium` is the default size.

<CheckboxDisabled />

### Indeterminate state

The checkbox offers a fully controlled indeterminate state (partialy checked).

<CheckboxIndeterminate />

<CheckboxIndeterminateLarge />

<VisibleWhenVisualTest>
<CheckboxWithErrorStates />
<CheckboxBoundingArea />
Expand Down
3 changes: 1 addition & 2 deletions packages/dnb-eufemia/src/components/checkbox/CheckIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export type CheckIconProps = {
}

// The new checkbox has too low contrast, as it is too thin on web
function CheckIcon({ size, ...props }: CheckIconProps) {
function CheckIcon({ size }: CheckIconProps) {
let vB = 16
if (size === 'large') {
vB = 24
Expand All @@ -18,7 +18,6 @@ function CheckIcon({ size, ...props }: CheckIconProps) {
fill="none"
className="dnb-checkbox__gfx"
aria-hidden
{...props}
>
<path
d={size === 'large' ? 'M1.5 15L7.5 21L22.5 3' : 'M1 10L5 14L15 2'}
Expand Down
11 changes: 11 additions & 0 deletions packages/dnb-eufemia/src/components/checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ export type CheckboxProps = {
* Determine whether the checkbox is checked or not. The default is `false`.
*/
checked?: boolean | undefined | null
/**
* Determine whether to show the indeterminate checked state when checked. The default is `false`.
*/
indeterminate?: boolean
/**
* The size of the checkbox. For now there is "medium" (default) and "large".
*/
Expand Down Expand Up @@ -167,6 +171,7 @@ function Checkbox(localProps: CheckboxProps) {
skeleton,
className,
id: idProp,
indeterminate,
checked,
onChange,
innerRef,
Expand Down Expand Up @@ -195,6 +200,10 @@ function Checkbox(localProps: CheckboxProps) {
}
}, [checked, prevChecked])

useEffect(() => {
ref.current.indeterminate = indeterminate
}, [indeterminate])

const callOnChange: CheckboxProps['onChange'] = useCallback(
(args) => {
onChange?.(args)
Expand Down Expand Up @@ -316,6 +325,8 @@ function Checkbox(localProps: CheckboxProps) {
<span className="dnb-checkbox__focus" />
</span>

<span className="dnb-checkbox__indeterminate" />

<CheckIcon size={size} />
</span>
</span>
Expand Down
5 changes: 5 additions & 0 deletions packages/dnb-eufemia/src/components/checkbox/CheckboxDocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export const CheckboxProperties: PropertiesTableProps = {
type: ['string', 'number'],
status: 'optional',
},
indeterminate: {
doc: 'Controls the checkbox indeterminate (partial) state.',
type: 'boolean',
status: 'optional',
},
status: {
doc: 'Text with a status message. The style defaults to an error message. You can use `true` to only get the status color, without a message.',
type: 'string',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,20 @@ describe.each(['ui', 'sbanken'])('Checkbox for %s', (themeName) => {
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match checkbox in indeterminate state', async () => {
const screenshot = await makeScreenshot({
selector:
'[data-visual-test="checkbox-indeterminate"] .dnb-checkbox',
})
expect(screenshot).toMatchImageSnapshot()
})
it('have to match checkbox in indeterminate state with larger bounding area', async () => {
const screenshot = await makeScreenshot({
selector:
'[data-visual-test="checkbox-indeterminate-large"] .dnb-checkbox',
})
expect(screenshot).toMatchImageSnapshot()
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,48 @@ describe('Checkbox component', () => {
document.querySelector('.dnb-checkbox__input').getAttribute('type')
).toBe('checkbox')
})
describe('Indeterminate state', () => {
it('renders indeterminate state', () => {
render(<Checkbox indeterminate />)

expect(
document.querySelector('.dnb-checkbox__indeterminate')
).toBeInTheDocument()
})

it('changes to no longer indeterminate when clicking indeterminate state', () => {
const mockOnChange = jest.fn()
render(<Checkbox indeterminate onChange={mockOnChange} />)

screen.getByRole('checkbox').click()

expect(mockOnChange).toHaveBeenCalledWith(
expect.not.objectContaining({ indeterminate: true })
)

expect(screen.getByRole('checkbox')).not.toHaveClass(
'.dnb-checkbox__indeterminate'
)
})

it('sets the input indeterminate when setting indeterminate true', () => {
render(<Checkbox indeterminate />)

expect(
(screen.getByRole('checkbox') as HTMLInputElement).indeterminate
).toBe(true)
})

it('sets the input indeterminate to false when clicking an indeterminate checkbox', () => {
render(<Checkbox indeterminate />)

screen.getByRole('checkbox').click()

expect(
(screen.getByRole('checkbox') as HTMLInputElement).indeterminate
).toBe(false)
})
})
})

describe('Checkbox scss', () => {
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit d1ba274

Please sign in to comment.