diff --git a/package.json b/package.json index 62c8352c..43265d5e 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "dev": "vite", "build": "vite build", "serve": "vite preview", + "story": "ladle serve", "lint": "eslint src" }, "eslintConfig": { diff --git a/src/component/utils/Accordion.stories.tsx b/src/component/utils/Accordion.stories.tsx new file mode 100644 index 00000000..725eacfd --- /dev/null +++ b/src/component/utils/Accordion.stories.tsx @@ -0,0 +1,85 @@ +import { useState } from "react"; +import { Story } from "@ladle/react"; +import Accordion, { Props } from "./Accordion"; + +type AccordionStory = Story; + +const argTypes: AccordionStory["argTypes"] = { + summaryIconType: { + options: ["plus", "arrow"], + control: { type: "inline-radio" }, + defaultValue: "arrow", + }, + summaryIconPosition: { + options: ["start", "end"], + control: { type: "inline-radio" }, + defaultValue: "start", + }, +}; + +export const 활용법: AccordionStory = ({ ...args }) => { + const [isOpened, setIsOpened] = useState(false); + + return ( +
+

Accordion

+

토글방식의 UI를 위한 컴포넌트

+

클릭하면 접혀있던/펼쳐져 있던 내용을 확인할 수 있습니다.

+ + 처음부터 열려있도록 설정할 수도 있습니다

} + detailUI={

펼쳐있을 때만 보이는 부분

} + /> +

활용방법

+ +

+ 느끼셨다시피 기본 스타일링은 없다시피 합니다. 필요에 따라 + className등으로 설정해주세요 +

+

+ 대표적으로 이용안내 + 페이지에서 활용하는 컴포넌트입니다 +

+

+ } + /> + +

+ 기타 활용 : 일괄접기 +

+ setIsOpened(!isOpened)} + /> + + +
+ ); +}; + +활용법.argTypes = argTypes; diff --git a/src/component/utils/Accordion.tsx b/src/component/utils/Accordion.tsx index 39c65ba7..1e0c3727 100644 --- a/src/component/utils/Accordion.tsx +++ b/src/component/utils/Accordion.tsx @@ -5,7 +5,7 @@ import Minus from "../../asset/img/plus_icon_on.svg"; import Arrow from "../../asset/img/arrow_right_black.svg"; import "../../asset/css/Accordion.css"; -type AccordionProp = { +export type Props = { initialOpened?: boolean; summaryButtonClassName?: string; summaryIconClassName?: string; @@ -17,6 +17,7 @@ type AccordionProp = { onChange?: (isOpened: boolean) => void; fixed?: boolean; }; + const Accordion = ({ initialOpened = false, summaryIconType, @@ -28,7 +29,7 @@ const Accordion = ({ dependencyOpened, onChange, fixed = false, -}: AccordionProp) => { +}: Props) => { const [isOpened, setIsOpened] = useState(initialOpened); useEffect(() => { diff --git a/src/component/utils/Carousel.stories.tsx b/src/component/utils/Carousel.stories.tsx new file mode 100644 index 00000000..eb803a0f --- /dev/null +++ b/src/component/utils/Carousel.stories.tsx @@ -0,0 +1,130 @@ +import { Story } from "@ladle/react"; +import Carousel from "./Carousel"; +import { Props } from "./CarouselRoot"; + +type CarouselStory = Story; + +const exampleArray = Array.from({ length: 10 }, (_, i) => ({ id: i + 1 })); +const exampleItemSize = 100; +// 리스트 내부에 들어갈 UI 컴포넌트 예시 +const ExampleItemUi = ({ item }: { item: { id: number } }) => ( +
+ {item.id} +
+); + +export const 기본활용법: CarouselStory = () => ( + <> +

Carousel

+

무한 회전하는 UI 컴포넌트

+

기본으로 애니메이션이 적용된 리스트

+

- 무한회전을 위한 설정 자동으로 적용됨 (마지막요소 다음에 첫요소 등)

+

- 마우스 hover시 일시 정지 및 재시작 기능 포함

+

- 메인페이지 인기도서, 인기검색어 등에 활용되고 있음

+ + + + +); + +export const 조합활용: CarouselStory = () => ( + <> +

Carousel

+

다양한 컴포넌트를 조합하여 활용

+

컴포넌트를 조합하여 다양한 UI를 구성할 수 있음

+

필수 컴포넌트인 Root와 List외의 컴포넌트는 필요에 따라 추가할 수 있음

+

Root로 감싸있기만 하면 컴포넌트의 위치 및 순서, 조합은 자유롭게 선택

+

+ cf. + + Compound Pattern + +

+ + + + + + + + + + + + + + + + +); +export const 컴포넌트상세: CarouselStory = () => ( + <> +

Carousel.Root

+

필수 컴포넌트, 전체를 감싸는 context 제공

+ +

Carousel.List

+

필수 컴포넌트, 리스트와 각 요소 UI 표현

+ +

Carousel.Container

+

리스트를 감싸는 컴포넌트 (생략가능)

+

특정 영역만 보이도록 설정하기 위함

+ + + + + + +

Carousel.Prev & Carousel.Next

+

리스트 이전/다음 요소로 넘기기 위한 버튼 컴포넌트 (생략가능)

+ + 다음 + + +

이전

+ + 이 안에 다양한 UI를 넣어 꾸밀 수 있어요 + +
+
+ +

Carousel.Pagination

+

리스트 페이지네이션 용 컴포넌트 (생략가능)

+

+ 리스트의 현재 위치를 나타내거나 특정 위치로 이동하도록 설정가능 (생략가능) +

+

Root에 저장된 page, setPage, lastPage를 Props로 받아 UI를 구성

+

- page : 현재 리스트의 위치

+

- setPage : 특정 위치로 이동시키는 함수

+ + + ( + <> + {exampleArray.map(item => { + const isCurrentPage = item.id === page; + return ( + + ); + })} + + )} + /> + + +); diff --git a/src/component/utils/CarouselRoot.tsx b/src/component/utils/CarouselRoot.tsx index dacac439..4e62d26a 100644 --- a/src/component/utils/CarouselRoot.tsx +++ b/src/component/utils/CarouselRoot.tsx @@ -4,7 +4,7 @@ import { useInterval } from "~/hook/useInterval"; import { CarouselContext } from "~/component/utils/Carousel"; import "~/asset/css/Carousel.css"; -type Props = { +export type Props = { length: number; itemSize?: number; itemCount?: number; diff --git a/src/component/utils/Tooltip.stories.tsx b/src/component/utils/Tooltip.stories.tsx new file mode 100644 index 00000000..2010ee1d --- /dev/null +++ b/src/component/utils/Tooltip.stories.tsx @@ -0,0 +1,27 @@ +import { Story } from "@ladle/react"; +import Tooltip, { Props } from "./Tooltip"; + +type TooltipStory = Story; + +export const 활용법: TooltipStory = () => ( + <> + {/* 툴팁 컴포넌트 활용에 필요, App.tsx에 내장되어 있음 */} +
+

Tooltip

+

UI의 간단한 설명을 추가하기 위한 컴포넌트

+

마우스 hover시 설명을 확인할 수 있습니다.

+ + 툴팁이 나올 요소입니다 + +
+ + 하위요소 위치에 바로 아래에 툴팁이 나옵니다 + +
+ +); diff --git a/src/component/utils/Tooltip.tsx b/src/component/utils/Tooltip.tsx index 8dca182a..19e59e33 100644 --- a/src/component/utils/Tooltip.tsx +++ b/src/component/utils/Tooltip.tsx @@ -2,13 +2,13 @@ import { ReactNode, useState } from "react"; import { createPortal } from "react-dom"; import { useBound } from "~/hook/useBound"; -type TooltipProps = { +export type Props = { className?: string; children: ReactNode; description: string; }; -const Tooltip = ({ children, description, className }: TooltipProps) => { +const Tooltip = ({ children, description, className }: Props) => { const [isDisplayed, setDisplayed] = useState(false); const { boundInfo, targetRef } = useBound({ hasResizeEvent: true,