Skip to content

Commit

Permalink
feat(accordion): add Accordion component
Browse files Browse the repository at this point in the history
  • Loading branch information
vickonrails committed Jun 9, 2021
1 parent dcf16db commit c0f8f79
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 11 deletions.
104 changes: 104 additions & 0 deletions src/components/accordion/accordion.stories.tsx
@@ -0,0 +1,104 @@
import React from 'react'
import { Story, Meta } from '@storybook/react'

import { Accordion, Text, AccordionPanel } from '../../components'
import { Heading } from '../heading'

export default {
title: 'Components/Accordion',
component: Accordion
} as Meta

export const Sizes = () => (
<>
<Heading level='h2' size='xl'>
Small Sized Heading
</Heading>
<Accordion size='sm'>
<AccordionPanel header='One'>
<div>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet
perspiciatis praesentium nemo nobis sed, assumenda vitae voluptatum
rerum, libero, quisquam nostrum aspernatur labore saepe totam iusto
harum? Quidem, mollitia aspernatur.
</div>
</AccordionPanel>
<AccordionPanel header='Two'>
<div>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet
perspiciatis praesentium nemo nobis sed, assumenda vitae voluptatum
rerum, libero, quisquam nostrum aspernatur labore saepe totam iusto
harum? Quidem, mollitia aspernatur.
</div>
</AccordionPanel>
<AccordionPanel header='Three'>
<div>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet
perspiciatis praesentium nemo nobis sed, assumenda vitae voluptatum
rerum, libero, quisquam nostrum aspernatur labore saepe totam iusto
harum? Quidem, mollitia aspernatur.
</div>
</AccordionPanel>
</Accordion>

<Heading level='h2' size='xl'>
Medium Sized Accordion
</Heading>
<Accordion size='md'>
<AccordionPanel header='One'>
<div>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet
perspiciatis praesentium nemo nobis sed, assumenda vitae voluptatum
rerum, libero, quisquam nostrum aspernatur labore saepe totam iusto
harum? Quidem, mollitia aspernatur.
</div>
</AccordionPanel>
<AccordionPanel header='Two'>
<div>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet
perspiciatis praesentium nemo nobis sed, assumenda vitae voluptatum
rerum, libero, quisquam nostrum aspernatur labore saepe totam iusto
harum? Quidem, mollitia aspernatur.
</div>
</AccordionPanel>
<AccordionPanel header='Three'>
<div>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet
perspiciatis praesentium nemo nobis sed, assumenda vitae voluptatum
rerum, libero, quisquam nostrum aspernatur labore saepe totam iusto
harum? Quidem, mollitia aspernatur.
</div>
</AccordionPanel>
</Accordion>

<Heading level='h2' size='xl'>
Large Sized Accordion
</Heading>
<Accordion size='lg'>
<AccordionPanel header='One'>
<div>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet
perspiciatis praesentium nemo nobis sed, assumenda vitae voluptatum
rerum, libero, quisquam nostrum aspernatur labore saepe totam iusto
harum? Quidem, mollitia aspernatur.
</div>
</AccordionPanel>
<AccordionPanel header='Two'>
<div>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet
perspiciatis praesentium nemo nobis sed, assumenda vitae voluptatum
rerum, libero, quisquam nostrum aspernatur labore saepe totam iusto
harum? Quidem, mollitia aspernatur.
</div>
</AccordionPanel>
<AccordionPanel header='Three'>
<div>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet
perspiciatis praesentium nemo nobis sed, assumenda vitae voluptatum
rerum, libero, quisquam nostrum aspernatur labore saepe totam iusto
harum? Quidem, mollitia aspernatur.
</div>
</AccordionPanel>
</Accordion>
</>
)
171 changes: 160 additions & 11 deletions src/components/accordion/accordion.tsx
@@ -1,23 +1,172 @@
import React, { FC } from 'react'
import React, { FC, HTMLAttributes, createContext, useContext } from 'react'
import styled from '@emotion/styled'
import { Disclosure } from '@headlessui/react'
import { ChevronDown } from 'react-feather'

import { accordionTheme } from '../theme/components/accordion.theme'
import { Flex } from '../../components'

const { Button, Panel } = Disclosure

