cashdoc-cms-design-system 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,107 @@
1
+ # Cashdoc CMS Design System
1
2
 
3
+ Cashdoc CMS용 디자인 시스템 컴포넌트 라이브러리 [Storybook](https://cashdoc-cms-design-system.vercel.app/?path=/docs/components-button--docs)
4
+
5
+ ## 기술 스택
6
+
7
+ - **React 18** - UI 라이브러리
8
+ - **TypeScript** - 타입 안전성
9
+ - **TailwindCSS** - 스타일링
10
+ - **Radix UI** - 접근성 프리미티브
11
+ - **Framer Motion** - 애니메이션
12
+ - **Vite** - 빌드 도구
13
+ - **Storybook** - 컴포넌트 문서화
14
+
15
+ ## 설치
16
+
17
+ ```bash
18
+ pnpm install cashdoc-cms-design-system
19
+ ```
20
+
21
+ ## 사용법
22
+
23
+ 프로젝트 최상단에서 cashdoc-cms-design-system의 `style.css` 파일을 import 후 사용하면 됩니다.
24
+
25
+ ```tsx
26
+ import "cashdoc-cms-design-system/dist/style.css";
27
+ ```
28
+
29
+ ```tsx
30
+ import { Button, Modal, DatePicker } from "cashdoc-cms-design-system";
31
+
32
+ function App() {
33
+ return <Button variant="default">버튼</Button>;
34
+ }
35
+ ```
36
+
37
+ ## 컴포넌트 리스트
38
+
39
+ ### Form
40
+
41
+ - `Button` - 기본 버튼
42
+ - `Checkbox` - 체크박스
43
+ - `RadioButton` - 라디오 버튼
44
+ - `Switch` - 토글 스위치
45
+ - `TextInput` - 텍스트 입력 필드
46
+ - `TagInput` - 태그 입력 필드
47
+
48
+ ### Data Input
49
+
50
+ - `DatePicker` - 날짜 선택
51
+ - `DateRangePicker` - 기간 선택
52
+ - `Dropdown` - 드롭다운 메뉴
53
+ - `Select` - 선택 입력
54
+ - `Combobox` - 검색 가능한 선택
55
+
56
+ ### Feedback
57
+
58
+ - `Modal` - 모달 다이얼로그
59
+ - `ConfirmModal` - 확인 모달
60
+ - `DeleteModal` - 삭제 확인 모달
61
+ - `ErrorModal` - 에러 알림
62
+ - `SuccessModal` - 성공 알림
63
+ - `WarningModal` - 경고 알림
64
+ - `Toast` - 토스트 알림
65
+ - `LoadingCircle` - 로딩 인디케이터
66
+
67
+ ### Navigation
68
+
69
+ - `SideNavigation` - 사이드바 네비게이션
70
+ - `Popover` - 팝오버 메뉴
71
+
72
+ ### Display
73
+
74
+ - `Text` - 타이포그래피
75
+ - `Icons` - 아이콘 세트
76
+
77
+ ## 개발
78
+
79
+ ### 로컬 개발 서버
80
+
81
+ ```bash
82
+ pnpm dev
83
+ ```
84
+
85
+ ### Storybook 실행
86
+
87
+ ```bash
88
+ pnpm storybook
89
+ ```
90
+
91
+ ### 빌드
92
+
93
+ ```bash
94
+ pnpm build
95
+ ```
96
+
97
+ ### 타입 체크
98
+
99
+ ```bash
100
+ pnpm type-check
101
+ ```
102
+
103
+ ### 린트
104
+
105
+ ```bash
106
+ pnpm lint
107
+ ```
@@ -0,0 +1,106 @@
1
+ import { default as React } from 'react';
2
+
3
+ export interface PaginationProps {
4
+ currentPage: number;
5
+ totalPages: number;
6
+ onPageChange: (page: number) => void;
7
+ siblingCount?: number;
8
+ showPrevNext?: boolean;
9
+ disabled?: boolean;
10
+ className?: string;
11
+ }
12
+ /**
13
+ * 사용자가 여러 페이지로 나뉜 콘텐츠를 탐색할 수 있게 하는 페이지네이션 컴포넌트입니다.
14
+ *
15
+ * {@link Pagination}은 이전/다음 버튼과 페이지 번호를 제공하며,
16
+ * 많은 페이지가 있을 때 중간 페이지를 생략(ellipsis)하여 UI를 깔끔하게 유지합니다.
17
+ *
18
+ * ## When (언제 사용해야 하는가)
19
+ *
20
+ * **사용해야 하는 경우:**
21
+ * - **긴 목록**: 많은 항목을 여러 페이지로 나누어 표시할 때
22
+ * - **검색 결과**: 검색 결과가 여러 페이지에 걸쳐 있을 때
23
+ * - **데이터 테이블**: 대량의 데이터를 페이지 단위로 보여줄 때
24
+ * - **명확한 페이지 구분**: 사용자가 특정 페이지로 직접 이동할 필요가 있을 때
25
+ *
26
+ * **사용하지 말아야 하는 경우:**
27
+ * - **무한 스크롤**: 지속적으로 콘텐츠가 로드되는 피드 형태가 더 적절한 경우
28
+ * - **적은 항목**: 한 페이지에 모두 표시할 수 있는 소량의 데이터
29
+ * - **단계별 프로세스**: 순차적인 단계를 나타낼 때는 Stepper 컴포넌트 사용
30
+ *
31
+ * ## Layout behavior
32
+ *
33
+ * - **Responsive**: 모바일에서는 siblingCount를 줄여 더 적은 페이지 번호를 표시하는 것을 권장
34
+ * - **Centered**: 일반적으로 페이지 하단 중앙에 배치
35
+ * - **Ellipsis**: 많은 페이지가 있을 때 자동으로 중간 페이지를 생략 (...으로 표시)
36
+ *
37
+ * ## Usage guidelines
38
+ *
39
+ * ### ✅ Do (권장 사항)
40
+ *
41
+ * - **적절한 페이지당 항목 수**: 10-50개 사이가 적절 (콘텐츠 유형에 따라 조정)
42
+ * - **현재 페이지 명확히 표시**: 활성 페이지는 시각적으로 구분되어야 함
43
+ * - **충분한 클릭 영역**: 모바일에서도 쉽게 탭할 수 있도록 버튼 크기 유지
44
+ * - **첫/마지막 페이지 비활성화**: 이동할 수 없는 경우 버튼을 비활성화하여 명확히 표시
45
+ *
46
+ * ### 🚫 Don't (주의/금지 사항)
47
+ *
48
+ * - **너무 많은 페이지 번호**: siblingCount를 너무 크게 설정하지 마세요
49
+ * - **불명확한 상태**: 로딩 중이거나 에러 상태일 때도 적절한 피드백 제공 필요
50
+ *
51
+ * ## Accessibility
52
+ *
53
+ * - **ARIA Labels**: 각 버튼에 명확한 레이블 제공 (aria-label, aria-current)
54
+ * - **Keyboard Navigation**: Tab 키로 버튼 간 이동, Enter/Space로 페이지 변경
55
+ * - **Screen Reader**: 현재 페이지와 전체 페이지 수를 읽어주도록 설정
56
+ * - **Disabled State**: 비활성화된 버튼은 포커스할 수 없도록 처리
57
+ *
58
+ * ## Example
59
+ *
60
+ * {@tool snippet}
61
+ * 기본적인 페이지네이션 사용:
62
+ *
63
+ * ```tsx
64
+ * const [currentPage, setCurrentPage] = useState(1);
65
+ * const totalPages = 10;
66
+ *
67
+ * <Pagination
68
+ * currentPage={currentPage}
69
+ * totalPages={totalPages}
70
+ * onPageChange={setCurrentPage}
71
+ * />
72
+ * ```
73
+ * {@end-tool}
74
+ *
75
+ * {@tool snippet}
76
+ * 많은 페이지와 커스텀 siblingCount:
77
+ *
78
+ * ```tsx
79
+ * <Pagination
80
+ * currentPage={25}
81
+ * totalPages={100}
82
+ * siblingCount={2}
83
+ * onPageChange={handlePageChange}
84
+ * />
85
+ * // 결과: 1 ... 23 24 25 26 27 ... 100
86
+ * ```
87
+ * {@end-tool}
88
+ *
89
+ * {@tool snippet}
90
+ * 비활성화 상태:
91
+ *
92
+ * ```tsx
93
+ * <Pagination
94
+ * currentPage={5}
95
+ * totalPages={10}
96
+ * onPageChange={handlePageChange}
97
+ * disabled={isLoading}
98
+ * />
99
+ * ```
100
+ * {@end-tool}
101
+ *
102
+ * See also:
103
+ *
104
+ * - {@link Button}, 단일 버튼 컴포넌트
105
+ */
106
+ export declare const Pagination: React.ForwardRefExoticComponent<PaginationProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,2 @@
1
+ export { Pagination } from './Pagination';
2
+ export type { PaginationProps } from './Pagination';
@@ -0,0 +1,110 @@
1
+ import { default as React } from 'react';
2
+
3
+ export interface TimePickerProps {
4
+ value?: string;
5
+ onChange?: (time: string) => void;
6
+ label?: string;
7
+ placeholder?: string;
8
+ format?: "24h" | "12h";
9
+ disabled?: boolean;
10
+ error?: boolean;
11
+ errorMessage?: string;
12
+ helperText?: string;
13
+ className?: string;
14
+ minuteStep?: number;
15
+ showIcon?: boolean;
16
+ }
17
+ /**
18
+ * 사용자가 시간을 선택할 수 있게 하는 컴포넌트입니다.
19
+ *
20
+ * {@link TimePicker}는 직관적인 스크롤 인터페이스를 통해 시간과 분을 선택할 수 있으며,
21
+ * 24시간 형식과 12시간(AM/PM) 형식을 모두 지원합니다.
22
+ *
23
+ * `@radix-ui/react-popover`를 기반으로 구현되었으며, 사용자가 잘못된 시간을 입력하는 것을 방지합니다.
24
+ *
25
+ * ## When (언제 사용해야 하는가)
26
+ *
27
+ * **사용해야 하는 경우:**
28
+ * - **특정 시간 입력**: 예약 시간, 알림 시간, 업무 시작/종료 시간 등을 선택해야 할 때
29
+ * - **정확한 시간 선택**: 사용자가 직접 타이핑하여 발생할 수 있는 형식 오류를 방지하고 싶을 때
30
+ * - **제한된 간격 선택**: 5분, 10분, 15분 단위로만 선택이 필요한 경우 (minuteStep 사용)
31
+ *
32
+ * **사용하지 말아야 하는 경우:**
33
+ * - **대략적인 시간**: '오전', '오후', '저녁' 등 상대적인 시간 선택이 필요한 경우 `Dropdown`이나 `RadioButton`이 더 적절할 수 있습니다.
34
+ * - **초 단위 정밀도**: 현재는 시간과 분까지만 지원하므로, 초 단위가 필요한 경우 다른 컴포넌트를 고려하세요.
35
+ *
36
+ * ## Layout behavior
37
+ *
38
+ * - **Popover 기반**: 클릭 시 입력창 아래에 시간 선택 팝오버가 나타나며, 화면 공간을 효율적으로 사용합니다.
39
+ * - **스크롤 선택**: 시간과 분을 각각 스크롤하여 선택할 수 있어 직관적입니다.
40
+ * - **Full Width**: `className`을 통해 부모 요소의 너비에 맞게 조절할 수 있습니다.
41
+ *
42
+ * ## Usage guidelines
43
+ *
44
+ * ### ✅ Do (권장 사항)
45
+ *
46
+ * - **적절한 Format**: 사용자가 익숙한 형식(한국: 24시간, 미국: 12시간)을 선택하세요.
47
+ * - **Minute Step 활용**: 일정 간격으로만 선택이 필요한 경우 `minuteStep`을 활용하여 UX를 개선하세요.
48
+ * - **레이블 및 헬퍼 텍스트**: 입력 항목의 용도를 명확히 하고, 필요한 경우 보충 설명을 제공하세요.
49
+ *
50
+ * ### 🚫 Don't (주의/금지 사항)
51
+ *
52
+ * - **Read-only 입력**: 사용자가 직접 타이핑하여 입력하는 기능은 지원하지 않으므로, 반드시 UI를 통해 선택하도록 안내하세요.
53
+ * - **과도한 Step**: `minuteStep`이 너무 크면 정확한 시간을 선택하기 어려울 수 있습니다.
54
+ *
55
+ * ## Accessibility
56
+ *
57
+ * - **Keyboard Navigation**: 팝오버는 키보드로 열고 닫을 수 있으며, `Esc` 키로 취소할 수 있습니다.
58
+ * - **Focus Management**: 시간 선택기가 열려 있는 동안 포커스가 적절히 관리됩니다.
59
+ * - **Aria Labels**: 각 버튼에는 스크린 리더를 위한 적절한 레이블이 포함되어 있습니다.
60
+ *
61
+ * ## Example
62
+ *
63
+ * {@tool snippet}
64
+ * 기본적인 시간 선택 예시 (24시간 형식):
65
+ *
66
+ * ```tsx
67
+ * const [time, setTime] = useState("");
68
+ *
69
+ * <TimePicker
70
+ * label="출근 시간"
71
+ * value={time}
72
+ * onChange={setTime}
73
+ * placeholder="시간을 선택하세요"
74
+ * />
75
+ * ```
76
+ * {@end-tool}
77
+ *
78
+ * {@tool snippet}
79
+ * 12시간 형식 및 15분 단위 선택:
80
+ *
81
+ * ```tsx
82
+ * <TimePicker
83
+ * label="회의 시간"
84
+ * format="12h"
85
+ * minuteStep={15}
86
+ * value="2:30 PM"
87
+ * onChange={setTime}
88
+ * />
89
+ * ```
90
+ * {@end-tool}
91
+ *
92
+ * {@tool snippet}
93
+ * 에러 상태:
94
+ *
95
+ * ```tsx
96
+ * <TimePicker
97
+ * label="마감 시간"
98
+ * error={true}
99
+ * errorMessage="업무 시간(9:00-18:00) 내에서 선택해주세요"
100
+ * />
101
+ * ```
102
+ * {@end-tool}
103
+ *
104
+ * See also:
105
+ *
106
+ * - {@link DatePicker}, 날짜를 선택해야 하는 경우
107
+ * - {@link DateRangePicker}, 날짜 범위를 선택해야 하는 경우
108
+ * - {@link TextInput}, 단순한 텍스트 입력이 필요한 경우
109
+ */
110
+ export declare const TimePicker: React.ForwardRefExoticComponent<TimePickerProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,2 @@
1
+ export { TimePicker } from './TimePicker';
2
+ export type { TimePickerProps } from './TimePicker';
@@ -7,9 +7,11 @@ export * from './Text';
7
7
  export * from './TextInput';
8
8
  export * from './DatePicker';
9
9
  export * from './DateRangePicker';
10
+ export * from './TimePicker';
10
11
  export * from './Switch';
11
12
  export * from './RadioButton';
12
13
  export * from './SideNavigation';
14
+ export * from './Pagination';
13
15
  export * from './Checkbox';
14
16
  export * from './Modal';
15
17
  export * from './Toast';