Skip to content

Commit

Permalink
chore: import 경로 정리
Browse files Browse the repository at this point in the history
Co-Authored-By: 박유현 <[email protected]>
  • Loading branch information
yunchaehyun and YuHyun-P committed Jan 25, 2024
1 parent 2c24bc3 commit 8937a44
Show file tree
Hide file tree
Showing 45 changed files with 870 additions and 4 deletions.
43 changes: 43 additions & 0 deletions src/components/Accordion/Accordion.css.ts
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,
},
],
});
26 changes: 26 additions & 0 deletions src/components/Accordion/Accordion.tsx
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;
56 changes: 56 additions & 0 deletions src/components/Accordion/AccordionContextProvider.tsx
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>
);
}
61 changes: 61 additions & 0 deletions src/components/Accordion/AccordionDetails.tsx
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>
);
}
57 changes: 57 additions & 0 deletions src/components/Accordion/AccordionSummary.tsx
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>
);
}
22 changes: 22 additions & 0 deletions src/components/Accordion/ChevronIcon/ChevronIcon.css.ts
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,
},
});
36 changes: 36 additions & 0 deletions src/components/Accordion/ChevronIcon/ChevronIcon.tsx
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,
};
3 changes: 3 additions & 0 deletions src/components/Accordion/ChevronIcon/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ChevronIcon from "./ChevronIcon";

export default ChevronIcon;
2 changes: 2 additions & 0 deletions src/components/Accordion/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Accordion } from "./Accordion";
export { useAccordion } from "./AccordionContextProvider";
40 changes: 40 additions & 0 deletions src/components/Badge/Badge.css.ts
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,
},
});
24 changes: 24 additions & 0 deletions src/components/Badge/Badge.tsx
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>;
}
1 change: 1 addition & 0 deletions src/components/Badge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Badge, badgeVariantList } from "./Badge";
6 changes: 3 additions & 3 deletions src/components/Button/Button.css.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { style, styleVariants } from "@vanilla-extract/css";

import color from "../../tokens/color";
import typography from "../../tokens/typography";
import { borderRadius } from "../../tokens/utils.css";
import color from "../../design-token/color";
import typography from "../../design-token/typography";
import { borderRadius } from "../../design-token/utils.css";

export const buttonBase = style([
typography.$semantic.title4Regular,
Expand Down
Loading

0 comments on commit 8937a44

Please sign in to comment.