feat: added accordion component
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
.accordionItem {
|
||||
border-bottom: 1px solid var(--Base-Border-Subtle);
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.card .summary {
|
||||
padding: var(--Spacing-x1) var(--Spacing-x-one-and-half);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
}
|
||||
|
||||
.faq .summary {
|
||||
padding: var(--Spacing-x2) 0;
|
||||
}
|
||||
|
||||
.faq .content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.summary {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x2);
|
||||
cursor: pointer;
|
||||
color: var(--Base-Text-High-contrast);
|
||||
font-family: var(--typography-Body-Bold-fontFamily);
|
||||
font-size: var(--typography-Body-Bold-fontSize);
|
||||
font-weight: var(--typography-Body-Bold-fontWeight);
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.summary:hover,
|
||||
.summary:focus {
|
||||
background-color: var(--Base-Surface-Primary-light-Hover);
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 var(--Spacing-x-one-and-half);
|
||||
overflow: hidden;
|
||||
max-height: 0;
|
||||
transition: max-height 0.3s;
|
||||
}
|
||||
|
||||
.chevron {
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
details[open] .chevron {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { VariantProps } from "class-variance-authority"
|
||||
|
||||
import { accordionItemVariants } from "./variants"
|
||||
|
||||
export interface AccordionItemProps
|
||||
extends React.HtmlHTMLAttributes<HTMLDetailsElement>,
|
||||
VariantProps<typeof accordionItemVariants> {
|
||||
title: string
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
"use client"
|
||||
|
||||
import { useRef } from "react"
|
||||
|
||||
import { ChevronDownIcon } from "@/components/Icons"
|
||||
|
||||
import { AccordionItemProps } from "./accordionItem"
|
||||
import { accordionItemVariants } from "./variants"
|
||||
|
||||
import styles from "./accordionItem.module.css"
|
||||
|
||||
export default function AccordionItem({
|
||||
children,
|
||||
title,
|
||||
variant,
|
||||
}: AccordionItemProps) {
|
||||
const contentRef = useRef<HTMLDivElement>(null)
|
||||
const detailsRef = useRef<HTMLDetailsElement>(null)
|
||||
|
||||
function toggleAccordion() {
|
||||
const details = detailsRef.current
|
||||
const content = contentRef.current
|
||||
if (details && content) {
|
||||
if (details.open) {
|
||||
content.style.maxHeight = `${content.scrollHeight}px`
|
||||
content.addEventListener(
|
||||
"transitionend",
|
||||
() => {
|
||||
// Remove maxHeight after transition to allow content to transition multiple times
|
||||
content.style.maxHeight = "none"
|
||||
},
|
||||
{ once: true }
|
||||
)
|
||||
} else {
|
||||
content.style.maxHeight = "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<li className={accordionItemVariants({ variant })}>
|
||||
<details ref={detailsRef} onToggle={toggleAccordion}>
|
||||
<summary className={styles.summary}>
|
||||
<span>{title}</span>
|
||||
<ChevronDownIcon className={styles.chevron} color="burgundy" />
|
||||
</summary>
|
||||
<div ref={contentRef} className={styles.content}>
|
||||
{children}
|
||||
</div>
|
||||
</details>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { cva } from "class-variance-authority"
|
||||
|
||||
import styles from "./accordionItem.module.css"
|
||||
|
||||
export const accordionItemVariants = cva(styles.accordionItem, {
|
||||
variants: {
|
||||
variant: {
|
||||
card: styles.card,
|
||||
faq: styles.faq,
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "card",
|
||||
},
|
||||
})
|
||||
11
components/TempDesignSystem/Accordion/accordion.module.css
Normal file
11
components/TempDesignSystem/Accordion/accordion.module.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.accordion {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
}
|
||||
.faq {
|
||||
background-color: var(--Base-Background-Primary-Normal);
|
||||
}
|
||||
7
components/TempDesignSystem/Accordion/accordion.ts
Normal file
7
components/TempDesignSystem/Accordion/accordion.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { VariantProps } from "class-variance-authority"
|
||||
|
||||
import { accordionVariants } from "./variants"
|
||||
|
||||
export interface AccordionProps
|
||||
extends React.HtmlHTMLAttributes<HTMLUListElement>,
|
||||
VariantProps<typeof accordionVariants> {}
|
||||
22
components/TempDesignSystem/Accordion/index.tsx
Normal file
22
components/TempDesignSystem/Accordion/index.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Children, cloneElement, isValidElement } from "react"
|
||||
|
||||
import { AccordionItemProps } from "./AccordionItem/accordionItem"
|
||||
import { AccordionProps } from "./accordion"
|
||||
import { accordionVariants } from "./variants"
|
||||
|
||||
export default function Accordion({
|
||||
children,
|
||||
className,
|
||||
variant,
|
||||
}: AccordionProps) {
|
||||
return (
|
||||
<ul className={accordionVariants({ className, variant })}>
|
||||
{Children.map(children, (child) => {
|
||||
if (isValidElement<AccordionItemProps>(child)) {
|
||||
return cloneElement(child, { variant })
|
||||
}
|
||||
})}
|
||||
{/* {children} */}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
15
components/TempDesignSystem/Accordion/variants.ts
Normal file
15
components/TempDesignSystem/Accordion/variants.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { cva } from "class-variance-authority"
|
||||
|
||||
import styles from "./accordion.module.css"
|
||||
|
||||
export const accordionVariants = cva(styles.accordion, {
|
||||
variants: {
|
||||
variant: {
|
||||
card: styles.card,
|
||||
faq: styles.faq,
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "card",
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user