@volr/react-ui 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 ADDED
@@ -0,0 +1,341 @@
1
+ # @volr/react-ui 사용 가이드
2
+
3
+ Volr의 UI 컴포넌트 라이브러리입니다. 미니멀하고 모던한 디자인의 로그인 모달을 제공합니다.
4
+
5
+ ## 설치
6
+
7
+ ```bash
8
+ npm install @volr/react-ui @volr/react
9
+ # 또는
10
+ yarn add @volr/react-ui @volr/react
11
+ ```
12
+
13
+ ## 기본 설정
14
+
15
+ ### 1. VolrUIProvider로 앱 래핑
16
+
17
+ 앱의 최상위 레벨에서 `VolrUIProvider`로 앱을 래핑합니다.
18
+
19
+ ```tsx
20
+ import { VolrUIProvider } from '@volr/react-ui';
21
+ import { VolrConfig } from '@volr/react';
22
+
23
+ const volrConfig: VolrConfig = {
24
+ apiBaseUrl: 'https://api.volr.dev',
25
+ defaultChainId: 1,
26
+ projectApiKey: 'your-project-api-key',
27
+ };
28
+
29
+ function App() {
30
+ return (
31
+ <VolrUIProvider
32
+ config={volrConfig}
33
+ accentColor="#3b82f6" // 버튼, 링크 등 강조 요소에 사용되는 색상
34
+ enabledLoginMethods={['email', 'social', 'siwe']} // 활성화할 로그인 방식
35
+ socialProviders={['google', 'twitter', 'apple']} // 활성화할 소셜 제공자
36
+ >
37
+ <YourApp />
38
+ </VolrUIProvider>
39
+ );
40
+ }
41
+ ```
42
+
43
+ ### 2. LoginModal 사용
44
+
45
+ 로그인 모달을 표시하려면 `LoginModal` 컴포넌트를 사용합니다.
46
+
47
+ ```tsx
48
+ import { useState } from 'react';
49
+ import { LoginModal } from '@volr/react-ui';
50
+
51
+ function LoginButton() {
52
+ const [isOpen, setIsOpen] = useState(false);
53
+
54
+ return (
55
+ <>
56
+ <button onClick={() => setIsOpen(true)}>로그인</button>
57
+
58
+ <LoginModal
59
+ isOpen={isOpen}
60
+ onClose={() => setIsOpen(false)}
61
+ onError={(error) => {
62
+ console.error('로그인 오류:', error);
63
+ // 에러 처리 로직
64
+ }}
65
+ />
66
+ </>
67
+ );
68
+ }
69
+ ```
70
+
71
+ ## 설정 옵션
72
+
73
+ ### VolrUIProvider Props
74
+
75
+ | Prop | Type | Default | Description |
76
+ |------|------|---------|-------------|
77
+ | `config` | `VolrConfig` | **필수** | Volr 설정 (apiBaseUrl, defaultChainId, projectApiKey) |
78
+ | `accentColor` | `string` | `'#303030'` | 버튼, 링크 등 강조 요소에 사용되는 색상 |
79
+ | `appName` | `string` | `undefined` | 앱 이름 |
80
+ | `enabledLoginMethods` | `('email' \| 'social' \| 'siwe')[]` | `['email', 'social', 'siwe']` | 활성화할 로그인 방식 |
81
+ | `socialProviders` | `('google' \| 'twitter' \| 'apple')[]` | `['google', 'twitter', 'apple']` | 활성화할 소셜 제공자 |
82
+ | `volrLogoUrl` | `string` | `undefined` | Volr 로고 URL |
83
+ | `providerPolicy` | `object` | `{ enforceOnFirstLogin: true }` | Provider 정책 설정 |
84
+
85
+ ### LoginModal Props
86
+
87
+ | Prop | Type | Default | Description |
88
+ |------|------|---------|-------------|
89
+ | `isOpen` | `boolean` | **필수** | 모달 열림/닫힘 상태 |
90
+ | `onClose` | `() => void` | **필수** | 모달 닫기 콜백 |
91
+ | `onError` | `(error: Error) => void` | `undefined` | 에러 발생 시 콜백 |
92
+
93
+ ## 사용 예시
94
+
95
+ ### 기본 사용
96
+
97
+ ```tsx
98
+ import { useState } from 'react';
99
+ import { LoginModal } from '@volr/react-ui';
100
+
101
+ function App() {
102
+ const [showLogin, setShowLogin] = useState(false);
103
+
104
+ return (
105
+ <>
106
+ <button onClick={() => setShowLogin(true)}>로그인</button>
107
+ <LoginModal
108
+ isOpen={showLogin}
109
+ onClose={() => setShowLogin(false)}
110
+ />
111
+ </>
112
+ );
113
+ }
114
+ ```
115
+
116
+ ### 이메일 로그인만 활성화
117
+
118
+ ```tsx
119
+ <VolrUIProvider
120
+ config={volrConfig}
121
+ accentColor="#6366f1"
122
+ enabledLoginMethods={['email']}
123
+ >
124
+ <App />
125
+ </VolrUIProvider>
126
+ ```
127
+
128
+ ### Google과 Apple만 활성화
129
+
130
+ ```tsx
131
+ <VolrUIProvider
132
+ config={volrConfig}
133
+ accentColor="#8b5cf6"
134
+ enabledLoginMethods={['social']}
135
+ socialProviders={['google', 'apple']}
136
+ >
137
+ <App />
138
+ </VolrUIProvider>
139
+ ```
140
+
141
+ ### 커스텀 에러 처리
142
+
143
+ ```tsx
144
+ function App() {
145
+ const [showLogin, setShowLogin] = useState(false);
146
+ const [error, setError] = useState<string | null>(null);
147
+
148
+ return (
149
+ <>
150
+ {error && (
151
+ <div style={{
152
+ padding: '12px',
153
+ backgroundColor: '#fef2f2',
154
+ color: '#991b1b',
155
+ borderRadius: '8px',
156
+ marginBottom: '16px'
157
+ }}>
158
+ {error}
159
+ </div>
160
+ )}
161
+
162
+ <button onClick={() => setShowLogin(true)}>로그인</button>
163
+
164
+ <LoginModal
165
+ isOpen={showLogin}
166
+ onClose={() => {
167
+ setShowLogin(false);
168
+ setError(null);
169
+ }}
170
+ onError={(err) => {
171
+ setError(err.message);
172
+ // 3초 후 에러 메시지 자동 숨김
173
+ setTimeout(() => setError(null), 3000);
174
+ }}
175
+ />
176
+ </>
177
+ );
178
+ }
179
+ ```
180
+
181
+ ## 로그인 플로우
182
+
183
+ ### 이메일 로그인
184
+ 1. 사용자가 "Email Login" 버튼 클릭
185
+ 2. 이메일 주소 입력 화면 표시
186
+ 3. 인증 코드 전송
187
+ 4. 6자리 코드 입력 화면 표시
188
+ 5. 코드 검증
189
+ 6. **신규 사용자**: Passkey 설정 화면으로 이동
190
+ 7. **기존 사용자**: 성공 화면으로 이동
191
+
192
+ ### 소셜 로그인 (Google, Twitter, Apple)
193
+ 1. 사용자가 소셜 로그인 버튼 클릭
194
+ 2. OAuth 페이지로 리다이렉트
195
+ 3. 소셜 계정으로 로그인 및 권한 승인
196
+ 4. 백엔드 콜백 처리 후 프론트엔드로 리다이렉트
197
+ 5. **신규 사용자**: Passkey 설정 화면으로 이동
198
+ 6. **기존 사용자**: 성공 화면으로 이동
199
+
200
+ ### 지갑 로그인 (SIWE)
201
+ 1. 사용자가 "Wallet Login" 버튼 클릭
202
+ 2. MetaMask 또는 다른 지갑 연결
203
+ 3. SIWE 메시지에 서명
204
+ 4. 백엔드에서 서명 검증
205
+ 5. **신규 사용자**: Passkey 설정 화면으로 이동
206
+ 6. **기존 사용자**: 성공 화면으로 이동
207
+
208
+ ## Passkey 설정
209
+
210
+ 신규 사용자의 경우 자동으로 Passkey 지갑이 생성됩니다:
211
+
212
+ 1. **Passkey 생성**: WebAuthn API를 사용하여 플랫폼 인증자(생체 인증) 생성
213
+ 2. **Wrap Key 파생**: Passkey PRF에서 Wrap Key 생성
214
+ 3. **Master Seed 생성 및 암호화**:
215
+ - 32바이트 무작위 Master Seed 생성
216
+ - Wrap Key로 AES-256-GCM 암호화
217
+ 4. **S3 업로드**: 암호화된 Master Seed를 S3에 업로드
218
+ 5. **Provider 등록**: 백엔드에 Provider 정보 등록
219
+ 6. **EVM 키 파생**: Master Seed에서 BIP-32로 EVM 키 쌍 파생
220
+ 7. **완료**: 지갑 주소 확인 및 로그인 완료
221
+
222
+ ## 디자인 원칙
223
+
224
+ - **미니멀리즘**: 깔끔하고 모던한 디자인, 불필요한 장식 없음
225
+ - **accentColor 사용**: 버튼, 링크 등 강조 요소에 config의 accentColor 활용
226
+ - **이모지 금지**: 모든 UI 요소에서 이모지 사용 안 함, SVG 아이콘만 사용
227
+ - **일관된 여백과 타이포그래피**: 명확한 시각적 계층
228
+
229
+ ## 백엔드 설정
230
+
231
+ 로그인 기능을 사용하려면 백엔드에 다음 환경 변수를 설정해야 합니다:
232
+
233
+ ```bash
234
+ # Google OAuth
235
+ GOOGLE_CLIENT_ID=your_google_client_id
236
+ GOOGLE_CLIENT_SECRET=your_google_client_secret
237
+ GOOGLE_REDIRECT_URI=http://localhost:3000/auth/google/callback
238
+
239
+ # Twitter OAuth
240
+ TWITTER_CLIENT_ID=your_twitter_client_id
241
+ TWITTER_CLIENT_SECRET=your_twitter_client_secret
242
+ TWITTER_REDIRECT_URI=http://localhost:3000/auth/twitter/callback
243
+
244
+ # Apple OAuth
245
+ APPLE_CLIENT_ID=your_apple_client_id
246
+ APPLE_REDIRECT_URI=http://localhost:3000/auth/apple/callback
247
+
248
+ # Frontend URL (OAuth 콜백 후 리다이렉트)
249
+ FRONTEND_URL=http://localhost:5173
250
+
251
+ # API Base URL
252
+ API_BASE_URL=http://localhost:3000
253
+ ```
254
+
255
+ ## API 엔드포인트
256
+
257
+ 백엔드에서 제공해야 하는 엔드포인트:
258
+
259
+ ### 이메일 로그인
260
+ - `POST /auth/email/send` - 인증 코드 전송
261
+ - `POST /auth/email/verify` - 인증 코드 검증 및 로그인
262
+
263
+ ### 소셜 로그인
264
+ - `GET /auth/google` - Google OAuth 시작
265
+ - `GET /auth/google/callback` - Google OAuth 콜백
266
+ - `GET /auth/twitter` - Twitter OAuth 시작
267
+ - `GET /auth/twitter/callback` - Twitter OAuth 콜백
268
+ - `GET /auth/apple` - Apple OAuth 시작
269
+ - `POST /auth/apple/callback` - Apple OAuth 콜백
270
+
271
+ ### SIWE 로그인
272
+ - `POST /auth/siwe/nonce` - Nonce 생성
273
+ - `POST /auth/siwe/verify` - SIWE 서명 검증
274
+
275
+ ### Passkey 관련
276
+ - `POST /blob/presign` - S3 업로드 URL 생성
277
+ - `POST /wallet/provider/register` - Provider 등록
278
+
279
+ ## 완전한 예제
280
+
281
+ ```tsx
282
+ import { useState } from 'react';
283
+ import { VolrUIProvider, LoginModal } from '@volr/react-ui';
284
+ import { VolrConfig } from '@volr/react';
285
+
286
+ const volrConfig: VolrConfig = {
287
+ apiBaseUrl: process.env.VITE_API_BASE_URL || 'http://localhost:3000',
288
+ defaultChainId: 1,
289
+ projectApiKey: process.env.VITE_PROJECT_API_KEY || '',
290
+ };
291
+
292
+ function LoginPage() {
293
+ const [isLoginOpen, setIsLoginOpen] = useState(false);
294
+
295
+ return (
296
+ <>
297
+ <button onClick={() => setIsLoginOpen(true)}>로그인</button>
298
+
299
+ <LoginModal
300
+ isOpen={isLoginOpen}
301
+ onClose={() => setIsLoginOpen(false)}
302
+ onError={(error) => {
303
+ console.error('로그인 오류:', error);
304
+ alert(error.message);
305
+ }}
306
+ />
307
+ </>
308
+ );
309
+ }
310
+
311
+ function App() {
312
+ return (
313
+ <VolrUIProvider
314
+ config={volrConfig}
315
+ accentColor="#6366f1"
316
+ enabledLoginMethods={['email', 'social', 'siwe']}
317
+ socialProviders={['google', 'twitter', 'apple']}
318
+ >
319
+ <LoginPage />
320
+ </VolrUIProvider>
321
+ );
322
+ }
323
+
324
+ export default App;
325
+ ```
326
+
327
+ ## 문제 해결
328
+
329
+ ### OAuth 리다이렉트 실패
330
+ - OAuth Client ID와 Secret 확인
331
+ - Redirect URI가 OAuth 앱 설정과 일치하는지 확인
332
+ - CORS 설정 확인
333
+
334
+ ### SIWE 서명 실패
335
+ - MetaMask 또는 다른 지갑이 설치되어 있는지 확인
336
+ - 지갑이 올바른 네트워크에 연결되어 있는지 확인
337
+
338
+ ### Passkey 생성 실패
339
+ - HTTPS 또는 localhost에서만 작동 (HTTP는 불가)
340
+ - 브라우저가 WebAuthn을 지원하는지 확인
341
+ - 디바이스에 생체 인증이 활성화되어 있는지 확인