@casperid/react 1.0.0 → 1.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.
Files changed (43) hide show
  1. package/README.md +1 -1
  2. package/dist/_commonjsHelpers-DKOUU3wS.cjs +2 -0
  3. package/dist/_commonjsHelpers-DKOUU3wS.cjs.map +1 -0
  4. package/dist/_commonjsHelpers-DaMA6jEr.js +9 -0
  5. package/dist/_commonjsHelpers-DaMA6jEr.js.map +1 -0
  6. package/dist/camera_utils-BQaOSBPu.js +397 -0
  7. package/dist/camera_utils-BQaOSBPu.js.map +1 -0
  8. package/dist/camera_utils-wchtqrQn.cjs +2 -0
  9. package/dist/camera_utils-wchtqrQn.cjs.map +1 -0
  10. package/dist/face_mesh-DYMPc5Ce.js +4212 -0
  11. package/dist/face_mesh-DYMPc5Ce.js.map +1 -0
  12. package/dist/face_mesh-fEvyDoPt.cjs +19 -0
  13. package/dist/face_mesh-fEvyDoPt.cjs.map +1 -0
  14. package/dist/index.cjs +41 -41
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.mjs +1786 -1501
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/style.css +1 -1
  19. package/package.json +23 -10
  20. package/src/CasperIDModal.tsx +0 -777
  21. package/src/index.css +0 -217
  22. package/src/index.ts +0 -41
  23. package/src/screens/AuthSelection.tsx +0 -221
  24. package/src/screens/DocumentScan.tsx +0 -348
  25. package/src/screens/FaceScan.tsx +0 -368
  26. package/src/screens/IdentityVerified.tsx +0 -51
  27. package/src/screens/L1Setup.tsx +0 -335
  28. package/src/screens/Login.tsx +0 -186
  29. package/src/screens/MintingIdentity.tsx +0 -446
  30. package/src/screens/PasskeyAuth.tsx +0 -259
  31. package/src/screens/PasskeyRegister.tsx +0 -281
  32. package/src/screens/PermissionsRequest.tsx +0 -96
  33. package/src/screens/PinVerification.tsx +0 -321
  34. package/src/screens/ReviewData.tsx +0 -315
  35. package/src/screens/SecurityUpgrade.tsx +0 -83
  36. package/src/screens/VerifyIdentityChoice.tsx +0 -59
  37. package/src/shared/Footer.tsx +0 -13
  38. package/src/shared/GlassContainer.tsx +0 -17
  39. package/src/shared/Header.tsx +0 -62
  40. package/src/types.ts +0 -342
  41. package/src/utils/fetchWithTimeout.ts +0 -52
  42. package/src/utils/i18n.ts +0 -640
  43. package/src/utils/webauthn.ts +0 -261
