Skip to content
This repository was archived by the owner on Oct 23, 2024. It is now read-only.

Commit da73fec

Browse files
committed
feature: create accordion component and story
1 parent 72b9b94 commit da73fec

7 files changed

Lines changed: 471 additions & 0 deletions

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import React from 'react';
2+
import { Accordion } from './Accordion';
3+
import { Layout } from '../../storybook';
4+
import styled from 'styled-components';
5+
import { Gear } from '../../icons';
6+
import { rem } from 'polished';
7+
import { core } from '../../tokens';
8+
9+
export default {
10+
title: 'components/Accordion/examples',
11+
component: Accordion,
12+
argTypes: {
13+
allowMultiple: { control: { disable: true } },
14+
defaultIndex: { control: { disable: true } },
15+
format: { control: { disable: true } },
16+
},
17+
};
18+
19+
export function AccordionWithSubcopy({ args }) {
20+
return (
21+
<Layout.StoryVertical center>
22+
<Accordion {...args}>
23+
<Accordion.Item
24+
title="Accordion item title"
25+
subcopy="Subcopy text"
26+
>
27+
Accordion content
28+
</Accordion.Item>
29+
</Accordion>
30+
</Layout.StoryVertical>
31+
);
32+
}
33+
34+
AccordionWithSubcopy.storyName = 'Accordion - subcopy';
35+
36+
export function AccordionWithIcon({ args }) {
37+
return (
38+
<Layout.StoryVertical center>
39+
<Accordion {...args}>
40+
<Accordion.Item
41+
title="Accordion item with icon"
42+
icon={<GearIcon />}
43+
>
44+
Accordion content
45+
</Accordion.Item>
46+
</Accordion>
47+
</Layout.StoryVertical>
48+
);
49+
}
50+
51+
const GearIcon = styled(Gear)`
52+
width: ${rem(22)};
53+
margin-right: ${rem(10)};
54+
path {
55+
fill: ${core.color.text.primary};
56+
}
57+
`;
58+
59+
AccordionWithIcon.storyName = 'Accordion - icon';
60+
61+
export function DisabledAccordion({ args }) {
62+
return (
63+
<Layout.StoryVertical center>
64+
<Accordion {...args}>
65+
<Accordion.Item
66+
title="Disabled accordion item"
67+
disabled={true}
68+
>
69+
Accordion content
70+
</Accordion.Item>
71+
</Accordion>
72+
</Layout.StoryVertical>
73+
);
74+
}
75+
76+
DisabledAccordion.storyName = 'Accordion - disabled';
77+
78+
export function AccordionWithError({ args }) {
79+
return (
80+
<Layout.StoryVertical center>
81+
<Accordion {...args}>
82+
<Accordion.Item
83+
title="Accordion item with error"
84+
hasError={true}
85+
>
86+
Accordion content
87+
</Accordion.Item>
88+
</Accordion>
89+
</Layout.StoryVertical>
90+
);
91+
}
92+
93+
AccordionWithError.storyName = 'Accordion - error';
94+
95+
export function AccordionWithAllowMultipleFalse({ args }) {
96+
return (
97+
<Layout.StoryVertical center>
98+
<Accordion {...args} allowMultiple={false} defaultIndex={0}>
99+
<Accordion.Item title="Accordion item 1">
100+
Accordion content
101+
</Accordion.Item>
102+
<Accordion.Item title="Accordion item 2">
103+
Accordion content
104+
</Accordion.Item>
105+
<Accordion.Item title="Accordion item 3">
106+
Accordion content
107+
</Accordion.Item>
108+
</Accordion>
109+
</Layout.StoryVertical>
110+
);
111+
}
112+
113+
AccordionWithAllowMultipleFalse.storyName =
114+
'Accordion - allowMultiple is false';
115+
116+
export function AccordionAllowMultiple({ args }) {
117+
return (
118+
<Layout.StoryVertical center>
119+
<Accordion {...args}>
120+
<Accordion.Item title="Accordion item 1">
121+
Accordion content
122+
</Accordion.Item>
123+
<Accordion.Item title="Accordion item 2">
124+
Accordion content
125+
</Accordion.Item>
126+
<Accordion.Item title="Accordion item 3">
127+
Accordion content
128+
</Accordion.Item>
129+
</Accordion>
130+
</Layout.StoryVertical>
131+
);
132+
}
133+
134+
AccordionAllowMultiple.storyName =
135+
'Accordion - allowMultiple is true (default)';
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React, { useState } from 'react';
2+
3+
import {
4+
Content,
5+
ChevronUp,
6+
CircleWarningIcon,
7+
Header,
8+
StyledChevronDown,
9+
Subcopy,
10+
Title,
11+
TitleContainer,
12+
TriggerContainer,
13+
Wrapper,
14+
} from './Accordion.style';
15+
import { MinorComponent } from '../../utils';
16+
import { AccordionItemProps } from './Accordion.types';
17+
18+
export interface Minors {
19+
Item: MinorComponent<any>;
20+
}
21+
22+
export function Item({
23+
children,
24+
title,
25+
format,
26+
index,
27+
allowMultiple,
28+
defaultActive,
29+
setActiveIndex,
30+
itemActive,
31+
subcopy = '',
32+
icon,
33+
hasError = false,
34+
disabled = false,
35+
}: AccordionItemProps) {
36+
const [active, setActive] = useState<boolean>(defaultActive);
37+
const isActive = allowMultiple
38+
? active && !disabled
39+
: itemActive && !disabled;
40+
41+
return (
42+
<Wrapper
43+
active={isActive}
44+
disabled={disabled}
45+
format={format}
46+
key={index}
47+
>
48+
<TriggerContainer
49+
onClick={() => {
50+
if (allowMultiple) {
51+
setActive(!active);
52+
} else {
53+
setActiveIndex({ index });
54+
}
55+
}}
56+
tabIndex={0}
57+
format={format}
58+
active={isActive}
59+
>
60+
<Header>
61+
{hasError && <CircleWarningIcon />}
62+
{!hasError && icon && icon}
63+
<TitleContainer>
64+
<Title>{title}</Title>
65+
{subcopy && <Subcopy>{subcopy}</Subcopy>}
66+
</TitleContainer>
67+
</Header>
68+
{isActive ? (
69+
<ChevronUp width="24" />
70+
) : (
71+
<StyledChevronDown width="24" />
72+
)}
73+
</TriggerContainer>
74+
{isActive && <Content active={isActive}>{children}</Content>}
75+
</Wrapper>
76+
);
77+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React from 'react';
2+
import styled, { css } from 'styled-components';
3+
import { rem } from 'polished';
4+
5+
import { Accordion } from './Accordion';
6+
7+
export default {
8+
title: 'components/Accordion/props',
9+
component: Accordion,
10+
argTypes: {
11+
allowMultiple: { control: { disable: true } },
12+
defaultIndex: { control: { disable: true } },
13+
format: { control: { disable: true } },
14+
},
15+
};
16+
17+
const formats = ['basic', 'secondary'];
18+
19+
export function Formats({ args }) {
20+
return (
21+
<Container>
22+
{formats.map((format, i) => (
23+
<Accordion key={i} format={format} {...args}>
24+
<Accordion.Item title={`Accordion format: ${format}`}>
25+
Accordion content
26+
</Accordion.Item>
27+
</Accordion>
28+
))}
29+
</Container>
30+
);
31+
}
32+
33+
const Container = styled.div`
34+
width: 50%;
35+
display: flex;
36+
flex-direction: column;
37+
gap: ${rem(8)};
38+
`;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from 'react';
2+
import { Story } from '@storybook/react';
3+
4+
import { Accordion } from './Accordion';
5+
import { Props } from './Accordion.types';
6+
import styled from 'styled-components';
7+
import { Gear } from '../../icons';
8+
import { rem } from 'polished';
9+
10+
export default {
11+
title: 'components/Accordion',
12+
component: Accordion,
13+
};
14+
15+
const Template: Story<Props> = (args) => {
16+
return (
17+
<Container>
18+
<Accordion {...args}>
19+
<Accordion.Item title="Accordion item 1">
20+
Accordion content
21+
</Accordion.Item>
22+
<Accordion.Item title="Accordion item 2">
23+
Accordion content
24+
</Accordion.Item>
25+
</Accordion>
26+
</Container>
27+
);
28+
};
29+
30+
const Container = styled.div`
31+
width: 50%;
32+
`;
33+
34+
export const Controls = Template.bind({});
35+
Controls.storyName = 'Accordion';

0 commit comments

Comments
 (0)