-
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.
Showing
45 changed files
with
870 additions
and
4 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,43 @@ | ||
import { style, styleVariants } from "@vanilla-extract/css"; | ||
|
||
import color from "../../design-token/color"; | ||
import typography from "../../design-token/typography"; | ||
import { flex } from "../../design-token/utils.css"; | ||
|
||
export const summaryText = { | ||
sm: typography.$semantic.caption1Regular, | ||
md: typography.$semantic.title3Bold, | ||
}; | ||
|
||
export const summaryColor = styleVariants({ | ||
black: { | ||
color: color.$scale.grey800, | ||
}, | ||
grey: { | ||
color: color.$scale.grey500, | ||
}, | ||
}); | ||
|
||
const summaryContainerBase = style([ | ||
flex, | ||
{ | ||
justifyContent: "flex-start", | ||
alignItems: "center", | ||
cursor: "pointer", | ||
}, | ||
]); | ||
|
||
export const summaryContainer = styleVariants({ | ||
sm: [ | ||
summaryContainerBase, | ||
{ | ||
gap: 5, | ||
}, | ||
], | ||
md: [ | ||
summaryContainerBase, | ||
{ | ||
gap: 13, | ||
}, | ||
], | ||
}); |
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,26 @@ | ||
import { type ReactNode } from "react"; | ||
|
||
import { AccordionContextProvider } from "./AccordionContextProvider"; | ||
import AccordionDetails from "./AccordionDetails"; | ||
import AccordionSummary from "./AccordionSummary"; | ||
|
||
interface AccordionProps { | ||
width?: number | string; | ||
open?: boolean; | ||
children: ReactNode; | ||
} | ||
|
||
export default function Accordion({ | ||
width = 200, | ||
open: initOpen = false, | ||
children, | ||
}: AccordionProps) { | ||
return ( | ||
<AccordionContextProvider open={initOpen} width={width}> | ||
{children} | ||
</AccordionContextProvider> | ||
); | ||
} | ||
|
||
Accordion.Details = AccordionDetails; | ||
Accordion.Summary = AccordionSummary; |
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,56 @@ | ||
import { | ||
type ReactNode, | ||
createContext, | ||
useCallback, | ||
useContext, | ||
useEffect, | ||
useMemo, | ||
useState, | ||
} from "react"; | ||
|
||
export type AccordionContextType = { | ||
open: boolean; | ||
width: number | string; | ||
onChange: (open: boolean) => void; | ||
}; | ||
|
||
const AccordionContext = createContext<AccordionContextType | null>(null); | ||
|
||
export function useAccordion() { | ||
const accordionData = useContext(AccordionContext); | ||
return accordionData; | ||
} | ||
|
||
export function AccordionContextProvider({ | ||
open: initOpen, | ||
width, | ||
children, | ||
}: { | ||
open: boolean; | ||
width: number | string; | ||
children: ReactNode; | ||
}) { | ||
const [open, setOpen] = useState(initOpen); | ||
|
||
const handleChange = useCallback( | ||
(nextOpen: boolean) => { | ||
setOpen(nextOpen); | ||
}, | ||
[setOpen], | ||
); | ||
|
||
const accordionContextValue = useMemo( | ||
() => ({ open, onChange: handleChange, width }), | ||
[open, handleChange, width], | ||
); | ||
|
||
useEffect(() => { | ||
setOpen(initOpen); | ||
}, [initOpen]); | ||
|
||
return ( | ||
<AccordionContext.Provider value={accordionContextValue}> | ||
{children} | ||
</AccordionContext.Provider> | ||
); | ||
} |
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,61 @@ | ||
import { type ReactNode, useEffect, useRef } from "react"; | ||
|
||
import { useAccordion } from "./AccordionContextProvider"; | ||
|
||
interface AccordionDetailsProps { | ||
className?: string; | ||
children: ReactNode; | ||
} | ||
|
||
export default function AccordionDetails({ | ||
className, | ||
children, | ||
}: AccordionDetailsProps) { | ||
const detailsRef = useRef<HTMLDetailsElement>(null); | ||
const accordionContext = useAccordion(); | ||
if (!accordionContext) { | ||
throw new Error( | ||
"Accordion.Details 컴포넌트는 Accordion 컴포넌트로 래핑해야 합니다.", | ||
); | ||
} | ||
|
||
const { width, open, onChange } = accordionContext; | ||
|
||
useEffect(() => { | ||
if (!detailsRef.current) { | ||
return undefined; | ||
} | ||
|
||
const $details = detailsRef.current; | ||
|
||
const handleBeforeMatch = (event: Event) => { | ||
const { target } = event; | ||
if (!(target instanceof HTMLDetailsElement)) { | ||
return; | ||
} | ||
|
||
const detailsOpen = target.open; | ||
if (detailsOpen === open) { | ||
return; | ||
} | ||
|
||
onChange(detailsOpen); | ||
}; | ||
|
||
$details.addEventListener("toggle", handleBeforeMatch); | ||
return () => { | ||
$details.removeEventListener("toggle", handleBeforeMatch); | ||
}; | ||
}, [onChange, open]); | ||
|
||
return ( | ||
<details | ||
ref={detailsRef} | ||
style={{ width }} | ||
open={open} | ||
className={className} | ||
> | ||
{children} | ||
</details> | ||
); | ||
} |
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,57 @@ | ||
import { MouseEventHandler, type ReactNode } from "react"; | ||
|
||
import classnames from "../../utils/classnames"; | ||
|
||
import * as styles from "./Accordion.css"; | ||
import { | ||
type AccordionContextType, | ||
useAccordion, | ||
} from "./AccordionContextProvider"; | ||
import ChevronIcon from "./ChevronIcon/ChevronIcon"; | ||
|
||
interface AccordionSummaryProps { | ||
color?: "black" | "grey"; | ||
size?: "md" | "sm"; | ||
children: ReactNode | RenderComponentType; | ||
} | ||
|
||
type RenderComponentType = (props: AccordionContextType) => ReactNode; | ||
|
||
export default function AccordionSummary({ | ||
color = "black", | ||
size = "md", | ||
children, | ||
}: AccordionSummaryProps) { | ||
const accordionContext = useAccordion(); | ||
if (!accordionContext) { | ||
throw new Error( | ||
"Accordion.Summary 컴포넌트는 Accordion 컴포넌트로 래핑해야 합니다.", | ||
); | ||
} | ||
|
||
const summaryStyle = classnames( | ||
styles.summaryText[size], | ||
styles.summaryColor[color], | ||
styles.summaryContainer[size], | ||
); | ||
|
||
const { open, onChange } = accordionContext; | ||
const chevronType = open ? "up" : "down"; | ||
|
||
const handleChange: MouseEventHandler = (event) => { | ||
event.preventDefault(); | ||
onChange(!open); | ||
}; | ||
|
||
return ( | ||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions | ||
<summary className={summaryStyle} onClick={handleChange}> | ||
<div> | ||
{children instanceof Function ? children(accordionContext) : children} | ||
</div> | ||
<div> | ||
<ChevronIcon type={chevronType} size={size} /> | ||
</div> | ||
</summary> | ||
); | ||
} |
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,22 @@ | ||
import { style, styleVariants } from "@vanilla-extract/css"; | ||
|
||
import { border, flexCenter } from "../../../design-token/utils.css"; | ||
|
||
export const containerBase = style([ | ||
flexCenter, | ||
border.all, | ||
{ | ||
borderRadius: "50%", | ||
}, | ||
]); | ||
|
||
export const containerVariants = styleVariants({ | ||
sm: { | ||
width: 18, | ||
height: 18, | ||
}, | ||
md: { | ||
width: 25, | ||
height: 25, | ||
}, | ||
}); |
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,36 @@ | ||
import { BsChevronDown, BsChevronUp } from "react-icons/bs"; | ||
|
||
import color from "../../../design-token/color"; | ||
import classnames from "../../../utils/classnames"; | ||
|
||
import * as styles from "./ChevronIcon.css"; | ||
|
||
interface ChevronIconProps { | ||
size: "md" | "sm"; | ||
type: keyof typeof chevronIconMap; | ||
} | ||
|
||
export default function ChevronIcon({ type, size }: ChevronIconProps) { | ||
const containerStyle = classnames( | ||
styles.containerBase, | ||
styles.containerVariants[size], | ||
); | ||
|
||
const Chevron = chevronIconMap[type]; | ||
|
||
return ( | ||
<div className={containerStyle}> | ||
<Chevron color={color.$scale.grey600} size={chevronSizeMap[size]} /> | ||
</div> | ||
); | ||
} | ||
|
||
const chevronIconMap = { | ||
up: BsChevronUp, | ||
down: BsChevronDown, | ||
}; | ||
|
||
const chevronSizeMap = { | ||
sm: 10, | ||
md: 14, | ||
}; |
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,3 @@ | ||
import ChevronIcon from "./ChevronIcon"; | ||
|
||
export default ChevronIcon; |
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,2 @@ | ||
export { default as Accordion } from "./Accordion"; | ||
export { useAccordion } from "./AccordionContextProvider"; |
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,40 @@ | ||
import { style, styleVariants } from "@vanilla-extract/css"; | ||
|
||
import color from "../../design-token/color"; | ||
import typography from "../../design-token/typography"; | ||
|
||
export const badgeBase = style([ | ||
typography.$semantic.caption2Regular, | ||
{ | ||
height: 22, | ||
padding: "3px 7px", | ||
borderRadius: 5, | ||
}, | ||
]); | ||
|
||
export const badgeVariants = styleVariants({ | ||
orange: { | ||
color: color.$semantic.badgeOrange, | ||
backgroundColor: color.$semantic.badgeOrangeBg, | ||
}, | ||
yellow: { | ||
color: color.$semantic.badgeYellow, | ||
backgroundColor: color.$semantic.badgeYellowBg, | ||
}, | ||
green: { | ||
color: color.$semantic.badgeGreen, | ||
backgroundColor: color.$semantic.badgeGreenBg, | ||
}, | ||
teal: { | ||
color: color.$semantic.badgeTeal, | ||
backgroundColor: color.$semantic.badgeTealBg, | ||
}, | ||
blue: { | ||
color: color.$semantic.badgeBlue, | ||
backgroundColor: color.$semantic.badgeBlueBg, | ||
}, | ||
purple: { | ||
color: color.$semantic.badgePurple, | ||
backgroundColor: color.$semantic.badgePurpleBg, | ||
}, | ||
}); |
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,24 @@ | ||
import { ReactNode } from "react"; | ||
|
||
import classnames from "../../utils/classnames"; | ||
import { objectKeys } from "../../utils/types"; | ||
|
||
import { badgeVariants } from "./Badge.css"; | ||
import * as styles from "./Badge.css"; | ||
|
||
export type BadgeVariantType = keyof typeof badgeVariants; | ||
|
||
export interface BadgeProps { | ||
variant: BadgeVariantType; | ||
children: ReactNode; | ||
} | ||
|
||
export const badgeVariantList = objectKeys(badgeVariants); | ||
|
||
export function Badge({ variant, children }: BadgeProps) { | ||
const badgeStyle = classnames( | ||
styles.badgeBase, | ||
styles.badgeVariants[variant], | ||
); | ||
return <span className={badgeStyle}>{children}</span>; | ||
} |
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 @@ | ||
export { Badge, badgeVariantList } from "./Badge"; |
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
Oops, something went wrong.