Skip to content

Instantly share code, notes, and snippets.

@yogicat
Last active July 3, 2020 07:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yogicat/fb05e513faa314b32c73cddc8782a6b0 to your computer and use it in GitHub Desktop.
Save yogicat/fb05e513faa314b32c73cddc8782a6b0 to your computer and use it in GitHub Desktop.
Accordion
import './NewAccordion.scss'
import React, { useState, ReactNode, createContext } from 'react'
import classNames from 'classnames'
interface AccordionProps {
children: ReactNode
className?: string
allowMultiple?: boolean
}
interface AccordionContextProps {
activeItems: number[]
toggleActiveItem(index: number): void
}
export const AccordionContext = createContext({} as AccordionContextProps)
export default function NewAccordion({ children, className, allowMultiple = false }: AccordionProps) {
const [activeItems, setActiveItems] = useState<number[]>([])
const toggleActiveItem = (index: number) => {
activeItems.includes(index)
? setActiveItems(activeItems.filter(itemIndex => itemIndex !== index))
: setActiveItems(allowMultiple ? [...activeItems, index] : [index])
}
return (
<AccordionContext.Provider
value={{
activeItems,
toggleActiveItem,
}}
>
<ul className={classNames('Accordion', className)}>{children}</ul>
</AccordionContext.Provider>
)
}
import React, { useContext } from 'react'
import classNames from 'classnames'
import useId from '../hooks/useId'
import Icon from './Icon'
import { AccordionContext } from './NewAccordion'
interface Props {
heading: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
contents: string
title: string
index: number
className?: string
}
function NewAccordionItem({ className, contents, heading: Heading, title, index }: Props) {
const id = useId('AccordionItem')
const { activeItems, toggleActiveItem } = useContext(AccordionContext)
const isOpen = activeItems.includes(index)
return (
<li className={classNames('Accordion__item', className)}>
<Heading className="Accordion__heading">
<button
aria-controls={id}
aria-expanded={isOpen}
className="Accordion__button"
onClick={() => toggleActiveItem(index)}
>
<span className="Accordion__title">{title}</span>
<Icon name={isOpen ? 'ArithmeticMinus' : 'ArithmeticPlus'} />
</button>
</Heading>
<div
id={id}
className={classNames('Accordion__content', {
'Accordion__content--active': isOpen,
})}
aria-hidden={!isOpen}
dangerouslySetInnerHTML={{
__html: contents,
}}
/>
</li>
)
}
export default React.memo(NewAccordionItem)
@yogicat
Copy link
Author

yogicat commented Jul 3, 2020

사용법

<Accordion>
   <AccordionItem title="제목" contents="내용내용" />
</Accordion>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment