Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RAC-225: Add Checkbox component Co-authored-by: StevenVAIDIE <StevenVAIDIE@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: StevenVAIDIE <StevenVAIDIE@users.noreply.github.com>
- Loading branch information
1 parent
c65634b
commit 29ec1b5
Showing
26 changed files
with
650 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,17 @@ | ||
import React from 'react'; | ||
import {addDecorator} from '@storybook/react'; | ||
import {addDecorator, addParameters} from '@storybook/react'; | ||
import { withThemesProvider } from "themeprovider-storybook"; | ||
import {StoryStyle} from '../src/shared/global'; | ||
import {pimTheme} from '../src/theme/pim'; | ||
|
||
addDecorator(story => ( | ||
<> | ||
<StoryStyle>{story()}</StoryStyle> | ||
</> | ||
)); | ||
|
||
addDecorator(withThemesProvider([pimTheme])) | ||
|
||
addParameters({ | ||
viewMode: 'docs', | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
akeneo-design-system/src/components/Checkbox/Checkbox.stories.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { useState } from 'react'; | ||
import { Meta, Story, ArgsTable, Canvas } from '@storybook/addon-docs/blocks'; | ||
import { action } from "@storybook/addon-actions"; | ||
import { Checkbox } from "./Checkbox.tsx"; | ||
|
||
<Meta | ||
title="Components/Checkbox" | ||
component={Checkbox} | ||
argTypes={{ | ||
readOnly: {control: {type: 'boolean'}}, | ||
checked: {control: {type: 'boolean'}}, | ||
label: {control: {type: 'text'}}, | ||
onChange: {action: 'Checkbox component onChange'}, | ||
}} | ||
args={{ | ||
label: 'Checkbox' | ||
}} | ||
/> | ||
|
||
# Checkbox | ||
|
||
## Usage | ||
The checkboxes are applied when users can select all, several, or none of the options from a given list. | ||
|
||
### Checkbox states | ||
The checkbox control allows three states: selected, unselected, and undetermined. The undetermined state comes into play when the checkbox contains a sublist of selections, some of which are selected, and others aren't. | ||
|
||
Users must be able to check the box by clicking directly on the box or by clicking on its label. | ||
|
||
### Content | ||
#### Title | ||
|
||
If necessary, a header can accompany a set of checkboxes to provide more context or clarity. | ||
|
||
#### Labels | ||
|
||
Always use clear and concise labels for the checkboxes. The labels appears on the right of the checkboxes. | ||
|
||
## Playground | ||
|
||
Use this playground to test the checkbox component | ||
|
||
<Canvas> | ||
<Story name="Standard"> | ||
{(args) => { | ||
return <Checkbox {...args}/>; | ||
}} | ||
</Story> | ||
</Canvas> | ||
|
||
<ArgsTable story="Standard" /> | ||
|
||
## Variation on state | ||
<Story name="State"> | ||
{(args) => { | ||
return ( | ||
<> | ||
<Checkbox {...args} checked={true} label={'Checkbox checked'}/> | ||
<Checkbox {...args} checked={false} undetermined={true} label={'Checkbox undetermined'}/> | ||
<Checkbox {...args} checked={false} label={'Checkbox unchecked'}/> | ||
</> | ||
) | ||
}} | ||
</Story> | ||
|
||
## Variation on disabled | ||
<Story name="Disabled"> | ||
{(args) => { | ||
return ( | ||
<> | ||
<Checkbox {...args} readOnly={true} checked={true} label={'Checked disabled'}/> | ||
<Checkbox {...args} readOnly={true} checked={false} undetermined={true} label={'Undetermined disabled'}/> | ||
<Checkbox {...args} readOnly={true} checked={false} label={'Unchecked disabled'}/> | ||
</> | ||
) | ||
}} | ||
</Story> | ||
|
||
## Animation | ||
<Story name="Animation"> | ||
{(args) => { | ||
const [checked, setChecked] = useState(true); | ||
return ( | ||
<Checkbox {...args} checked={checked} onChange={(newCheck) => setChecked(newCheck)}/> | ||
) | ||
}} | ||
</Story> |
131 changes: 131 additions & 0 deletions
131
akeneo-design-system/src/components/Checkbox/Checkbox.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import React from 'react'; | ||
import styled, {css, keyframes} from 'styled-components'; | ||
import {AkeneoThemedProps, getColor} from '../../theme'; | ||
import {CheckIcon, PartialCheckIcon} from '../../icons'; | ||
|
||
const checkTick = keyframes` | ||
to { | ||
stroke-dashoffset: 0; | ||
} | ||
`; | ||
|
||
const uncheckTick = keyframes` | ||
to { | ||
stroke-dashoffset: 20px; | ||
} | ||
`; | ||
|
||
const Container = styled.div` | ||
display: flex; | ||
`; | ||
|
||
const TickIcon = styled(CheckIcon)` | ||
animation: ${uncheckTick} 0.2s ease-in forwards; | ||
opacity: 0; | ||
stroke-dasharray: 0px; | ||
stroke-dashoffset: 0; | ||
transition-delay: 0.2s; | ||
transition: opacity 0.1s ease-out; | ||
`; | ||
|
||
const CheckboxContainer = styled.div<{checked: boolean; readOnly: boolean} & AkeneoThemedProps>` | ||
background-color: transparent; | ||
height: 20px; | ||
width: 20px; | ||
border: 1px solid ${getColor('grey80')}; | ||
border-radius: 3px; | ||
outline: none; | ||
background-color: ${getColor('grey20')}; | ||
${(props) => | ||
props.checked && | ||
css` | ||
background-color: ${getColor('blue100')}; | ||
${TickIcon} { | ||
animation-delay: 0.2s; | ||
animation: ${checkTick} 0.2s ease-out forwards; | ||
stroke-dashoffset: 20px; | ||
opacity: 1; | ||
transition-delay: 0s; | ||
} | ||
`} | ||
${(props) => | ||
props.checked && | ||
props.readOnly && | ||
css` | ||
background-color: ${getColor('blue20')}; | ||
border-color: ${getColor('blue40')}; | ||
`} | ||
${(props) => | ||
!props.checked && | ||
props.readOnly && | ||
css` | ||
background-color: ${getColor('grey60')}; | ||
border-color: ${getColor('grey100')}; | ||
`} | ||
`; | ||
|
||
const LabelContainer = styled.div<{readOnly: boolean} & AkeneoThemedProps>` | ||
color: ${getColor('grey140')}; | ||
font-weight: 400; | ||
font-size: 15px; | ||
padding-left: 10px; | ||
${(props) => | ||
props.readOnly && | ||
css` | ||
color: ${getColor('grey100')}; | ||
`} | ||
`; | ||
|
||
type CheckboxProps = { | ||
/** | ||
* State of the Checkbox | ||
*/ | ||
checked: boolean; | ||
|
||
/** | ||
* Displays the value of the input, but does not allow changes.s | ||
*/ | ||
readOnly?: boolean; | ||
|
||
/** | ||
* The undetermined state comes into play when the checkbox contains a sublist of selections, | ||
* some of which are selected, and others aren't. | ||
*/ | ||
undetermined?: boolean; | ||
|
||
/** | ||
* Provide a description of the Checkbox, the label appears on the right of the checkboxes. | ||
*/ | ||
label?: string; | ||
|
||
/** | ||
* The handler called when clicking on Checkbox | ||
*/ | ||
onChange?: (value: boolean) => void; | ||
}; | ||
|
||
/** | ||
* The checkboxes are applied when users can select all, several, or none of the options from a given list. | ||
*/ | ||
const Checkbox = ({label, checked, onChange, undetermined = false, readOnly = false}: CheckboxProps) => { | ||
if (undefined === onChange && false === readOnly) { | ||
throw new Error('A Checkbox element expect an onChange attribute if not readOnly'); | ||
} | ||
|
||
const handleChange = () => onChange && !readOnly && onChange(!checked); | ||
|
||
return ( | ||
<Container onClick={handleChange}> | ||
<CheckboxContainer checked={checked || undetermined} readOnly={readOnly}> | ||
{undetermined ? <PartialCheckIcon height={20} width={20} /> : <TickIcon height={20} width={20} />} | ||
</CheckboxContainer> | ||
{label ? <LabelContainer readOnly={readOnly}>{label}</LabelContainer> : null} | ||
</Container> | ||
); | ||
}; | ||
|
||
export {Checkbox}; |
33 changes: 33 additions & 0 deletions
33
akeneo-design-system/src/components/Checkbox/Checkbox.unit.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import React from 'react'; | ||
import {fireEvent, render} from '../../shared/test-util'; | ||
import {Checkbox} from './Checkbox'; | ||
|
||
it('it calls onChange handler when user clicks on checkbox', () => { | ||
const onChange = jest.fn(); | ||
const {getByText} = render(<Checkbox checked={true} onChange={onChange} label="Checkbox" />); | ||
|
||
const checkbox = getByText('Checkbox'); | ||
fireEvent.click(checkbox); | ||
|
||
expect(onChange).toBeCalledWith(false); | ||
}); | ||
|
||
it('it does not call onChange handler when read-only', () => { | ||
const onChange = jest.fn(); | ||
const {getByText} = render(<Checkbox checked={true} readOnly={true} onChange={onChange} label="Checkbox" />); | ||
|
||
const checkbox = getByText('Checkbox'); | ||
fireEvent.click(checkbox); | ||
|
||
expect(onChange).not.toBeCalled(); | ||
}); | ||
|
||
it('it cannot be instantiated without handler when not readonly', () => { | ||
jest.spyOn(console, 'error').mockImplementation(() => { | ||
// do nothing. | ||
}); | ||
|
||
expect(() => { | ||
render(<Checkbox checked={true} label="Checkbox" />); | ||
}).toThrow('A Checkbox element expect an onChange attribute if not readOnly'); | ||
}); |
37 changes: 37 additions & 0 deletions
37
akeneo-design-system/src/components/Checkbox/Checkbox.visual.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import 'expect-puppeteer'; | ||
|
||
import {toMatchImageSnapshot} from 'jest-image-snapshot'; | ||
|
||
expect.extend({toMatchImageSnapshot}); | ||
|
||
describe('Checkbox visual tests', () => { | ||
it('Renders standard checkbox component correctly', async () => { | ||
await page.goto('http://localhost:6006/iframe.html?id=components-checkbox--standard'); | ||
const root = await page.$('#root'); | ||
if (null === root) return; | ||
|
||
const image = await root.screenshot(); | ||
|
||
expect(image).toMatchImageSnapshot(); | ||
}); | ||
|
||
it('Renders checkbox component varying by state', async () => { | ||
await page.goto('http://localhost:6006/iframe.html?id=components-checkbox--state'); | ||
const root = await page.$('#root'); | ||
if (null === root) return; | ||
|
||
const image = await root.screenshot(); | ||
|
||
expect(image).toMatchImageSnapshot(); | ||
}); | ||
|
||
it('Renders checkbox component varying on disabled', async () => { | ||
await page.goto('http://localhost:6006/iframe.html?id=components-checkbox--disabled'); | ||
const root = await page.$('#root'); | ||
if (null === root) return; | ||
|
||
const image = await root.screenshot(); | ||
|
||
expect(image).toMatchImageSnapshot(); | ||
}); | ||
}); |
Binary file added
BIN
+6.89 KB
...sx-checkbox-visual-tests-renders-checkbox-component-varying-by-state-1-snap.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+5.96 KB
...checkbox-visual-tests-renders-checkbox-component-varying-on-disabled-1-snap.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+1.83 KB
...-checkbox-visual-tests-renders-standard-checkbox-component-correctly-1-snap.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.