Skip to content

Commit

Permalink
feature: create accordion component and story
Browse files Browse the repository at this point in the history
  • Loading branch information
rose-liang committed Aug 15, 2023
1 parent 72b9b94 commit da73fec
Show file tree
Hide file tree
Showing 7 changed files with 471 additions and 0 deletions.
135 changes: 135 additions & 0 deletions src/components/Accordion/Accordion.examples.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import React from 'react';
import { Accordion } from './Accordion';
import { Layout } from '../../storybook';
import styled from 'styled-components';
import { Gear } from '../../icons';
import { rem } from 'polished';
import { core } from '../../tokens';

export default {
title: 'components/Accordion/examples',
component: Accordion,
argTypes: {
allowMultiple: { control: { disable: true } },
defaultIndex: { control: { disable: true } },
format: { control: { disable: true } },
},
};

export function AccordionWithSubcopy({ args }) {
return (
<Layout.StoryVertical center>
<Accordion {...args}>
<Accordion.Item
title="Accordion item title"
subcopy="Subcopy text"
>
Accordion content
</Accordion.Item>
</Accordion>
</Layout.StoryVertical>
);
}

AccordionWithSubcopy.storyName = 'Accordion - subcopy';

export function AccordionWithIcon({ args }) {
return (
<Layout.StoryVertical center>
<Accordion {...args}>
<Accordion.Item
title="Accordion item with icon"
icon={<GearIcon />}
>
Accordion content
</Accordion.Item>
</Accordion>
</Layout.StoryVertical>
);
}

const GearIcon = styled(Gear)`
width: ${rem(22)};
margin-right: ${rem(10)};
path {
fill: ${core.color.text.primary};
}
`;

AccordionWithIcon.storyName = 'Accordion - icon';

export function DisabledAccordion({ args }) {
return (
<Layout.StoryVertical center>
<Accordion {...args}>
<Accordion.Item
title="Disabled accordion item"
disabled={true}
>
Accordion content
</Accordion.Item>
</Accordion>
</Layout.StoryVertical>
);
}

DisabledAccordion.storyName = 'Accordion - disabled';

export function AccordionWithError({ args }) {
return (
<Layout.StoryVertical center>
<Accordion {...args}>
<Accordion.Item
title="Accordion item with error"
hasError={true}
>
Accordion content
</Accordion.Item>
</Accordion>
</Layout.StoryVertical>
);
}

AccordionWithError.storyName = 'Accordion - error';

export function AccordionWithAllowMultipleFalse({ args }) {
return (
<Layout.StoryVertical center>
<Accordion {...args} allowMultiple={false} defaultIndex={0}>
<Accordion.Item title="Accordion item 1">
Accordion content
</Accordion.Item>
<Accordion.Item title="Accordion item 2">
Accordion content
</Accordion.Item>
<Accordion.Item title="Accordion item 3">
Accordion content
</Accordion.Item>
</Accordion>
</Layout.StoryVertical>
);
}

AccordionWithAllowMultipleFalse.storyName =
'Accordion - allowMultiple is false';

export function AccordionAllowMultiple({ args }) {
return (
<Layout.StoryVertical center>
<Accordion {...args}>
<Accordion.Item title="Accordion item 1">
Accordion content
</Accordion.Item>
<Accordion.Item title="Accordion item 2">
Accordion content
</Accordion.Item>
<Accordion.Item title="Accordion item 3">
Accordion content
</Accordion.Item>
</Accordion>
</Layout.StoryVertical>
);
}

AccordionAllowMultiple.storyName =
'Accordion - allowMultiple is true (default)';
77 changes: 77 additions & 0 deletions src/components/Accordion/Accordion.minors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useState } from 'react';

import {
Content,
ChevronUp,
CircleWarningIcon,
Header,
StyledChevronDown,
Subcopy,
Title,
TitleContainer,
TriggerContainer,
Wrapper,
} from './Accordion.style';
import { MinorComponent } from '../../utils';
import { AccordionItemProps } from './Accordion.types';

export interface Minors {
Item: MinorComponent<any>;
}

export function Item({
children,
title,
format,
index,
allowMultiple,
defaultActive,
setActiveIndex,
itemActive,
subcopy = '',
icon,
hasError = false,
disabled = false,
}: AccordionItemProps) {
const [active, setActive] = useState<boolean>(defaultActive);
const isActive = allowMultiple
? active && !disabled
: itemActive && !disabled;

return (
<Wrapper
active={isActive}
disabled={disabled}
format={format}
key={index}
>
<TriggerContainer
onClick={() => {
if (allowMultiple) {
setActive(!active);
} else {
setActiveIndex({ index });
}
}}
tabIndex={0}
format={format}
active={isActive}
>
<Header>
{hasError && <CircleWarningIcon />}
{!hasError && icon && icon}
<TitleContainer>
<Title>{title}</Title>
{subcopy && <Subcopy>{subcopy}</Subcopy>}
</TitleContainer>
</Header>
{isActive ? (
<ChevronUp width="24" />
) : (
<StyledChevronDown width="24" />
)}
</TriggerContainer>
{isActive && <Content active={isActive}>{children}</Content>}
</Wrapper>
);
}
38 changes: 38 additions & 0 deletions src/components/Accordion/Accordion.props.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import styled, { css } from 'styled-components';
import { rem } from 'polished';

import { Accordion } from './Accordion';

export default {
title: 'components/Accordion/props',
component: Accordion,
argTypes: {
allowMultiple: { control: { disable: true } },
defaultIndex: { control: { disable: true } },
format: { control: { disable: true } },
},
};

const formats = ['basic', 'secondary'];

export function Formats({ args }) {
return (
<Container>
{formats.map((format, i) => (
<Accordion key={i} format={format} {...args}>
<Accordion.Item title={`Accordion format: ${format}`}>
Accordion content
</Accordion.Item>
</Accordion>
))}
</Container>
);
}

const Container = styled.div`
width: 50%;
display: flex;
flex-direction: column;
gap: ${rem(8)};
`;
35 changes: 35 additions & 0 deletions src/components/Accordion/Accordion.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { Story } from '@storybook/react';

import { Accordion } from './Accordion';
import { Props } from './Accordion.types';
import styled from 'styled-components';
import { Gear } from '../../icons';
import { rem } from 'polished';

export default {
title: 'components/Accordion',
component: Accordion,
};

const Template: Story<Props> = (args) => {
return (
<Container>
<Accordion {...args}>
<Accordion.Item title="Accordion item 1">
Accordion content
</Accordion.Item>
<Accordion.Item title="Accordion item 2">
Accordion content
</Accordion.Item>
</Accordion>
</Container>
);
};

const Container = styled.div`
width: 50%;
`;

export const Controls = Template.bind({});
Controls.storyName = 'Accordion';

0 comments on commit da73fec

Please sign in to comment.