@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 +95 -223
- package/dist/index.esm.js +363 -318
- package/dist/index.js +20 -5
- package/dist/types/core/hooks.d.ts +1 -2
- package/dist/types/core/index.d.ts +6 -0
- package/dist/types/{presets/default/components → core}/portal.d.ts +1 -1
- package/dist/types/core/store.d.ts +2 -1
- package/dist/types/core/types.d.ts +5 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/lib/utils.d.ts +2 -0
- package/dist/types/main.d.ts +0 -1
- package/dist/types/okcancel/context.d.ts +5 -0
- package/dist/types/okcancel/hooks.d.ts +5 -0
- package/dist/types/okcancel/index.d.ts +4 -0
- package/dist/types/okcancel/provider.d.ts +7 -0
- package/dist/types/okcancel/types.d.ts +56 -0
- package/dist/types/registry/confirm-dialog.d.ts +2 -0
- package/dist/types/registry/index.d.ts +8 -0
- package/dist/types/registry/simple-alert-dialog.d.ts +2 -0
- package/dist/types/registry/ui/alert-dialog.d.ts +20 -0
- package/package.json +14 -6
- package/dist/types/presets/default/components/dialog.d.ts +0 -6
- package/dist/types/presets/default/hooks.d.ts +0 -2
- package/dist/types/presets/default/provider.d.ts +0 -6
- package/dist/types/presets/default/types.d.ts +0 -37
package/README.md
CHANGED
|
@@ -2,277 +2,149 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@pop-kit/okcancel)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://stackblitz.com/edit/vitejs-vite-wszi61bn?file=src%2FApp.tsx)
|
|
6
5
|
|
|
7
|
-
**React
|
|
8
|
-
`confirm`, `alert`
|
|
6
|
+
**React 기반의 UI-Agnostic 비동기 오버레이 관리자**입니다.
|
|
7
|
+
`confirm`, `alert` 로직을 비즈니스 로직에서 분리하여 `await` 한 줄로 우아하게 제어하세요.
|
|
8
|
+
|
|
9
|
+
---
|
|
9
10
|
|
|
10
11
|
## ✨ 주요 특징
|
|
11
12
|
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
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
|
-
|
|
28
|
+
### 2. shadcn/ui 프리셋 추가 (선택 사항)
|
|
24
29
|
|
|
25
|
-
|
|
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
|
-
|
|
30
|
-
import { OkCancelProvider, useOkCancel } from 'react-okcancel';
|
|
36
|
+
_설치 후 `components/ui/ok-cancel/` 폴더에 다이얼로그 컴포넌트들이 생성됩니다._
|
|
31
37
|
|
|
32
|
-
|
|
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
|
-
|
|
44
|
-
// 삭제 로직
|
|
45
|
-
await alert({
|
|
46
|
-
title: '완료',
|
|
47
|
-
description: '항목이 성공적으로 삭제되었습니다.',
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
};
|
|
40
|
+
## 🚀 사용 가이드 (Usage)
|
|
51
41
|
|
|
52
|
-
|
|
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
|
-
<
|
|
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
|
-
|
|
86
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
109
|
+
#### 확인 다이얼로그 (`ConfirmDialogProps`)
|
|
134
110
|
|
|
135
|
-
|
|
111
|
+
`onConfirm`과 `onCancel`을 모두 받아 `boolean` 결과를 반환합니다.
|
|
136
112
|
|
|
137
113
|
```tsx
|
|
138
|
-
|
|
139
|
-
title: '성공',
|
|
140
|
-
description: '파일이 성공적으로 업로드되었습니다.',
|
|
141
|
-
confirmText: '확인',
|
|
142
|
-
});
|
|
114
|
+
import type { ConfirmDialogProps } from '@pop-kit/okcancel';
|
|
143
115
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
- 버튼: 전체 너비로 확장
|
|
231
|
-
|
|
232
|
-
모바일 스타일을 커스터마이징하려면:
|
|
132
|
+
```tsx
|
|
133
|
+
import type { AlertDialogProps } from '@pop-kit/okcancel';
|
|
233
134
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
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. 자유롭게 사용하고 기여해 주세요!
|