const Accordion: FC<any> = (props) => {
return <Disclosure {...props} />
const AccordionContext = createContext<AccordionBaseProps | null>(null)

const { Provider } = AccordionContext

const Accordion: FC<AccordionProps> = ({
children,
className,
size,
width,
fullWidth,
showIcon,
iconPosition,
...props
}) => {
const _className = className
? `avocado-accordion ${className}`
: `avocado-accordion`

const accordionValues = {
size,
width,
fullWidth,
showIcon,
iconPosition
}

return (
<Provider value={accordionValues}>
<StyledAccordion
className={_className}
width={width}
fullWidth={fullWidth}
{...props}
>
{children}
</StyledAccordion>
</Provider>
)
}

const AccordionButton: FC<any> = Button
// interface AccordionButtonProps {}
const AccordionButton: FC = Button

const AccordionPanel: FC<AccordionPanelProps> = ({
children,
className,
header,
...props
}) => {
const context = useContext(AccordionContext)
const { iconPosition, showIcon, size } = context as AccordionBaseProps

const _className = className
? `avocado-accordion_panel ${className}`
: `avocado-accordion_panel`

const AccordionPanel: FC<any> = (props) => {
return (
<span>
<Button>{props.heading}</Button>
<Panel>{props.children}</Panel>
</span>
<Disclosure>
<StyledDisclosure
className={_className}
{...props}
size={size}
iconPosition={iconPosition}
showIcon={showIcon}
>
<Button className='avocado-accordion_panel__button'>
<Flex alignItems='center' justifyContent='space-between' gap={0}>
{header}
<ChevronDown className='avocado-accordion_panel__icon' />
</Flex>
</Button>
<Panel className='avocado-accordion_panel__content'>{children}</Panel>
</StyledDisclosure>
</Disclosure>
)
}
// interface AccordionPanelProps {}

interface AccordionPanelProps
extends HTMLAttributes<HTMLElement>,
Omit<AccordionBaseProps, 'width' | 'fullWidth'> {
/**
* header - component/text to show on the Accordion Button
*/
header: string | JSX.Element
}

const StyledDisclosure = styled.div<AccordionBaseProps>`
display: block;
width: 100%;
border-bottom: 1px solid ${accordionTheme.border};
.avocado-accordion_panel__button {
cursor: pointer;
width: 100%;
text-align: left;
background: inherit;
border: none;
padding: ${({ size }) => size && `${accordionTheme.sizes[size].margin} 0`};
user-select: none;
font-size: ${({ size }) => size && accordionTheme.sizes[size].fontSize};
}
.avocado-accordion_panel__content {
background: ${accordionTheme.panelBackground};
font-size: ${({ size }) => size && accordionTheme.sizes[size].fontSize};
margin: 0;
padding: 0.85em;
}
.avocado-accordion_panel__icon {
height: 1em;
}
`

const StyledAccordion = styled.div<AccordionProps>`
width: ${({ width, fullWidth }) => (fullWidth ? '100%' : width)};
font-size: ${({ size }) => size && accordionTheme.sizes[size].fontSize};
margin-bottom: 1.5em;
button {
font-size: inherit;
}
`

type AccordionSize = 'sm' | 'md' | 'lg'
type AccordionBaseProps = {
/**
* size - size of the Accordion component
*/
size?: AccordionSize

/**
* width - width of the Accordion component in px
*/
width?: string

/**
* fullWidth - when set to true, Accordion stretches to fill horizontal space
*/
fullWidth?: boolean

/**
* showIcon - should Accordion show chevron icon
*/
showIcon?: boolean

/**
* iconPosition - position of Accordion header icon
*/
iconPosition?: 'left' | 'right'
}
interface AccordionProps
extends HTMLAttributes<HTMLElement>,
AccordionBaseProps {}

Accordion.defaultProps = {
size: 'md',
width: '20em',
iconPosition: 'right',
fullWidth: false,
showIcon: true
}

export { Accordion, AccordionButton, AccordionPanel }
20 changes: 20 additions & 0 deletions src/components/theme/components/accordion.theme.ts
@@ -0,0 +1,20 @@
import colors from '../colors'

export const accordionTheme = {
border: colors.gray[4],
panelBackground: colors.gray[3],
sizes: {
sm: {
fontSize: `0.875em`,
margin: `0.5em`
},
md: {
fontSize: `1em`,
margin: `0.5em`
},
lg: {
fontSize: `1em`,
margin: `0.625em`
}
}
}
1 change: 1 addition & 0 deletions src/components/theme/components/index.ts
Expand Up @@ -4,3 +4,4 @@ export * from './select.theme'
export * from './avatar.theme'
export * from './image.theme'
export * from './spinner.theme'
export * from './accordion.theme'

0 comments on commit c0f8f79

Please sign in to comment.