aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-04-04 18:46:05 +0200
committerArmand Philippot <git@armandphilippot.com>2022-04-04 18:46:05 +0200
commite8bac61a7f0be6c60624b00e06ab8d00efc932f8 (patch)
tree7b8920512e79edb006f3ff85c290f5ef0a9b1c3b
parent8a4fbf91b0ffdcb0ec38105f918ce6f90e6ec161 (diff)
chore: add a PlusMinus icon component
-rw-r--r--src/components/atoms/icons/plus-minus.module.scss39
-rw-r--r--src/components/atoms/icons/plus-minus.stories.tsx73
-rw-r--r--src/components/atoms/icons/plus-minus.test.tsx16
-rw-r--r--src/components/atoms/icons/plus-minus.tsx45
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;