diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/atoms/icons/plus-minus.module.scss | 39 | ||||
| -rw-r--r-- | src/components/atoms/icons/plus-minus.stories.tsx | 73 | ||||
| -rw-r--r-- | src/components/atoms/icons/plus-minus.test.tsx | 16 | ||||
| -rw-r--r-- | src/components/atoms/icons/plus-minus.tsx | 45 |
4 files changed, 173 insertions, 0 deletions
diff --git a/src/components/atoms/icons/plus-minus.module.scss b/src/components/atoms/icons/plus-minus.module.scss new file mode 100644 index 0000000..c54db33 --- /dev/null +++ b/src/components/atoms/icons/plus-minus.module.scss @@ -0,0 +1,39 @@ +@use "@styles/abstracts/functions" as fun; + +.icon { + display: flex; + place-content: center; + place-items: center; + width: var(--icon-size, #{fun.convert-px(30)}); + height: var(--icon-size, #{fun.convert-px(30)}); + position: relative; + background: var(--color-bg); + border: fun.convert-px(1) solid var(--color-primary); + border-radius: fun.convert-px(3); + color: var(--color-primary); + + &::before, + &::after { + content: ""; + position: absolute; + background: var(--color-primary); + transition: transform 0.4s ease-out 0s; + } + + &::after { + height: fun.convert-px(3); + width: 60%; + } + + &::before { + height: 60%; + width: fun.convert-px(3); + transform: scaleY(1); + } + + &--minus { + &::before { + transform: scaleY(0); + } + } +} diff --git a/src/components/atoms/icons/plus-minus.stories.tsx b/src/components/atoms/icons/plus-minus.stories.tsx new file mode 100644 index 0000000..1b5086a --- /dev/null +++ b/src/components/atoms/icons/plus-minus.stories.tsx @@ -0,0 +1,73 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import PlusMinusIcon from './plus-minus'; + +export default { + title: 'Atoms/Icons', + component: PlusMinusIcon, + args: { + ariaHidden: true, + }, + argTypes: { + additionalClasses: { + control: { + type: 'text', + }, + description: 'Set additional classes.', + table: { + category: 'Options', + }, + type: { + name: 'string', + required: false, + }, + }, + ariaHidden: { + control: { + type: 'boolean', + }, + description: 'Should be hidden for accessibility.', + table: { + category: 'Options', + defaultValue: { summary: true }, + }, + type: { + name: 'boolean', + required: false, + }, + }, + ariaLabel: { + control: { + type: 'text', + }, + description: 'An accessible name.', + table: { + category: 'Options', + }, + type: { + name: 'string', + required: false, + }, + }, + state: { + control: { + type: 'radio', + options: ['plus', 'minus'], + }, + description: 'Which state should be displayed.', + type: { + name: 'enum', + required: true, + value: ['plus', 'minus'], + }, + }, + }, +} as ComponentMeta<typeof PlusMinusIcon>; + +const Template: ComponentStory<typeof PlusMinusIcon> = (args) => ( + <PlusMinusIcon {...args} /> +); + +export const PlusMinus = Template.bind({}); +PlusMinus.args = { + state: 'plus', +}; diff --git a/src/components/atoms/icons/plus-minus.test.tsx b/src/components/atoms/icons/plus-minus.test.tsx new file mode 100644 index 0000000..96c2ad0 --- /dev/null +++ b/src/components/atoms/icons/plus-minus.test.tsx @@ -0,0 +1,16 @@ +import { render, screen } from '@test-utils'; +import PlusMinus from './plus-minus'; + +describe('PlusMinus', () => { + it('renders a plus icon', () => { + render(<PlusMinus state="plus" ariaHidden={false} ariaLabel="Plus icon" />); + expect(screen.getByLabelText('Plus icon')).toHaveClass('icon--plus'); + }); + + it('renders a minus icon', () => { + render( + <PlusMinus state="minus" ariaHidden={false} ariaLabel="Minus icon" /> + ); + expect(screen.getByLabelText('Minus icon')).toHaveClass('icon--minus'); + }); +}); diff --git a/src/components/atoms/icons/plus-minus.tsx b/src/components/atoms/icons/plus-minus.tsx new file mode 100644 index 0000000..1a6f7b0 --- /dev/null +++ b/src/components/atoms/icons/plus-minus.tsx @@ -0,0 +1,45 @@ +import { FC } from 'react'; +import styles from './plus-minus.module.scss'; + +type PlusMinusProps = { + /** + * Adds additional classes. + */ + additionalClasses?: string; + /** + * An accessible name. + */ + ariaLabel?: string; + /** + * Should be hidden for accessibility. Default: true. + */ + ariaHidden?: boolean; + /** + * Which state should be displayed. + */ + state: 'plus' | 'minus'; +}; + +/** + * PlusMinus component + * + * Render a plus or a minus icon. + */ +const PlusMinus: FC<PlusMinusProps> = ({ + additionalClasses, + ariaHidden = true, + ariaLabel, + state, +}) => { + const stateClass = `icon--${state}`; + + return ( + <div + className={`${styles.icon} ${styles[stateClass]} ${additionalClasses}`} + aria-label={ariaLabel} + aria-hidden={ariaHidden} + ></div> + ); +}; + +export default PlusMinus; |
