@pop-kit/okcancel 0.0.0 → 0.1.0

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
@@ -2,277 +2,149 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/@pop-kit/okcancel.svg)](https://www.npmjs.com/package/@pop-kit/okcancel)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![Live Demo](https://img.shields.io/badge/Live-Demo-blue?style=flat&logo=stackblitz)](https://stackblitz.com/edit/vitejs-vite-wszi61bn?file=src%2FApp.tsx)
6
5
 
7
- **React + TypeScript 기반의 비동기 UI 인터랙션 라이브러리 (Headless & Logic-First)**입니다.
8
- `confirm`, `alert` 뿐만 아니라 다양한 오버레이(Sheet, Toast 등)를 `await` 함수 호출로 제어할 수 있습니다.
6
+ **React 기반의 UI-Agnostic 비동기 오버레이 관리자**입니다.
7
+ `confirm`, `alert` 로직을 비즈니스 로직에서 분리하여 `await` 줄로 우아하게 제어하세요.
8
+
9
+ ---
9
10
 
10
11
  ## ✨ 주요 특징
11
12
 
12
- - **Promise 기반 로직** - `await confirm()` 줄로 복잡한 상태 관리 대체
13
- - **Headless 아키텍처** - UI와 로직의 완전한 분리, Shadcn/MUI 어떤 스타일과도 호환
14
- - **DX (개발자 경험) 중심** - 자동 로딩 상태 관리, TypeScript 지원
15
- - **AI-Native** - Cursor, Copilot AI가 코드를 작성하기 쉬운 구조
13
+ - **UI-Agnostic (Headless)** - UI를 강제하지 않습니다. shadcn/ui, MUI, 또는 직접 만든 컴포넌트 등 무엇이든 주입하여 사용할 수 있습니다.
14
+ - **Promise 기반 흐름** - 상태 지옥(isOpen, setOpen)에서 벗어나 `const ok = await confirm()` 코드를 통해 선형적인 로직을 작성합니다.
15
+ - **IntelliSense 지원** - `confirm.destructive()`, `alert.success()` 사용자 정의 변형(Variant)에 대한 완벽한 자동완성을 지원합니다.
16
+ - **shadcn/ui 프리셋 제공** - 별도의 패키지 설치 없이 CLI 명령어로 프로젝트에 바로 다이얼로그 프리셋을 추가할 수 있습니다.
17
+
18
+ ---
16
19
 
17
20
  ## 📦 설치
18
21
 
22
+ ### 1. Core 라이브러리 설치
23
+
19
24
  ```bash
20
25
  npm install @pop-kit/okcancel
21
26
  ```
22
27
 
23
- ## 🎮 Live Demo
28
+ ### 2. shadcn/ui 프리셋 추가 (선택 사항)
24
29
 
25
- [**StackBlitz에서 바로 체험하기**](https://stackblitz.com/edit/vitejs-vite-wszi61bn?file=src%2FApp.tsx)
30
+ 가장 인기 있는 shadcn/ui 기반의 프리셋을 프로젝트에 즉시 추가할 수 있습니다.
26
31
 
27
- ## 🚀 빠른 시작
32
+ ```bash
33
+ npx shadcn@latest add "https://raw.githubusercontent.com/[USER]/react-okcancel/main/registry.json"
34
+ ```
28
35
 
29
- ```tsx
30
- import { OkCancelProvider, useOkCancel } from 'react-okcancel';
36
+ _설치 후 `components/ui/ok-cancel/` 폴더에 다이얼로그 컴포넌트들이 생성됩니다._
31
37
 
32
- function MyComponent() {
33
- const { confirm, alert } = useOkCancel();
34
-
35
- const handleDelete = async () => {
36
- const confirmed = await confirm({
37
- title: '삭제 확인',
38
- description: '정말로 이 항목을 삭제하시겠습니까?',
39
- confirmText: '삭제',
40
- cancelText: '취소',
41
- });
38
+ ---
42
39
 
43
- if (confirmed) {
44
- // 삭제 로직
45
- await alert({
46
- title: '완료',
47
- description: '항목이 성공적으로 삭제되었습니다.',
48
- });
49
- }
50
- };
40
+ ## 🚀 사용 가이드 (Usage)
51
41
 
52
- return <button onClick={handleDelete}>항목 삭제</button>;
53
- }
42
+ ### 1. Provider 설정 (Setup)
43
+
44
+ `OkCancelProvider`에 UI 컴포넌트를 주입하여 초기화합니다. `as const`를 사용하여 컴포넌트 맵을 정의하면 나중에 호출할 때 완벽한 자동완성(IntelliSense)이 지원됩니다.
45
+
46
+ ```tsx
47
+ import { OkCancelProvider } from '@pop-kit/okcancel';
48
+ import { ConfirmDialog, SimpleAlertDialog } from '@/components/ui/ok-cancel';
49
+
50
+ // 🛠️ 컴포넌트 구성 (단일 또는 여러 스타일 조합 가능)
51
+ const components = {
52
+ alert: SimpleAlertDialog, // 1. 단일 컴포넌트 주입
53
+ confirm: {
54
+ // 2. 여러 스타일(Variants) 주입
55
+ default: ConfirmDialog,
56
+ destructive: DestructiveConfirm, // confirm.destructive()로 호출 가능
57
+ },
58
+ } as const;
54
59
 
55
60
  function App() {
56
61
  return (
57
- <OkCancelProvider>
58
- <MyComponent />
62
+ <OkCancelProvider components={components}>
63
+ <YourApp />
59
64
  </OkCancelProvider>
60
65
  );
61
66
  }
62
67
  ```
63
68
 
64
- ## 📖 함수 설명
65
-
66
- ### `confirm(options: ConfirmOptions): Promise<boolean>`
67
-
68
- 확인/취소 버튼이 있는 확인 다이얼로그를 표시합니다.
69
+ ### 2. Hook 사용 (Hooks)
69
70
 
70
- #### 옵션
71
+ `useOkCancel`을 사용하여 사용자 인터랙션을 기다립니다. 기본적인 호출과 미리 정의한 변형(Variant) 호출이 모두 가능합니다.
71
72
 
72
- | 옵션 | 타입 | 기본값 | 설명 |
73
- | ------------------- | ----------- | -------- | ------------------------------------- |
74
- | `title` | `ReactNode` | - | 다이얼로그 제목 |
75
- | `description` | `ReactNode` | - | 다이얼로그 내용/메시지 |
76
- | `confirmText` | `ReactNode` | `'확인'` | 확인 버튼 텍스트 |
77
- | `cancelText` | `ReactNode` | `'취소'` | 취소 버튼 텍스트 |
78
- | `canCloseOnOverlay` | `boolean` | `true` | 오버레이 클릭으로 닫기 허용 |
79
- | `canCloseOnEsc` | `boolean` | `true` | Escape 키로 닫기 허용 |
80
- | `showCloseButton` | `boolean` | `false` | 오른쪽 상단 X 버튼 표시 |
81
- | `enableAnimation` | `boolean` | `true` | 다이얼로그 슬라이드 애니메이션 활성화 |
73
+ ```tsx
74
+ import { useOkCancel } from '@pop-kit/okcancel';
82
75
 
83
- #### 반환값
76
+ function MyComponent() {
77
+ // 정의한 components 타입을 전달하면 자동완성이 지원됩니다.
78
+ const { confirm, alert } = useOkCancel<typeof components>();
79
+
80
+ const handleAction = async () => {
81
+ // 💡 기본적인 confirm 호출
82
+ const ok = await confirm({
83
+ title: '삭제하시겠습니까?',
84
+ description: '이 작업은 되돌릴 수 없습니다.',
85
+ });
84
86
 
85
- - `true` 사용자가 확인 버튼을 클릭한 경우
86
- - `false` 사용자가 취소 버튼을 클릭하거나, Escape를 누르거나, 오버레이를 클릭한 경우
87
+ if (ok) {
88
+ // 💡 미리 정의한 'destructive' 변형 호출 (IntelliSense 지원)
89
+ const forceDelete = await confirm.destructive({
90
+ title: '정말 강제로 삭제할까요?',
91
+ confirmText: '강제 삭제',
92
+ });
87
93
 
88
- #### 예제
94
+ if (forceDelete) {
95
+ await deleteItem();
96
+ await alert({ title: '삭제 성공!' });
97
+ }
98
+ }
99
+ };
89
100
 
90
- ```tsx
91
- const result = await confirm({
92
- title: '저장 확인',
93
- description: (
94
- <div>
95
- <p>변경사항을 저장하시겠습니까?</p>
96
- <p>
97
- <strong>주의:</strong> 이 작업은 되돌릴 수 없습니다.
98
- </p>
99
- </div>
100
- ),
101
- confirmText: '저장',
102
- cancelText: '취소',
103
- canCloseOnOverlay: false, // 실수로 닫히는 것 방지
104
- showCloseButton: true, // X 버튼 표시
105
- enableAnimation: false, // 애니메이션 비활성화
106
- });
107
-
108
- if (result) {
109
- console.log('사용자가 저장을 확인했습니다');
110
- } else {
111
- console.log('사용자가 저장을 취소했습니다');
101
+ return <button onClick={handleAction}>삭제</button>;
112
102
  }
113
103
  ```
114
104
 
115
- ### `alert(options: AlertOptions): Promise<void>`
116
-
117
- 확인 버튼만 있는 알림 다이얼로그를 표시합니다.
118
-
119
- #### 옵션
120
-
121
- | 옵션 | 타입 | 기본값 | 설명 |
122
- | ------------------- | ----------- | -------- | ------------------------------------- |
123
- | `title` | `ReactNode` | - | 다이얼로그 제목 |
124
- | `description` | `ReactNode` | - | 다이얼로그 내용/메시지 |
125
- | `confirmText` | `ReactNode` | `'확인'` | 확인 버튼 텍스트 |
126
- | `canCloseOnOverlay` | `boolean` | `true` | 오버레이 클릭으로 닫기 허용 |
127
- | `canCloseOnEsc` | `boolean` | `true` | Escape 키로 닫기 허용 |
128
- | `showCloseButton` | `boolean` | `false` | 오른쪽 상단 X 버튼 표시 |
129
- | `enableAnimation` | `boolean` | `true` | 다이얼로그 슬라이드 애니메이션 활성화 |
105
+ ### 3. 커스텀 컴포넌트 만들기 (Custom Components)
130
106
 
131
- #### 반환값
107
+ Headless 라이브러리이므로 UI는 자유롭게 정의할 수 있습니다. 단, 라이브러리가 `await` 로직을 제어하기 위해 **반드시 제공된 Props 타입(`ConfirmDialogProps`, `AlertDialogProps`)을 사용해야 합니다.**
132
108
 
133
- - `undefined` 다이얼로그가 닫힐 때 (닫힌 방법과 관계없이)
109
+ #### 확인 다이얼로그 (`ConfirmDialogProps`)
134
110
 
135
- #### 예제
111
+ `onConfirm`과 `onCancel`을 모두 받아 `boolean` 결과를 반환합니다.
136
112
 
137
113
  ```tsx
138
- await alert({
139
- title: '성공',
140
- description: '파일이 성공적으로 업로드되었습니다.',
141
- confirmText: '확인',
142
- });
114
+ import type { ConfirmDialogProps } from '@pop-kit/okcancel';
143
115
 
144
- console.log('사용자가 알림을 확인했습니다');
145
- ```
146
-
147
- ## 🎨 커스터마이징
148
-
149
- CSS 변수를 재정의하여 모양을 커스터마이징할 수 있습니다:
150
-
151
- ```css
152
- :root {
153
- /* 다이얼로그 */
154
- --okcancel-dialog-bg: #fff;
155
- --okcancel-dialog-border-radius: 8px;
156
- --okcancel-dialog-shadow: 0 20px 25px -5px rgb(0 0 0 / 10%), 0 8px 10px -6px rgb(0 0 0 / 10%);
157
- --okcancel-dialog-max-width: none;
158
- --okcancel-dialog-min-width: auto;
159
- --okcancel-dialog-max-height: none;
160
- --okcancel-dialog-min-height: auto;
161
- --okcancel-dialog-width: 500px;
162
- --okcancel-dialog-height: max-content;
163
- --okcancel-dialog-padding: 16px 24px;
164
- --okcancel-dialog-border: none;
165
-
166
- /* 다이얼로그 콘텐츠 */
167
- --okcancel-content-padding: 0;
168
- --okcancel-content-gap: 8px;
169
- --okcancel-content-flex-direction: column;
170
- --okcancel-content-justify-content: center;
171
- --okcancel-content-align-items: normal;
172
- --okcancel-content-height: auto;
173
- --okcancel-content-max-height: none;
174
- --okcancel-content-min-height: 100px;
175
-
176
- /* 제목 */
177
- --okcancel-title-font-size: 20px;
178
- --okcancel-title-color: #222;
179
- --okcancel-title-font-weight: 600;
180
-
181
- /* 설명 */
182
- --okcancel-description-font-size: 16px;
183
- --okcancel-description-color: #8e8e8e;
184
- --okcancel-description-font-weight: 400;
185
-
186
- /* 버튼 컨테이너 */
187
- --okcancel-btn-box-padding: 10px 0;
188
- --okcancel-btn-box-gap: 12px;
189
- --okcancel-btn-box-flex-direction: row;
190
- --okcancel-btn-box-justify-content: flex-end;
191
- --okcancel-btn-box-align-items: center;
192
- --okcancel-btn-box-height: auto;
193
-
194
- /* 버튼 */
195
- --okcancel-button-padding: 8px 16px;
196
- --okcancel-button-border-radius: 6px;
197
- --okcancel-button-width: 100px;
198
- --okcancel-button-height: 40px;
199
- --okcancel-button-max-width: none;
200
- --okcancel-button-min-width: auto;
201
- --okcancel-button-border: none;
202
- --okcancel-button-box-shadow: none;
203
- --okcancel-button-font-size: 16px;
204
- --okcancel-button-font-weight: 500;
205
- --okcancel-button-text-align: center;
206
- --okcancel-button-flex: 0 1 auto;
207
-
208
- /* 주 버튼 (확인) */
209
- --okcancel-button-primary-bg: #2c89e5;
210
- --okcancel-button-primary-color: #fff;
211
- --okcancel-button-primary-border: none;
212
-
213
- /* 보조 버튼 (취소) */
214
- --okcancel-button-secondary-bg: transparent;
215
- --okcancel-button-secondary-color: #222;
216
- --okcancel-button-secondary-border: 1px solid #d4d4d4;
217
-
218
- /* 오버레이 */
219
- --okcancel-overlay-bg: rgb(0 0 0 / 50%);
220
- --okcancel-z-index: 1000;
116
+ export function MyConfirm({ title, description, onConfirm, onCancel }: ConfirmDialogProps) {
117
+ return (
118
+ <div className="modal">
119
+ <h2>{title}</h2>
120
+ <p>{description}</p>
121
+ <button onClick={onCancel}>취소</button>
122
+ <button onClick={onConfirm}>확인</button>
123
+ </div>
124
+ );
221
125
  }
222
126
  ```
223
127
 
224
- ### 반응형 커스터마이징
128
+ #### 알림 다이얼로그 (`AlertDialogProps`)
225
129
 
226
- 모바일에서는 자동으로 다음과 같이 조정됩니다:
130
+ `onConfirm`만 받아 작업을 완료하고 `void`를 반환합니다.
227
131
 
228
- - 다이얼로그 너비: 화면의 85%
229
- - 버튼 간격: 넓게 조정
230
- - 버튼: 전체 너비로 확장
231
-
232
- 모바일 스타일을 커스터마이징하려면:
132
+ ```tsx
133
+ import type { AlertDialogProps } from '@pop-kit/okcancel';
233
134
 
234
- ```css
235
- @media (width < 640px) {
236
- :root {
237
- --okcancel-dialog-width: 90%; /* 모바일 너비 조정 */
238
- --okcancel-btn-box-gap: 16px; /* 버튼 간격 조정 */
239
- --okcancel-button-flex: 1; /* 버튼 전체 너비 */
240
- --okcancel-btn-box-flex-direction: column; /* 버튼 세로 배치 */
241
- }
135
+ export function MyAlert({ title, description, onConfirm }: AlertDialogProps) {
136
+ return (
137
+ <div className="alert">
138
+ <h2>{title}</h2>
139
+ <p>{description}</p>
140
+ <button onClick={onConfirm}>닫기</button>
141
+ </div>
142
+ );
242
143
  }
243
144
  ```
244
145
 
245
- ## ♿ 접근성 기능
146
+ ---
246
147
 
247
- - **ARIA 역할**: 적절한 `dialog` 및 `alertdialog` 역할
248
- - **포커스 관리**: 확인 버튼에 자동 포커스, 포커스 트래핑
249
- - **키보드 내비게이션**:
250
- - `Tab` / `Shift+Tab`으로 버튼 간 이동
251
- - `Enter` / `Space`로 포커스된 버튼 활성화
252
- - `Escape`로 다이얼로그 닫기 (활성화된 경우)
253
- - **스크린 리더 지원**: 적절한 라벨링 및 알림
148
+ ## ⚖️ License
254
149
 
255
- ## 🔧 고급 사용법
256
-
257
- ### JSX를 사용한 커스텀 콘텐츠
258
-
259
- ```tsx
260
- const result = await confirm({
261
- title: '파일 삭제',
262
- description: (
263
- <div>
264
- <p>다음 파일들을 삭제하시겠습니까?</p>
265
- <ul>
266
- <li>document.pdf</li>
267
- <li>image.jpg</li>
268
- <li>data.json</li>
269
- </ul>
270
- <p>
271
- <strong>경고:</strong> 이 작업은 되돌릴 수 없습니다.
272
- </p>
273
- </div>
274
- ),
275
- confirmText: '삭제',
276
- cancelText: '취소',
277
- });
278
- ```
150
+ MIT License. 자유롭게 사용하고 기여해 주세요!