Skip to content

Commit

Permalink
Add accordion ui component
Browse files Browse the repository at this point in the history
  • Loading branch information
evdmatvey committed Jul 15, 2024
1 parent 7892101 commit 74b1db7
Show file tree
Hide file tree
Showing 10 changed files with 393 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .storybook/index.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import url(../src/app/styles/variables.css);
@import url(../src/app/styles/globals.css);

* {
box-sizing: border-box;
Expand Down
1 change: 1 addition & 0 deletions src/shared/ui/Accordion/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ui/Accordion/Accordion';
9 changes: 9 additions & 0 deletions src/shared/ui/Accordion/model/accordion.context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createContext } from 'react';

export interface AccordionContext {
size?: 'large' | 'standard';
activeId?: number;
toggleAccordion?: (id: number) => void;
}

export const AccordionContext = createContext<AccordionContext>({});
9 changes: 9 additions & 0 deletions src/shared/ui/Accordion/model/useAccordionContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { useContext } from 'react';
import { AccordionContext } from './accordion.context';

export const useAccordionContext = () => {
const { activeId, toggleAccordion, size } =
useContext<AccordionContext>(AccordionContext);

return { activeId, toggleAccordion, size };
};
158 changes: 158 additions & 0 deletions src/shared/ui/Accordion/stories/Accordion.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import type { Meta, StoryObj } from '@storybook/react';
import HomeIcon from '@/shared/ui/Icons/ui/HomeIcon';
import Accordion from '../ui/Accordion/Accordion';

const meta: Meta<typeof Accordion> = {
component: Accordion,
title: 'Components/Accordion',
tags: ['autodocs'],
parameters: {
docs: {
subtitle:
'Accordion component that includes all cases in our design layout',
description: {
component:
'This component is an implemented compound component pattern. `Accordion` is the wrapper component, `Accordion.Item` - the component of the element',
},
},
},
argTypes: {
defaultActiveId: { control: 'number' },
size: { control: 'radio', options: ['standard', 'large'] },
},
};

export default meta;
type Story = StoryObj<typeof Accordion>;

export const Default: Story = {
name: 'Accordion',
args: {
defaultActiveId: 1,
size: 'standard',
},
parameters: {
docs: {
description: {
story:
'You should use the option that is specified in the design layout',
},
},
},
render: (args) => (
<div style={{ width: '500px', margin: '0 auto' }}>
<Accordion {...args}>
<Accordion.Item id={1} title="Lorem ipsum dolor.">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Iste,
provident accusantium, deleniti ratione minima repellat, sapiente
soluta earum expedita recusandae sunt enim deserunt velit itaque.
</Accordion.Item>
<Accordion.Item
id={2}
title="Lorem ipsum dolor sit amet consectetur adipisicing elit."
>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dolorum
dolorem, similique hic molestiae, non tenetur possimus doloribus neque
quibusdam at officia dignissimos pariatur nostrum. Assumenda minima
placeat quia quas quam!
</Accordion.Item>
<Accordion.Item id={3} title="Lorem ipsum dolor sit amet.">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Pariatur,
maxime.
</Accordion.Item>
</Accordion>
</div>
),
};

export const WithIcon: Story = {
name: 'Accordion with icon',
args: {
defaultActiveId: 1,
size: 'standard',
},
parameters: {
docs: {
description: {
story: 'You can see what the Accordion component looks like with icon',
},
},
},
render: (args) => (
<div style={{ width: '500px', margin: '0 auto' }}>
<Accordion {...args}>
<Accordion.Item id={1} title="Lorem ipsum dolor.">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Iste,
provident accusantium, deleniti ratione minima repellat, sapiente
soluta earum expedita recusandae sunt enim deserunt velit itaque.
</Accordion.Item>
<Accordion.Item
icon={<HomeIcon />}
id={2}
title="Lorem ipsum dolor sit amet consectetur adipisicing elit."
>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dolorum
dolorem, similique hic molestiae, non tenetur possimus doloribus neque
quibusdam at officia dignissimos pariatur nostrum. Assumenda minima
placeat quia quas quam!
</Accordion.Item>
<Accordion.Item
icon={<HomeIcon />}
id={3}
title="Lorem ipsum dolor sit amet."
>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Pariatur,
maxime.
</Accordion.Item>
</Accordion>
</div>
),
};

