diff options
Diffstat (limited to 'src/components/atoms/forms')
| -rw-r--r-- | src/components/atoms/forms/boolean-field.module.scss | 5 | ||||
| -rw-r--r-- | src/components/atoms/forms/boolean-field.stories.tsx | 175 | ||||
| -rw-r--r-- | src/components/atoms/forms/boolean-field.test.tsx | 60 | ||||
| -rw-r--r-- | src/components/atoms/forms/boolean-field.tsx | 62 | ||||
| -rw-r--r-- | src/components/atoms/forms/checkbox.stories.tsx | 102 | ||||
| -rw-r--r-- | src/components/atoms/forms/checkbox.test.tsx | 28 | ||||
| -rw-r--r-- | src/components/atoms/forms/checkbox.tsx | 46 |
7 files changed, 302 insertions, 176 deletions
diff --git a/src/components/atoms/forms/boolean-field.module.scss b/src/components/atoms/forms/boolean-field.module.scss new file mode 100644 index 0000000..3f0676e --- /dev/null +++ b/src/components/atoms/forms/boolean-field.module.scss @@ -0,0 +1,5 @@ +@use "@styles/abstracts/mixins" as mix; + +.hidden { + @include mix.visually-hidden; +} diff --git a/src/components/atoms/forms/boolean-field.stories.tsx b/src/components/atoms/forms/boolean-field.stories.tsx new file mode 100644 index 0000000..8b6136b --- /dev/null +++ b/src/components/atoms/forms/boolean-field.stories.tsx @@ -0,0 +1,175 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { useState } from 'react'; +import BooleanFieldComponent from './boolean-field'; + +/** + * BooleanField - Storybook Meta + */ +export default { + title: 'Atoms/Forms', + component: BooleanFieldComponent, + args: { + hidden: false, + }, + argTypes: { + 'aria-labelledby': { + control: { + type: 'text', + }, + description: 'One or more ids that refers to the field name.', + table: { + category: 'Accessibility', + }, + type: { + name: 'string', + required: false, + }, + }, + checked: { + control: { + type: null, + }, + description: 'The field state: true if checked.', + type: { + name: 'boolean', + required: true, + }, + }, + className: { + control: { + type: 'text', + }, + description: 'Set additional classnames to the field.', + table: { + category: 'Styles', + }, + type: { + name: 'string', + required: false, + }, + }, + hidden: { + control: { + type: 'boolean', + }, + description: 'Define if the field should be visually hidden.', + table: { + category: 'Options', + defaultValue: { summary: false }, + }, + type: { + name: 'boolean', + required: false, + }, + }, + id: { + control: { + type: 'text', + }, + description: 'The field id.', + type: { + name: 'string', + required: true, + }, + }, + name: { + control: { + type: 'text', + }, + description: 'The field name.', + type: { + name: 'string', + required: true, + }, + }, + onChange: { + control: { + type: null, + }, + description: 'A callback function to handle field state change.', + table: { + category: 'Events', + }, + type: { + name: 'function', + required: true, + }, + }, + onClick: { + control: { + type: null, + }, + description: 'A callback function to handle click on field.', + table: { + category: 'Events', + }, + type: { + name: 'function', + required: false, + }, + }, + type: { + control: { + type: 'select', + }, + description: 'The field type. Either checkbox or radio.', + options: ['checkbox', 'radio'], + type: { + name: 'string', + required: true, + }, + }, + value: { + control: { + type: 'text', + }, + description: 'The field value.', + type: { + name: 'string', + required: true, + }, + }, + }, +} as ComponentMeta<typeof BooleanFieldComponent>; + +const Template: ComponentStory<typeof BooleanFieldComponent> = ({ + checked, + onChange: _onChange, + ...args +}) => { + const [isChecked, setIsChecked] = useState<boolean>(checked); + + return ( + <BooleanFieldComponent + checked={isChecked} + onChange={() => { + setIsChecked(!isChecked); + }} + {...args} + /> + ); +}; + +/** + * Checkbox Story + */ +export const Checkbox = Template.bind({}); +Checkbox.args = { + id: 'checkbox', + checked: false, + name: 'checkbox', + type: 'checkbox', + value: 'checkbox', +}; + +/** + * Radio Story + */ +export const Radio = Template.bind({}); +Radio.args = { + id: 'radio', + checked: false, + name: 'radio', + type: 'radio', + value: 'radio', +}; diff --git a/src/components/atoms/forms/boolean-field.test.tsx b/src/components/atoms/forms/boolean-field.test.tsx new file mode 100644 index 0000000..95ec4b1 --- /dev/null +++ b/src/components/atoms/forms/boolean-field.test.tsx @@ -0,0 +1,60 @@ +import { render, screen } from '@test-utils'; +import BooleanField from './boolean-field'; + +describe('BooleanField', () => { + it('renders an unchecked checkbox', () => { + render( + <BooleanField + checked={false} + id="jest-checkbox" + name="jest-checkbox" + onChange={() => null} + type="checkbox" + value="checkbox" + /> + ); + expect(screen.getByRole('checkbox')).not.toBeChecked(); + }); + + it('renders a checked checkbox', () => { + render( + <BooleanField + checked={true} + id="jest-checkbox" + name="jest-checkbox" + onChange={() => null} + type="checkbox" + value="checkbox" + /> + ); + expect(screen.getByRole('checkbox')).toBeChecked(); + }); + + it('renders an unchecked radio', () => { + render( + <BooleanField + checked={false} + id="jest-radio" + name="jest-radio" + onChange={() => null} + type="radio" + value="radio" + /> + ); + expect(screen.getByRole('radio')).not.toBeChecked(); + }); + + it('renders a checked radio', () => { + render( + <BooleanField + checked={true} + id="jest-radio" + name="jest-radio" + onChange={() => null} + type="radio" + value="radio" + /> + ); + expect(screen.getByRole('radio')).toBeChecked(); + }); +}); diff --git a/src/components/atoms/forms/boolean-field.tsx b/src/components/atoms/forms/boolean-field.tsx new file mode 100644 index 0000000..946e375 --- /dev/null +++ b/src/components/atoms/forms/boolean-field.tsx @@ -0,0 +1,62 @@ +import { ChangeEventHandler, FC, MouseEventHandler } from 'react'; +import styles from './boolean-field.module.scss'; + +export type BooleanFieldProps = { + /** + * One or more ids that refers to the checkbox name. + */ + 'aria-labelledby'?: string; + /** + * True if the field should be checked. + */ + checked: boolean; + /** + * Add classnames to the checkbox. + */ + className?: string; + /** + * Field id attribute. + */ + id: string; + /** + * True if the field should be visually hidden. Default: false. + */ + hidden?: boolean; + /** + * Field name attribute. + */ + name: string; + /** + * Callback function to handle state change. + */ + onChange: ChangeEventHandler<HTMLInputElement>; + /** + * A callback function to handle click. + */ + onClick?: MouseEventHandler<HTMLInputElement>; + /** + * The input type. + */ + type: 'checkbox' | 'radio'; + /** + * Field name attribute. + */ + value: string; +}; + +/** + * BooleanField component + * + * Render a checkbox or a radio input type. + */ +const BooleanField: FC<BooleanFieldProps> = ({ + className = '', + hidden = false, + ...props +}) => { + const modifier = hidden ? 'hidden' : ''; + + return <input className={`${styles[modifier]} ${className}`} {...props} />; +}; + +export default BooleanField; diff --git a/src/components/atoms/forms/checkbox.stories.tsx b/src/components/atoms/forms/checkbox.stories.tsx deleted file mode 100644 index 588fdcc..0000000 --- a/src/components/atoms/forms/checkbox.stories.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { useState } from 'react'; -import CheckboxComponent from './checkbox'; - -/** - * Checkbox - Storybook Meta - */ -export default { - title: 'Atoms/Forms', - component: CheckboxComponent, - argTypes: { - 'aria-labelledby': { - control: { - type: 'text', - }, - description: 'One or more ids that refers to the checkbox name.', - table: { - category: 'Accessibility', - }, - type: { - name: 'string', - required: false, - }, - }, - className: { - control: { - type: 'text', - }, - description: 'Set additional classnames to the checkbox.', - table: { - category: 'Styles', - }, - type: { - name: 'string', - required: false, - }, - }, - id: { - control: { - type: 'text', - }, - description: 'The checkbox id.', - type: { - name: 'string', - required: true, - }, - }, - name: { - control: { - type: 'text', - }, - description: 'The checkbox name.', - type: { - name: 'string', - required: true, - }, - }, - setValue: { - control: { - type: null, - }, - description: 'A callback function to handle checkbox state.', - type: { - name: 'function', - required: true, - }, - }, - value: { - control: { - type: null, - }, - description: - 'The checkbox state: either checked (true) or unchecked (false).', - type: { - name: 'boolean', - required: true, - }, - }, - }, -} as ComponentMeta<typeof CheckboxComponent>; - -const Template: ComponentStory<typeof CheckboxComponent> = ({ - value, - setValue: _setValue, - ...args -}) => { - const [isChecked, setIsChecked] = useState<boolean>(value); - - return ( - <CheckboxComponent value={isChecked} setValue={setIsChecked} {...args} /> - ); -}; - -/** - * Checkbox Story - */ -export const Checkbox = Template.bind({}); -Checkbox.args = { - id: 'storybook-checkbox', - name: 'storybook-checkbox', - value: false, -}; diff --git a/src/components/atoms/forms/checkbox.test.tsx b/src/components/atoms/forms/checkbox.test.tsx deleted file mode 100644 index 3b54549..0000000 --- a/src/components/atoms/forms/checkbox.test.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { render, screen } from '@test-utils'; -import Checkbox from './checkbox'; - -describe('Checkbox', () => { - it('renders an unchecked checkbox', () => { - render( - <Checkbox - id="jest-checkbox" - name="jest-checkbox" - value={false} - setValue={() => null} - /> - ); - expect(screen.getByRole('checkbox')).not.toBeChecked(); - }); - - it('renders a checked checkbox', () => { - render( - <Checkbox - id="jest-checkbox" - name="jest-checkbox" - value={true} - setValue={() => null} - /> - ); - expect(screen.getByRole('checkbox')).toBeChecked(); - }); -}); diff --git a/src/components/atoms/forms/checkbox.tsx b/src/components/atoms/forms/checkbox.tsx deleted file mode 100644 index aec97f0..0000000 --- a/src/components/atoms/forms/checkbox.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { FC, SetStateAction } from 'react'; - -export type CheckboxProps = { - /** - * One or more ids that refers to the checkbox name. - */ - 'aria-labelledby'?: string; - /** - * Add classnames to the checkbox. - */ - className?: string; - /** - * Checkbox id attribute. - */ - id: string; - /** - * Checkbox name attribute. - */ - name: string; - /** - * Callback function to set checkbox value. - */ - setValue: (value: SetStateAction<boolean>) => void; - /** - * Checkbox value. - */ - value: boolean; -}; - -/** - * Checkbox component - * - * Render a checkbox type input. - */ -const Checkbox: FC<CheckboxProps> = ({ value, setValue, ...props }) => { - return ( - <input - type="checkbox" - checked={value} - onChange={() => setValue(!value)} - {...props} - /> - ); -}; - -export default Checkbox; |