package/src/index.css DELETED
@@ -1,217 +0,0 @@
1
- @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap');
2
- @import "tailwindcss";
3
-
4
- @theme {
5
- --font-sans: "Plus Jakarta Sans", "Inter", ui-sans-serif, system-ui, sans-serif;
6
- }
7
-
8
- /* ============================================
9
- CSS Variable Bridge — driven by <CasperIDModal theme={...} />
10
- Variables are set dynamically by the component via scoped styles.
11
- No defaults here to prevent flash of default colors.
12
- ============================================ */
13
- :root {
14
- /* Brand variables are injected by CasperIDModal component */
15
- font-family: var(--casperid-font, "Plus Jakarta Sans", Inter, sans-serif);
16
- }
17
-
18
- /* Light mode (default) */
19
- :root,
20
- .light {
21
- --bg-app: #f8fafc;
22
- --text-primary: #0f172a;
23
- --text-secondary: #64748b;
24
- --glass-bg: rgba(255, 255, 255, 0.94);
25
- --glass-border: rgba(0, 0, 0, 0.16);
26
- }
27
-
28
- /* Dark mode */
29
- .dark {
30
- --bg-app: #0B0813;
31
- --text-primary: #ffffff;
32
- --text-secondary: #94a3b8;
33
- --glass-bg: #0e0b16;
34
- --glass-border: rgba(255, 255, 255, 0.18);
35
- }
36
-
37
- @layer base {
38
- body {
39
- @apply antialiased;
40
- }
41
- }
42
-
43
- @layer components {
44
- .glass-container {
45
- @apply backdrop-blur-[32px] border transition-all duration-500;
46
- background: var(--glass-bg);
47
- border-color: var(--glass-border);
48
- }
49
-
50
- /* Force background color to prevent clipping or transparency issues in light mode */
51
- :root:not(.dark) .glass-container {
52
- background-color: var(--glass-bg) !important;
53
- }
54
-
55
- .dark .glass-container {
56
- background-color: var(--glass-bg) !important;
57
- }
58
-
59
- .light .glass-container {
60
- box-shadow:
61
- 0 20px 50px -12px rgba(0, 0, 0, 0.1),
62
- 0 0 0 1px rgba(0, 0, 0, 0.05);
63
- }
64
-
65
- .mesh-gradient {
66
- @apply transition-all duration-700;
67
- /* Vibrant mesh gradient using the dynamic primary color */
68
- background:
69
- radial-gradient(circle at 10% 10%, color-mix(in srgb, var(--casperid-primary), transparent 65%) 0%, transparent 60%),
70
- radial-gradient(circle at 90% 90%, color-mix(in srgb, var(--casperid-primary), transparent 90%) 0%, transparent 50%);
71
- }
72
-
73
- .dark .mesh-gradient {
74
- background:
75
- radial-gradient(circle at 10% 10%, color-mix(in srgb, var(--casperid-primary), transparent 80%) 0%, transparent 50%),
76
- radial-gradient(circle at 90% 90%, color-mix(in srgb, var(--casperid-primary), transparent 92%) 0%, transparent 40%);
77
- }
78
-
79
- .text-main {
80
- color: var(--text-primary);
81
- }
82
-
83
- .text-muted {
84
- color: var(--text-secondary);
85
- }
86
-
87
- .text-brand {
88
- color: var(--casperid-primary);
89
- }
90
-
91
- /* ============================================
92
- Brand Color Utilities (using CSS variables)
93
- ============================================ */
94
- .bg-brand {
95
- background-color: var(--casperid-primary);
96
- }
97
-
98
- .bg-brand-90 {
99
- background-color: color-mix(in srgb, var(--casperid-primary) 90%, transparent);
100
- }
101
-
102
- .bg-brand-20 {
103
- background-color: color-mix(in srgb, var(--casperid-primary) 20%, transparent);
104
- }
105
-
106
- .bg-brand-10 {
107
- background-color: color-mix(in srgb, var(--casperid-primary) 10%, transparent);
108
- }
109
-
110
- .bg-brand-5 {
111
- background-color: color-mix(in srgb, var(--casperid-primary) 5%, transparent);
112
- }
113
-
114
- .hover\:bg-brand-90:hover {
115
- background-color: color-mix(in srgb, var(--casperid-primary) 90%, transparent);
116
- }
117
-
118
- .hover\:bg-brand-15:hover {
119
- background-color: color-mix(in srgb, var(--casperid-primary) 15%, transparent);
120
- }
121
-
122
- .border-brand {
123
- border-color: var(--casperid-primary);
124
- }
125
-
126
- .border-brand-30 {
127
- border-color: color-mix(in srgb, var(--casperid-primary) 30%, transparent);
128
- }
129
-
130
- .border-brand-20 {
131
- border-color: color-mix(in srgb, var(--casperid-primary) 20%, transparent);
132
- }
133
-
134
- .border-brand-10 {
135
- border-color: color-mix(in srgb, var(--casperid-primary) 10%, transparent);
136
- }
137
-
138
- .border-brand-5 {
139
- border-color: color-mix(in srgb, var(--casperid-primary) 5%, transparent);
140
- }
141
-
142
- .border-brand-40 {
143
- border-color: color-mix(in srgb, var(--casperid-primary) 40%, transparent);
144
- }
145
-
146
- .hover\:border-brand-40:hover {
147
- border-color: color-mix(in srgb, var(--casperid-primary) 40%, transparent);
148
- }
149
-
150
- .hover\:border-brand-30:hover {
151
- border-color: color-mix(in srgb, var(--casperid-primary) 30%, transparent);
152
- }
153
-
154
- .shadow-brand {
155
- box-shadow: 0 10px 25px -5px color-mix(in srgb, var(--casperid-primary) 30%, transparent);
156
- }
157
-
158
- .ring-brand {
159
- --tw-ring-color: var(--casperid-primary);
160
- }
161
-
162
- .ring-brand-40 {
163
- --tw-ring-color: color-mix(in srgb, var(--casperid-primary) 40%, transparent);
164
- }
165
-
166
- .selection-brand {
167
- --tw-selection-bg: color-mix(in srgb, var(--casperid-primary) 30%, transparent);
168
- }
169
-
170
- /* Border radius utility */
171
- .rounded-brand {
172
- border-radius: var(--casperid-radius, 12px);
173
- }
174
-
175
- /* Focus ring utilities */
176
- .focus-within\:ring-brand-40:focus-within {
177
- --tw-ring-color: color-mix(in srgb, var(--casperid-primary) 40%, transparent);
178
- --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
179
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
180
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
181
- }
182
-
183
- .focus\:ring-brand-30:focus {
184
- --tw-ring-color: color-mix(in srgb, var(--casperid-primary) 30%, transparent);
185
- --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
186
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
187
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
188
- }
189
-
190
- /* Gradient utilities */
191
- .from-brand {
192
- --tw-gradient-from: var(--casperid-primary) var(--tw-gradient-from-position);
193
- --tw-gradient-to: color-mix(in srgb, var(--casperid-primary) 0%, transparent) var(--tw-gradient-to-position);
194
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
195
- }
196
-
197
- .from-brand-20 {
198
- --tw-gradient-from: color-mix(in srgb, var(--casperid-primary) 20%, transparent) var(--tw-gradient-from-position);
199
- --tw-gradient-to: transparent var(--tw-gradient-to-position);
200
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
201
- }
202
-
203
- .from-brand-5 {
204
- --tw-gradient-from: color-mix(in srgb, var(--casperid-primary) 5%, transparent) var(--tw-gradient-from-position);
205
- --tw-gradient-to: transparent var(--tw-gradient-to-position);
206
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
207
- }
208
-
209
- .to-brand {
210
- --tw-gradient-to: var(--casperid-primary) var(--tw-gradient-to-position);
211
- }
212
-
213
- .via-brand-10 {
214
- --tw-gradient-to: transparent var(--tw-gradient-to-position);
215
- --tw-gradient-stops: var(--tw-gradient-from), color-mix(in srgb, var(--casperid-primary) 10%, transparent) var(--tw-gradient-via-position), var(--tw-gradient-to);
216
- }
217
- }
package/src/index.ts DELETED
@@ -1,41 +0,0 @@
1
- // Styles (optional - consumers can import separately)
2
- import './index.css';
3
-
4
- // Main component
5
- export { CasperIDModal } from './CasperIDModal';
6
- export { default } from './CasperIDModal';
7
-
8
- // Individual screens (for advanced customisation / white-labelling)
9
- export { default as AuthSelectionScreen } from './screens/AuthSelection';
10
- export { default as LoginScreen } from './screens/Login';
11
- export { default as PinVerificationScreen } from './screens/PinVerification';
12
- export { default as SecurityUpgradeScreen } from './screens/SecurityUpgrade';
13
- export { default as FaceScanScreen } from './screens/FaceScan';
14
- export { default as VerifyIdentityChoiceScreen } from './screens/VerifyIdentityChoice';
15
- export { default as DocumentScanScreen } from './screens/DocumentScan';
16
- export { default as ReviewDataScreen } from './screens/ReviewData';
17
- export { default as MintingIdentityScreen } from './screens/MintingIdentity';
18
- export { default as IdentityVerifiedScreen } from './screens/IdentityVerified';
19
- export { default as PermissionsRequestScreen } from './screens/PermissionsRequest';
20
-
21
- // Shared components
22
- export { default as GlassContainer } from './shared/GlassContainer';
23
- export { default as Header } from './shared/Header';
24
- export { default as Footer } from './shared/Footer';
25
-
26
- // Types
27
- export type {
28
- CasperIDModalProps,
29
- CasperIDTheme,
30
- Screen,
31
- SDKMode,
32
- VerificationTier,
33
- ScreenProps,
34
- DocumentType,
35
- ExtractedDocumentData,
36
- KYCState,
37
- OTPState,
38
- } from './types';
39
-
40
- // Utilities
41
- export { fetchWithTimeout, ApiError, handleApiResponse } from './utils/fetchWithTimeout';
@@ -1,221 +0,0 @@
1
- import React, { useState, useEffect, useCallback } from 'react';
2
- import { motion } from 'framer-motion';
3
- import { Fingerprint, Puzzle, ChevronRight, Smartphone, ShieldCheck, RefreshCw, Loader2, AlertCircle } from 'lucide-react';
4
- import { t } from '../utils/i18n';
5
-
6
- interface ExtensionUserData {
7
- wallet: string;
8
- cnsName?: string;
9
- email?: string;
10
- tier?: string;
11
- humanId?: string;
12
- }
13
-
14
- interface AuthSelectionProps {
15
- onNext: (method: 'extension' | 'otp') => void;
16
- onExtensionSuccess?: (userData: ExtensionUserData) => void;
17
- onError?: (error: string) => void;
18
- language?: string;
19
- }
20
-
21
- const AuthSelection: React.FC<AuthSelectionProps> = ({
22
- onNext,
23
- onExtensionSuccess,
24
- onError,
25
- language = 'EN'
26
- }) => {
27
- const [isCheckingExtension, setIsCheckingExtension] = useState(false);
28
- const [extensionInstalled, setExtensionInstalled] = useState<boolean | null>(null);
29
- const [error, setError] = useState('');
30
-
31
- // Check if extension is installed on mount
32
- useEffect(() => {
33
- checkExtensionInstalled();
34
- }, []);
35
-
36
- // Listen for extension login events
37
- useEffect(() => {
38
- const handleExtensionLogin = (event: CustomEvent<ExtensionUserData>) => {
39
- setIsCheckingExtension(false);
40
- if (event.detail && event.detail.wallet) {
41
- onExtensionSuccess?.(event.detail);
42
- }
43
- };
44
-
45
- window.addEventListener('casperid-login', handleExtensionLogin as EventListener);
46
- return () => {
47
- window.removeEventListener('casperid-login', handleExtensionLogin as EventListener);
48
- };
49
- }, [onExtensionSuccess]);
50
-
51
- const checkExtensionInstalled = useCallback(() => {
52
- // Check for extension anchor or localStorage data
53
- const anchor = document.getElementById('casperid-draggable-anchor');
54
- let storedUser: string | null = null;
55
-
56
- try {
57
- storedUser = localStorage.getItem('casperid_user');
58
- } catch {
59
- // localStorage may not be available in some contexts
60
- }
61
-
62
- if (anchor || storedUser) {
63
- setExtensionInstalled(true);
64
- return true;
65
- }
66
-
67
- // Also check if we can detect extension via a brief timeout
68
- // Extension injects its content script which adds the anchor
69
- setTimeout(() => {
70
- const anchorAfterDelay = document.getElementById('casperid-draggable-anchor');
71
- setExtensionInstalled(!!anchorAfterDelay);
72
- }, 500);
73
-
74
- return false;
75
- }, []);
76
-
77
- const isValidUserData = (data: unknown): data is ExtensionUserData => {
78
- return (
79
- typeof data === 'object' &&
80
- data !== null &&
81
- 'wallet' in data &&
82
- typeof (data as ExtensionUserData).wallet === 'string' &&
83
- (data as ExtensionUserData).wallet.length > 0
84
- );
85
- };
86
-
87
- const handleExtensionLogin = async () => {
88
- setIsCheckingExtension(true);
89
- setError('');
90
-
91
- // Check if already logged in via extension
92
- try {
93
- const storedUser = localStorage.getItem('casperid_user');
94
- if (storedUser) {
95
- const userData = JSON.parse(storedUser);
96
- if (isValidUserData(userData)) {
97
- setIsCheckingExtension(false);
98
- onExtensionSuccess?.(userData);
99
- return;
100
- }
101
- }
102
- } catch {
103
- // Invalid stored data or localStorage not available, continue with extension trigger
104
- }
105
-
106
- // Check if extension anchor exists
107
- const anchor = document.getElementById('casperid-draggable-anchor');
108
-
109
- if (anchor) {
110
- // Trigger click on the anchor to initiate login
111
- anchor.click();
112
-
113
- // Set a timeout to show error if no response
114
- setTimeout(() => {
115
- setIsCheckingExtension(false);
116
- // Check again if login succeeded
117
- try {
118
- const newStoredUser = localStorage.getItem('casperid_user');
119
- if (!newStoredUser) {
120
- setError(t('extension_connect_msg', language));
121
- }
122
- } catch {
123
- setError(t('extension_connect_msg', language));
124
- }
125
- }, 3000);
126
- } else {
127
- // Extension not detected
128
- setIsCheckingExtension(false);
129
- setError(t('extension_not_detected', language));
130
- onError?.('Extension not installed');
131
- }
132
- };
133
-
134
- const handleOTPLogin = () => {
135
- setError('');
136
- onNext('otp');
137
- };
138
-
139
- return (
140
- <motion.div
141
- initial={{ opacity: 0, y: 20 }}
142
- animate={{ opacity: 1, y: 0 }}
143
- exit={{ opacity: 0, y: -20 }}
144
- className="flex-1 px-8 flex flex-col justify-center gap-8"
145
- >
146
- <div className="text-center space-y-3">
147
- <div className="relative w-24 h-24 mx-auto mb-6">
148
- <div className="absolute inset-0 bg-brand-20 blur-2xl rounded-full" />
149
- <div className="relative w-full h-full glass-container flex items-center justify-center rounded-2xl border border-brand-30">
150
- <Fingerprint className="w-10 h-10 text-brand" />
151
- </div>
152
- </div>
153
- <h1 className="text-2xl font-extrabold leading-tight tracking-tight text-main">{t('welcome_back', language)}</h1>
154
- <p className="text-muted text-sm leading-relaxed">
155
- {t('auth_subtitle', language)}
156
- </p>
157
- </div>
158
-
159
- {/* Error Message */}
160
- {error && (
161
- <div className="flex items-start gap-3 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-2xl">
162
- <AlertCircle className="w-5 h-5 text-red-500 shrink-0 mt-0.5" />
163
- <p className="text-red-600 dark:text-red-400 text-sm font-medium">{error}</p>
164
- </div>
165
- )}
166
-
167
- <div className="space-y-4">
168
- <button
169
- onClick={handleExtensionLogin}
170
- disabled={isCheckingExtension}
171
- className="w-full group relative overflow-hidden flex items-center gap-4 bg-brand hover:bg-brand-90 text-white py-5 px-6 rounded-2xl font-bold transition-all transform active:scale-[0.98] disabled:opacity-70 disabled:cursor-not-allowed shadow-brand"
172
- >
173
- <div className="bg-white/20 p-2 rounded-lg">
174
- {isCheckingExtension ? (
175
- <Loader2 className="w-5 h-5 animate-spin" />
176
- ) : (
177
- <Puzzle className="w-5 h-5" />
178
- )}
179
- </div>
180
- <div className="flex flex-col items-start">
181
- <span className="text-base">
182
- {isCheckingExtension ? t('connecting', language) : t('sign_in_with_extension', language)}
183
- </span>
184
- <span className="text-[10px] uppercase tracking-widest text-white/70">
185
- {extensionInstalled === true ? t('extension_detected', language) : t('secure_wallet', language)}
186
- </span>
187
- </div>
188
- <ChevronRight className="ml-auto w-4 h-4 opacity-50 group-hover:opacity-100 transition-opacity" />
189
- </button>
190
-
191
- <button
192
- onClick={handleOTPLogin}
193
- disabled={isCheckingExtension}
194
- className="w-full group relative overflow-hidden flex items-center gap-4 dark:bg-white/5 bg-slate-100/50 hover:dark:bg-white/10 hover:bg-slate-200/80 border dark:border-white/10 border-slate-200 text-main py-5 px-6 rounded-2xl font-bold transition-all transform active:scale-[0.98] disabled:opacity-50"
195
- >
196
- <div className="bg-brand-10 p-2 rounded-lg">
197
- <Smartphone className="w-5 h-5 text-brand" />
198
- </div>
199
- <div className="flex flex-col items-start">
200
- <span className="text-base">{t('sign_in_with_otp', language)}</span>
201
- <span className="text-[10px] uppercase tracking-widest text-brand font-bold">{t('two_factor_auth', language)}</span>
202
- </div>
203
- <ChevronRight className="ml-auto w-4 h-4 opacity-50 group-hover:opacity-100 transition-opacity" />
204
- </button>
205
- </div>
206
-
207
- <div className="grid grid-cols-2 gap-3">
208
- <div className="glass-container p-4 rounded-2xl flex flex-col items-center gap-2 text-center border-slate-200/50">
209
- <ShieldCheck className="w-5 h-5 text-brand" />
210
- <span className="text-[10px] font-bold text-muted">{t('fully_audited', language)}</span>
211
- </div>
212
- <div className="glass-container p-4 rounded-2xl flex flex-col items-center gap-2 text-center border-slate-200/50">
213
- <RefreshCw className="w-5 h-5 text-brand" />
214
- <span className="text-[10px] font-bold text-muted">{t('non_custodial', language)}</span>
215
- </div>
216
- </div>
217
- </motion.div>
218
- );
219
- };
220
-
221
- export default AuthSelection;