export const DarkMode: Story = {
name: 'Accordion on dark mode',
args: {
defaultActiveId: 1,
size: 'standard',
},
parameters: {
docs: {
description: {
story:
'You can see what the Accordion component looks like with dark mode',
},
},
backgrounds: {
default: 'dark',
},
},
render: (args) => (
<div data-theme="dark" style={{ width: '500px', margin: '0 auto' }}>
<Accordion {...args}>
<Accordion.Item id={1} title="Lorem ipsum dolor.">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Iste,
provident accusantium, deleniti ratione minima repellat, sapiente
soluta earum expedita recusandae sunt enim deserunt velit itaque.
</Accordion.Item>
<Accordion.Item
icon={<HomeIcon />}
id={2}
title="Lorem ipsum dolor sit amet consectetur adipisicing elit."
>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dolorum
dolorem, similique hic molestiae, non tenetur possimus doloribus neque
quibusdam at officia dignissimos pariatur nostrum. Assumenda minima
placeat quia quas quam!
</Accordion.Item>
<Accordion.Item
icon={<HomeIcon />}
id={3}
title="Lorem ipsum dolor sit amet."
>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Pariatur,
maxime.
</Accordion.Item>
</Accordion>
</div>
),
};
5 changes: 5 additions & 0 deletions src/shared/ui/Accordion/ui/Accordion/Accordion.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.root {
display: flex;
flex-direction: column;
gap: 20px;
}
32 changes: 32 additions & 0 deletions src/shared/ui/Accordion/ui/Accordion/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { type FC, type ReactNode, useState } from 'react';
import { AccordionContext } from '../../model/accordion.context';
import AccordionItem, {
AccordionItemProps,
} from '../AccordionItem/AccordionItem';
import styles from './Accordion.module.css';

interface AccordionProps {
children: ReactNode;
defaultActiveId: number;
size: 'standard' | 'large';
}

const Accordion: FC<AccordionProps> & { Item: FC<AccordionItemProps> } = ({
size = 'standard',
defaultActiveId = 1,
children,
}) => {
const [activeId, setActiveId] = useState(defaultActiveId);

const toggleAccordion = (id: number) => setActiveId(id);

return (
<AccordionContext.Provider value={{ activeId, toggleAccordion, size }}>
<div className={styles.root}>{children}</div>
</AccordionContext.Provider>
);
};

Accordion.Item = AccordionItem;

export default Accordion;
123 changes: 123 additions & 0 deletions src/shared/ui/Accordion/ui/AccordionItem/AccordionItem.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
.root {
padding-bottom: 20px;
display: flex;
flex-direction: column;
gap: 16px;
border-bottom: 1px solid var(--gray-200);
}

[data-theme='dark'] .root {
border-bottom-color: var(--gray-700);
}

.header {
display: flex;
align-items: center;
gap: 16px;
color: var(--gray-900);
cursor: pointer;
}

[data-theme='dark'] .header {
color: var(--white-100);
}

.header svg path {
fill: var(--gray-900);
}

[data-theme='dark'] .header svg path {
fill: var(--white-100);
}

.header .title {
flex-grow: 1;
}

.header h3 {
display: inline-block;
border-bottom: 2px solid transparent;
transition: all 0.15s ease-in;
}

.title {
display: flex;
align-items: center;
gap: 12px;
}

.root.standard .title span {
width: 20px;
height: 20px;
}

.root.large .title span {
width: 24px;
height: 24px;
}

.header:hover h3 {
border-bottom-color: var(--gray-900);
}

[data-theme='dark'] .header:hover h3 {
border-bottom-color: var(--white-100);
}

.header span {
width: 16px;
height: 16px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}

.root.standard .header span {
width: 16px;
height: 16px;
}

.root.large .header span {
width: 20px;
height: 20px;
}

.content {
overflow: hidden;
animation: flipdown 0.5s ease-out forwards;
color: var(--gray-900);
}

[data-theme='dark'] .content {
color: var(--gray-300);
}

@keyframes flipdown {
0% {
opacity: 0;
transform-origin: top center;
transform: rotateX(-90deg);
}

5% {
opacity: 1;
}

80% {
transform: rotateX(8deg);
}

83% {
transform: rotateX(6deg);
}

92% {
transform: rotateX(-3deg);
}

100% {
transform-origin: top center;
transform: rotateX(0deg);
}
}
Loading

0 comments on commit 74b1db7

Please sign in to comment.