Skip to content

Commit 2a16bd1

Browse files
authored
Merge pull request #13840 from saurabhburade/faq-component
Create FAQ Accordion Component
2 parents 592714a + e5100df commit 2a16bd1

File tree

3 files changed

+153
-1
lines changed

3 files changed

+153
-1
lines changed

src/components/Faq/Faq.stories.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Meta, StoryObj } from "@storybook/react"
2+
3+
import { Faq as FaqComponent, FaqContent, FaqItem, FaqTrigger } from "."
4+
5+
const meta = {
6+
title: "Molecules / Display Content / Faq",
7+
component: FaqComponent,
8+
decorators: [
9+
(Story) => (
10+
<div className="mx-auto w-[calc(100vw-2rem)] max-w-[min(52rem,100%)] p-4">
11+
<Story />
12+
</div>
13+
),
14+
],
15+
} satisfies Meta<typeof FaqComponent>
16+
17+
export default meta
18+
19+
export const Faq: StoryObj = {
20+
render: () => (
21+
<FaqComponent type="single" collapsible>
22+
<FaqItem value="item-1">
23+
<FaqTrigger>
24+
<h2 className="text-start text-base md:text-xl">
25+
Why is there no &apos;official&apos; Ethereum L2?
26+
</h2>
27+
</FaqTrigger>
28+
29+
<FaqContent>
30+
Just as there is no &apos;official&apos; Ethereum client, there is no
31+
&apos;official&apos; Ethereum layer 2. Ethereum is permissionless -
32+
technically anyone can create a layer 2! Multiple teams will implement
33+
their version of a layer 2, and the ecosystem as a whole will benefit
34+
from a diversity of design approaches that are optimized for different
35+
use cases. Much like we have multiple Ethereum clients developed by
36+
multiple teams in order to have diversity in the network, this too
37+
will be how layer 2s develop in the future.
38+
</FaqContent>
39+
</FaqItem>
40+
<FaqItem value="item-2">
41+
<FaqTrigger>
42+
<h2 className="text-start text-base md:text-xl">
43+
Why is there no &apos;official&apos; Ethereum L2?
44+
</h2>
45+
</FaqTrigger>
46+
<FaqContent>
47+
Just as there is no &apos;official&apos; Ethereum client, there is no
48+
&apos;official&apos; Ethereum layer 2. Ethereum is permissionless -
49+
technically anyone can create a layer 2! Multiple teams will implement
50+
their version of a layer 2, and the ecosystem as a whole will benefit
51+
from a diversity of design approaches that are optimized for different
52+
use cases. Much like we have multiple Ethereum clients developed by
53+
multiple teams in order to have diversity in the network, this too
54+
will be how layer 2s develop in the future.
55+
</FaqContent>
56+
</FaqItem>
57+
</FaqComponent>
58+
),
59+
}

src/components/Faq/index.tsx

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React from "react"
2+
import * as AccordionPrimitive from "@radix-ui/react-accordion"
3+
4+
import {
5+
Accordion,
6+
AccordionContent,
7+
AccordionItem,
8+
AccordionTrigger,
9+
} from "@/components/ui/accordion"
10+
11+
import { cn } from "@/lib/utils/cn"
12+
13+
const FaqTrigger = React.forwardRef<
14+
React.ElementRef<typeof AccordionPrimitive.Trigger>,
15+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
16+
>(({ className, children, ...props }, ref) => (
17+
<AccordionTrigger
18+
ref={ref}
19+
className={cn(
20+
"w-full p-4 md:px-8 md:py-6",
21+
"text-start font-medium",
22+
"hover:text-body [&[data-state=open]_h2]:text-current [&[data-state=open]_svg]:-rotate-90 hover:[&_h2]:!text-body [&_svg]:rotate-90",
23+
"[&_[data-label='icon-container']]:ms-8 [&_[data-label='icon-container']]:rounded-full [&_[data-label='icon-container']]:border [&_[data-label='icon-container']]:border-body [&_[data-label='icon-container']]:p-2 [&_svg]:text-lg",
24+
"[&_[data-label='icon-container']:hover_svg]:text-primary-hover hover:[&_[data-label='icon-container']]:!border-primary-hover hover:[&_[data-label='icon-container']]:shadow-[4px_4px_0_hsla(var(--primary-low-contrast),1)]",
25+
"[&[data-state=open]]:text-current",
26+
className
27+
)}
28+
{...props}
29+
>
30+
{children}
31+
</AccordionTrigger>
32+
))
33+
FaqTrigger.displayName = AccordionPrimitive.Trigger.displayName
34+
35+
const Faq = ({
36+
children,
37+
type,
38+
...props
39+
}: AccordionPrimitive.AccordionSingleProps) => {
40+
return (
41+
<Accordion
42+
type={type}
43+
collapsible
44+
className={cn(
45+
"overflow-hidden rounded border",
46+
"w-full bg-background",
47+
props?.className
48+
)}
49+
{...props}
50+
>
51+
{children}
52+
</Accordion>
53+
)
54+
}
55+
56+
const FaqItem = React.forwardRef<
57+
React.ElementRef<typeof AccordionPrimitive.Item>,
58+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
59+
>(({ className, ...props }, ref) => (
60+
<AccordionItem
61+
ref={ref}
62+
className={cn(
63+
"w-full border-b last:border-b-0 hover:bg-background-highlight [&[data-state=open]]:bg-background-highlight",
64+
className
65+
)}
66+
{...props}
67+
/>
68+
))
69+
FaqItem.displayName = "AccordionItem"
70+
71+
const FaqContent = React.forwardRef<
72+
React.ElementRef<typeof AccordionPrimitive.Content>,
73+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
74+
>(({ className, children, ...props }, ref) => (
75+
<AccordionContent
76+
ref={ref}
77+
className={cn(
78+
"w-full overflow-hidden px-4 text-sm md:px-8",
79+
"transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
80+
)}
81+
{...props}
82+
>
83+
<div className={cn("border-t border-body-light py-3 md:py-6", className)}>
84+
{children}
85+
</div>
86+
</AccordionContent>
87+
))
88+
89+
FaqContent.displayName = AccordionPrimitive.Content.displayName
90+
91+
export { Faq, FaqContent, FaqItem, FaqTrigger }

src/components/ui/accordion.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ const AccordionTrigger = React.forwardRef<
3333
<>
3434
{children}
3535
{!hideIcon && (
36-
<ChevronNext className="size-[1em] shrink-0 text-2xl transition-transform duration-200" />
36+
<div data-label="icon-container">
37+
<ChevronNext className="size-[1em] shrink-0 text-2xl transition-transform duration-200" />
38+
</div>
3739
)}
3840
</>
3941
</AccordionPrimitive.Trigger>

0 commit comments

Comments
 (0)