-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #190
- Loading branch information
github-actions
committed
Jan 19, 2021
1 parent
f6a3be7
commit f5e716b
Showing
7 changed files
with
231 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React from 'react' | ||
import { Accordion, AccordionProps, Panel } from './index' | ||
import { Meta, Story } from '@storybook/react/types-6-0' | ||
|
||
const mockPanels: Panel[] = [ | ||
{ content: 'Content1', key: 1, title: 'Title 1' }, | ||
{ content: 'Content2', key: 2, title: 'Title 2' }, | ||
{ content: 'Content3', key: 3, title: 'Title 3' } | ||
] | ||
|
||
export default { | ||
argTypes: { | ||
panels: { control: { disable: true } } | ||
}, | ||
component: Accordion, | ||
parameters: { | ||
// disabled because shallow rendering doesn't work with decorator and hook inside decorator. | ||
storyshots: { disable: true } | ||
}, | ||
title: 'Accordion' | ||
} as Meta | ||
|
||
const Template: Story<AccordionProps> = args => ( | ||
<Accordion {...args} panels={mockPanels} /> | ||
) | ||
|
||
export const Default = Template.bind({}) | ||
|
||
export const Exclusive = Template.bind({}) | ||
Exclusive.args = { | ||
exclusive: true | ||
} | ||
|
||
export const ExpandAll = Template.bind({}) | ||
ExpandAll.args = { | ||
expandAllOnMount: true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { faChevronDown } from '@fortawesome/free-solid-svg-icons' | ||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' | ||
import { motion } from 'framer-motion' | ||
import React, { FC } from 'react' | ||
|
||
interface CollapseButtonProps { | ||
isCollapsed: boolean | ||
} | ||
|
||
export const CollapseButton: FC<CollapseButtonProps> = ({ | ||
isCollapsed | ||
}: CollapseButtonProps) => ( | ||
<motion.div | ||
animate={{ | ||
rotate: isCollapsed ? 0 : 180 | ||
}} | ||
whileHover={{ scale: 1.1 }} | ||
> | ||
<FontAwesomeIcon icon={faChevronDown} /> | ||
</motion.div> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { createUseStyles } from 'react-jss' | ||
import { styleguide } from '../assets/styles' | ||
import { AnimatePresence, motion } from 'framer-motion' | ||
import React, { FC, ReactNode } from 'react' | ||
|
||
const { spacing } = styleguide | ||
|
||
const useStyles = createUseStyles({ | ||
content: { | ||
paddingTop: spacing.s | ||
} | ||
}) | ||
|
||
interface PanelContentProps { | ||
children: ReactNode | ||
isActive: boolean | ||
} | ||
|
||
export const PanelContent: FC<PanelContentProps> = ({ | ||
children, | ||
isActive | ||
}: PanelContentProps) => { | ||
const classes = useStyles() | ||
|
||
return ( | ||
<AnimatePresence initial={false}> | ||
{isActive && ( | ||
<motion.section | ||
animate='open' | ||
exit='collapsed' | ||
initial='collapsed' | ||
transition={{ | ||
duration: 0.8, | ||
ease: [0.04, 0.62, 0.23, 0.98] | ||
}} | ||
variants={{ | ||
collapsed: { height: 0, opacity: 0 }, | ||
open: { height: 'auto', opacity: 1 } | ||
}} | ||
> | ||
<div className={classes.content}>{children}</div> | ||
</motion.section> | ||
)} | ||
</AnimatePresence> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { CollapseButton } from './CollapseButton' | ||
import { createUseStyles } from 'react-jss' | ||
import { generateAccordionPanelStyles } from './utils' | ||
import { PanelContent } from './PanelContent' | ||
import React, { FC, Key, ReactNode, useState } from 'react' | ||
import { styleguide, themes, ThemeType } from '../assets/styles' | ||
|
||
const { flexSpaceBetween, font } = styleguide | ||
const { dark, light } = ThemeType | ||
|
||
const useStyles = createUseStyles({ | ||
header: { | ||
...font.bodyLarge, | ||
...flexSpaceBetween, | ||
cursor: 'pointer' | ||
}, | ||
panel: generateAccordionPanelStyles(light), | ||
title: { | ||
color: themes[light].primary | ||
}, | ||
// eslint-disable-next-line sort-keys | ||
'@global': { | ||
[`.${dark}`]: { | ||
'& $panel': generateAccordionPanelStyles(dark), | ||
'& $title': { color: themes[dark].state.hover } | ||
} | ||
} | ||
}) | ||
|
||
export interface Panel { | ||
content: ReactNode | ||
key: Key | ||
title: string | ||
} | ||
|
||
interface SharedAccordionProps { | ||
defaultActiveKey?: Key | ||
panels: Panel[] | ||
} | ||
|
||
interface ExclusiveAccordionProps extends SharedAccordionProps { | ||
exclusive: true | ||
expandAllOnMount?: never | ||
} | ||
|
||
interface NonExclusiveAccordionProps extends SharedAccordionProps { | ||
exclusive: false | ||
expandAllOnMount?: boolean | ||
} | ||
|
||
export type AccordionProps = | ||
| ExclusiveAccordionProps | ||
| NonExclusiveAccordionProps | ||
|
||
export const Accordion: FC<AccordionProps> = ({ | ||
defaultActiveKey, | ||
exclusive = false, | ||
expandAllOnMount = false, | ||
panels | ||
}: AccordionProps) => { | ||
const getInitialActiveKeys = () => { | ||
const defaultActiveKeys: Key[] = [panels[0].key] | ||
|
||
if (defaultActiveKey) return [defaultActiveKey] | ||
else if (expandAllOnMount) return panels.map(({ key }) => key) | ||
|
||
return defaultActiveKeys | ||
} | ||
|
||
const [activeKeys, setActiveKeys] = useState<Key[]>(getInitialActiveKeys()) | ||
const classes = useStyles() | ||
|
||
const togglePanel = (panelKey: Key) => { | ||
let newActiveKeys = [...activeKeys, panelKey] | ||
|
||
// Close panel if it is open | ||
if (activeKeys.includes(panelKey)) | ||
newActiveKeys = activeKeys.filter(key => panelKey !== key) | ||
// If accordion is exclusive, only one panel can be open at a time | ||
else if (exclusive) newActiveKeys = [panelKey] | ||
|
||
setActiveKeys(newActiveKeys) | ||
} | ||
|
||
return ( | ||
<div> | ||
{panels.map(({ content, key, title }) => { | ||
const isActivePanel = activeKeys.includes(key) | ||
|
||
return ( | ||
<div className={classes.panel} key={key}> | ||
<div | ||
className={classes.header} | ||
onClick={() => togglePanel(key)} | ||
> | ||
<div className={classes.title}>{title}</div> | ||
<CollapseButton isCollapsed={!isActivePanel} /> | ||
</div> | ||
<PanelContent isActive={isActivePanel}> | ||
{content} | ||
</PanelContent> | ||
</div> | ||
) | ||
})} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { styleguide, themedStyles, ThemeType } from '../assets/styles' | ||
|
||
const { spacing } = styleguide | ||
|
||
export const generateAccordionPanelStyles = (themeType: ThemeType) => { | ||
const { base } = themedStyles[themeType] | ||
|
||
const borderStyles = `1px solid ${base.borderColor}` | ||
|
||
return { | ||
'&:first-of-type': { | ||
borderTop: borderStyles | ||
}, | ||
borderBottom: borderStyles, | ||
color: base.color, | ||
padding: spacing.m | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './Accordion' | ||
export * from './Avatar' | ||
export * from './assets/styles' | ||
export * from './Button' | ||
|