@lumiapassport/ui-kit 1.12.5 → 1.13.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
@@ -13,9 +13,9 @@ React UI components and hooks for Lumia Passport - a secure, user-friendly authe
13
13
  ## Installation
14
14
 
15
15
  ```bash
16
- npm install @lumiapassport/ui-kit
16
+ npm install @lumiapassport/ui-kit
17
17
  # or
18
- pnpm add @lumiapassport/ui-kit
18
+ pnpm add @lumiapassport/ui-kit
19
19
  # or
20
20
  yarn add @lumiapassport/ui-kit
21
21
  ```
@@ -24,31 +24,28 @@ yarn add @lumiapassport/ui-kit
24
24
 
25
25
  ### 1. Setup QueryClient (Required)
26
26
 
27
- The UI Kit requires `@tanstack/react-query` for state management. First, create a query client:
27
+ The UI Kit requires `@tanstack/react-query` for query management. First, create a query client:
28
28
 
29
29
  ```tsx
30
30
  // queryClient.ts
31
- import { QueryClient } from '@tanstack/react-query';
31
+ import { QueryClient } from '@tanstack/react-query'
32
32
 
33
33
  export const queryClient = new QueryClient({
34
- defaultOptions: {
35
- queries: {
36
- staleTime: 1000 * 60 * 5, // 5 minutes
37
- gcTime: 1000 * 60 * 10, // 10 minutes
38
- refetchOnWindowFocus: false,
39
- retry: false,
40
- },
41
- },
42
- });
34
+ defaultOptions: {}
35
+ })
43
36
  ```
44
37
 
45
38
  ### 2. Wrap your app with providers
46
39
 
47
40
  ```tsx
48
- import { QueryClientProvider } from '@tanstack/react-query';
49
- import { LumiaPassportProvider } from '@lumiapassport/ui-kit';
50
- import '@lumiapassport/ui-kit/dist/styles.css';
51
- import { queryClient } from './queryClient';
41
+ import {
42
+ //
43
+ LumiaPassportProvider,
44
+ LumiaPassportSessionProvider,
45
+ LumiaRainbowKitProvider
46
+ } from '@lumiapassport/ui-kit'
47
+
48
+ import { queryClient } from './queryClient'
52
49
 
53
50
  function Root() {
54
51
  return (
@@ -56,25 +53,51 @@ function Root() {
56
53
  <LumiaPassportProvider
57
54
  projectId="your-project-id" // Get from Lumia Passport Dashboard
58
55
  >
59
- <YourApp />
56
+ <LumiaRainbowKitProvider>
57
+ <LumiaPassportSessionProvider>
58
+ <YourApp />
59
+ </LumiaPassportSessionProvider>
60
+ </LumiaRainbowKitProvider>
60
61
  </LumiaPassportProvider>
61
62
  </QueryClientProvider>
62
- );
63
+ )
63
64
  }
64
65
  ```
65
66
 
66
67
  ### 3. Add the Connect Button
67
68
 
68
69
  ```tsx
69
- import { ConnectWalletButton } from '@lumiapassport/ui-kit';
70
+ import { ConnectWalletButton } from '@lumiapassport/ui-kit'
70
71
 
71
72
  function YourApp() {
72
73
  return (
73
74
  <div>
74
75
  <h1>My App</h1>
75
- <ConnectWalletButton label="Sign in" mode="compact"/>
76
+ <ConnectWalletButton label="Sign in" />
76
77
  </div>
77
- );
78
+ )
79
+ }
80
+ ```
81
+
82
+ ### 3.1 (Optional)
83
+
84
+ Custom unconnected button can be provided via ConnectButton prop.
85
+ Prop consumes standart HTMLButton component and will provide required onClick to it
86
+
87
+ ```tsx
88
+ import { ConnectWalletButton } from '@lumiapassport/ui-kit'
89
+
90
+ function CustomButtonComponent(props: HTMLAttributes<HTMLButtonElement>) => {
91
+ return (<button {...props}/>)
92
+ }
93
+
94
+ function YourApp() {
95
+ return (
96
+ <div>
97
+ <h1>My App</h1>
98
+ <ConnectWalletButton label="Sign in" ConnectButton={CustomButtonComponent} />
99
+ </div>
100
+ )
78
101
  }
79
102
  ```
80
103
 
@@ -109,20 +132,23 @@ That's it! The `ConnectWalletButton` provides a complete authentication UI with
109
132
  projectId="your-project-id"
110
133
  initialConfig={{
111
134
  // UI customization
135
+ preferedColorMode?: 'light', // 'light' | 'dark'
136
+
112
137
  ui: {
113
- theme: 'dark', // 'light' | 'dark' | 'auto'
114
138
  title: 'Welcome to MyApp',
115
139
  subtitle: 'Sign in to continue',
140
+
141
+ // beta
142
+ dialogClassName: 'string',
143
+
116
144
  authOrder: ['email', 'passkey', 'social'],
117
- modal: {
118
- width: '420px',
119
- borderRadius: '24px'
120
- },
145
+
121
146
  branding: {
122
147
  tagline: 'Powered by MPC',
123
148
  link: { text: 'Learn More', url: 'https://example.com/docs' },
124
149
  },
125
- // Custom colors
150
+
151
+ // TO BE DEPRECATED, cssv is used
126
152
  colors: {
127
153
  dark: {
128
154
  background: '#060117',
@@ -241,20 +267,21 @@ That's it! The `ConnectWalletButton` provides a complete authentication UI with
241
267
 
242
268
  ## Using Hooks
243
269
 
244
- > **Note:** The old `useLumiaSession` and `LumiaSessionProvider` names are deprecated but still supported for backward compatibility. They will show a console warning and will be removed in v2.0.0. Please migrate to the new names: `useLumiaPassportSession` and `LumiaPassportSessionProvider`.
270
+ > **Note:** The `useLumiaPassportSession` hook is based on pure Zustand store so if you already using hook consider 2 options: 1) refactor state extarction so it uses zustand state extraction feature. 2) consider using new session hooks: `useLumiaPassportAccountSession`, `useLumiaPassportAddress` etc. Otherwise you might experience excessive re-rendering issues
245
271
 
246
- ### useLumiaPassportSession - Authentication and Session State
272
+ ### useLumiaPassportAccountSession, useLumiaPassportLoadingStatus, useLumiaPassportBalance, useLumiaPassportIFrameReady, useLumiaPassportAddress, useLumiaPassportError, useLumiaPassportLoadingStatus, useLumiaPassportRecoveryUserId, useLumiaPassportHasServerVault
247
273
 
248
274
  ```tsx
249
- import { useLumiaPassportSession } from '@lumiapassport/ui-kit';
275
+ import { useLumiaPassportAccountSession, useLumiaPassportLoadingStatus } from '@lumiapassport/ui-kit'
250
276
 
251
277
  function MyComponent() {
252
- const { session, isLoading } = useLumiaPassportSession();
278
+ const session = useLumiaPassportAccountSession() // const session = useLumiaPassportSession(s => s.session) - with prev hook & Zustand state extraction feature
279
+ const { isSessionLoading } = useLumiaPassportLoadingStatus()
253
280
 
254
- if (isLoading) return <div>Loading...</div>;
281
+ if (isSessionLoading) return <div>Loading...</div>
255
282
 
256
283
  if (!session) {
257
- return <div>Not authenticated. Please connect your wallet.</div>;
284
+ return <div>Not authenticated. Please connect your wallet.</div>
258
285
  }
259
286
 
260
287
  return (
@@ -264,30 +291,30 @@ function MyComponent() {
264
291
  <p>Wallet Address: {session.ownerAddress}</p>
265
292
  <p>Smart Account: {session.accountAddress}</p>
266
293
  </div>
267
- );
294
+ )
268
295
  }
269
296
  ```
270
297
 
271
298
  ### useSendTransaction - Send Transactions
272
299
 
273
300
  ```tsx
274
- import { useSendTransaction } from '@lumiapassport/ui-kit';
301
+ import { useSendTransaction } from '@lumiapassport/ui-kit'
275
302
 
276
303
  function TransactionExample() {
277
- const { sendTransaction, isPending } = useSendTransaction();
304
+ const { sendTransaction, isPending } = useSendTransaction()
278
305
 
279
306
  const handleSend = async () => {
280
307
  try {
281
308
  const userOpHash = await sendTransaction({
282
309
  to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
283
310
  value: '1000000000000000000', // 1 ETH in wei
284
- data: '0x', // Optional contract call data
285
- });
286
- console.log('UserOp hash:', userOpHash);
311
+ data: '0x' // Optional contract call data
312
+ })
313
+ console.log('UserOp hash:', userOpHash)
287
314
  } catch (error) {
288
- console.error('Transaction failed:', error);
315
+ console.error('Transaction failed:', error)
289
316
  }
290
- };
317
+ }
291
318
 
292
319
  return (
293
320
  <div>
@@ -295,7 +322,7 @@ function TransactionExample() {
295
322
  {isPending ? 'Sending...' : 'Send Transaction'}
296
323
  </button>
297
324
  </div>
298
- );
325
+ )
299
326
  }
300
327
  ```
301
328
 
@@ -304,39 +331,40 @@ function TransactionExample() {
304
331
  For direct control without using the React hook, you can use `sendUserOperation` function:
305
332
 
306
333
  ```tsx
307
- import { sendUserOperation, useLumiaPassportSession } from '@lumiapassport/ui-kit';
334
+ import { sendUserOperation, useLumiaPassportAccountSession } from '@lumiapassport/ui-kit'
308
335
 
309
336
  function DirectTransactionExample() {
310
- const { session } = useLumiaPassportSession();
337
+ const session = useLumiaPassportAccountSession()
311
338
 
312
339
  const handleSend = async () => {
313
340
  if (!session) {
314
- console.error('No active session');
315
- return;
341
+ console.error('No active session')
342
+ return
316
343
  }
317
344
 
318
345
  try {
319
346
  // Send transaction directly with full control
320
347
  const userOpHash = await sendUserOperation(
321
- session, // Required: session from useLumiaPassportSession
348
+ session, // Required: session from useLumiaPassportAccountSession
322
349
  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', // to address
323
- '1000000000000000000', // value in wei (1 ETH)
324
- '0x', // data (optional contract call)
325
- 'standard', // fee type: 'economy' | 'standard' | 'fast'
326
- 'v0.7' // EntryPoint version
327
- );
350
+ '1000000000000000000', // value in wei (1 ETH)
351
+ '0x', // data (optional contract call)
352
+ 'standard', // fee type: 'economy' | 'standard' | 'fast'
353
+ 'v0.7' // EntryPoint version
354
+ )
328
355
 
329
- console.log('Transaction submitted:', userOpHash);
356
+ console.log('Transaction submitted:', userOpHash)
330
357
  } catch (error) {
331
- console.error('Transaction failed:', error);
358
+ console.error('Transaction failed:', error)
332
359
  }
333
- };
360
+ }
334
361
 
335
- return <button onClick={handleSend}>Send Transaction</button>;
362
+ return <button onClick={handleSend}>Send Transaction</button>
336
363
  }
337
364
  ```
338
365
 
339
366
  **When to use:**
367
+
340
368
  - ✅ Use `useSendTransaction()` hook for React components (automatic session management)
341
369
  - ✅ Use `sendUserOperation()` function for custom logic, utility functions, or non-React code
342
370
 
@@ -347,43 +375,46 @@ Deploy the smart account contract immediately after registration. This is **opti
347
375
  **Smart behavior:** Automatically checks if account is already deployed and skips transaction to save gas.
348
376
 
349
377
  ```tsx
350
- import { deployAccount, useLumiaPassportSession } from '@lumiapassport/ui-kit';
378
+ import { deployAccount, useLumiaPassportAccountSession } from '@lumiapassport/ui-kit'
351
379
 
352
380
  function DeployAccountExample() {
353
- const { session } = useLumiaPassportSession();
381
+ const session = useLumiaPassportAccountSession()
354
382
 
355
383
  const handleDeploy = async () => {
356
- if (!session) return;
384
+ if (!session) return
357
385
 
358
386
  try {
359
387
  // Deploy account with minimal gas cost (skips if already deployed)
360
- const userOpHash = await deployAccount(session, 'economy');
388
+ const userOpHash = await deployAccount(session, 'economy')
361
389
 
362
390
  if (userOpHash) {
363
- console.log('Account deployed:', userOpHash);
391
+ console.log('Account deployed:', userOpHash)
364
392
  } else {
365
- console.log('Account already deployed, skipped');
393
+ console.log('Account already deployed, skipped')
366
394
  }
367
395
  } catch (error) {
368
- console.error('Deployment failed:', error);
396
+ console.error('Deployment failed:', error)
369
397
  }
370
- };
398
+ }
371
399
 
372
- return <button onClick={handleDeploy}>Deploy Account</button>;
400
+ return <button onClick={handleDeploy}>Deploy Account</button>
373
401
  }
374
402
  ```
375
403
 
376
404
  **Return values:**
405
+
377
406
  - Returns `userOpHash` (string) - if deployment was needed and executed
378
407
  - Returns `null` - if account already deployed (saves gas)
379
408
 
380
409
  **Advanced usage:**
410
+
381
411
  ```tsx
382
412
  // Force deployment even if already deployed (not recommended)
383
- const hash = await deployAccount(session, 'economy', { force: true });
413
+ const hash = await deployAccount(session, 'economy', { force: true })
384
414
  ```
385
415
 
386
416
  **Why use this?**
417
+
387
418
  - ✅ **Pre-deploy** account before first real transaction
388
419
  - ✅ **No user consent** required (safe minimal operation)
389
420
  - ✅ **Cleaner UX** - separate deployment from first payment
@@ -391,6 +422,7 @@ const hash = await deployAccount(session, 'economy', { force: true });
391
422
  - ⚠️ **Optional** - accounts auto-deploy on first transaction anyway
392
423
 
393
424
  **How it works:**
425
+
394
426
  1. Checks if smart account contract exists on-chain
395
427
  2. If exists: returns `null` immediately (no gas cost)
396
428
  3. If not exists: sends minimal UserOperation (`to=0x0, value=0, data=0x`)
@@ -401,69 +433,77 @@ const hash = await deployAccount(session, 'economy', { force: true });
401
433
  Sign structured data according to [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard. This is commonly used for off-chain signatures in dApps (e.g., NFT marketplace orders, gasless transactions, permit signatures).
402
434
 
403
435
  ```tsx
404
- import { signTypedData, useLumiaPassportSession } from '@lumiapassport/ui-kit';
436
+ import { signTypedData, useLumiaPassportAccountSession } from '@lumiapassport/ui-kit'
405
437
 
406
438
  function SignatureExample() {
407
- const { session } = useLumiaPassportSession();
439
+ const session = useLumiaPassportAccountSession()
408
440
 
409
441
  const handleSign = async () => {
410
- if (!session) return;
442
+ if (!session) return
411
443
 
412
444
  try {
413
445
  // Define EIP712 typed data
414
446
  const signature = await signTypedData(session, {
415
447
  domain: {
416
- name: 'MyDApp', // Your dApp name (must match contract)
417
- version: '1', // Contract version
418
- chainId: 994, // Lumia Prism Testnet
419
- verifyingContract: '0x...', // Your contract address (REQUIRED in production!)
448
+ name: 'MyDApp', // Your dApp name (must match contract)
449
+ version: '1', // Contract version
450
+ chainId: 994, // Lumia Prism Testnet
451
+ verifyingContract: '0x...' // Your contract address (REQUIRED in production!)
420
452
  },
421
453
  types: {
422
454
  Order: [
423
455
  { name: 'tokenIds', type: 'uint256[]' },
424
456
  { name: 'price', type: 'uint256' },
425
- { name: 'deadline', type: 'uint256' },
426
- ],
457
+ { name: 'deadline', type: 'uint256' }
458
+ ]
427
459
  },
428
460
  primaryType: 'Order',
429
461
  message: {
430
462
  tokenIds: [1n, 2n, 3n],
431
463
  price: 1000000000000000000n, // 1 token in wei
432
- deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), // 1 hour from now
433
- },
434
- });
464
+ deadline: BigInt(Math.floor(Date.now() / 1000) + 3600) // 1 hour from now
465
+ }
466
+ })
435
467
 
436
- console.log('Signature:', signature);
468
+ console.log('Signature:', signature)
437
469
 
438
470
  // Verify signature (optional)
439
- const { recoverTypedDataAddress } = await import('viem');
471
+ const { recoverTypedDataAddress } = await import('viem')
440
472
  const recoveredAddress = await recoverTypedDataAddress({
441
- domain: { /* same domain */ },
442
- types: { /* same types */ },
473
+ domain: {
474
+ /* same domain */
475
+ },
476
+ types: {
477
+ /* same types */
478
+ },
443
479
  primaryType: 'Order',
444
- message: { /* same message */ },
445
- signature,
446
- });
480
+ message: {
481
+ /* same message */
482
+ },
483
+ signature
484
+ })
447
485
 
448
- console.log('Signer:', recoveredAddress); // Should match session.ownerAddress
486
+ console.log('Signer:', recoveredAddress) // Should match session.ownerAddress
449
487
  } catch (error) {
450
- console.error('Signing failed:', error);
488
+ console.error('Signing failed:', error)
451
489
  }
452
- };
490
+ }
453
491
 
454
- return <button onClick={handleSign}>Sign Message</button>;
492
+ return <button onClick={handleSign}>Sign Message</button>
455
493
  }
456
494
  ```
457
495
 
458
496
  **Important Notes about ERC-4337 Smart Accounts:**
459
497
 
460
498
  In Account Abstraction (ERC-4337), there are **two addresses**:
499
+
461
500
  1. **Owner Address (EOA)** - The address that signs messages/transactions
462
501
  2. **Smart Account Address** - The contract wallet address
463
502
 
464
503
  ⚠️ **Critical:** The signature is created by the **owner address** (EOA), NOT the smart account address!
465
504
 
466
505
  **Compatibility with existing protocols:**
506
+
467
507
  - ✅ **Works:** Protocols that verify signatures off-chain (e.g., your backend verifies the owner EOA signature)
468
508
  - ⚠️ **May not work:** Protocols designed for EOA wallets that store and verify against `msg.sender` or wallet address
469
509
  - Example: Uniswap Permit2, some NFT marketplaces
@@ -472,16 +512,19 @@ In Account Abstraction (ERC-4337), there are **two addresses**:
472
512
  - **Solution:** Use ERC-1271 signature validation in your smart contracts (allows contracts to validate signatures)
473
513
 
474
514
  **Domain Configuration:**
515
+
475
516
  - In production, use your actual `verifyingContract` address (not zero address!)
476
517
  - The `domain` parameters must match exactly between frontend and smart contract
477
518
  - The `chainId` should match the network you're deploying to
478
519
 
479
520
  **Technical Details:**
521
+
480
522
  - Shows a MetaMask-like confirmation modal with structured message preview
481
523
  - All BigInt values are supported in the message
482
524
  - Signature can be verified using `viem.recoverTypedDataAddress()` - will return owner EOA address
483
525
 
484
526
  **When to use signTypedData:**
527
+
485
528
  - ✅ Custom backend signature verification (you control the verification logic)
486
529
  - ✅ Gasless transactions with meta-transaction relayers
487
530
  - ✅ DAO voting and governance (off-chain signatures)
@@ -491,13 +534,13 @@ In Account Abstraction (ERC-4337), there are **two addresses**:
491
534
  ### prepareUserOperation - Prepare for Backend Submission
492
535
 
493
536
  ```tsx
494
- import { prepareUserOperation, useLumiaPassportSession } from '@lumiapassport/ui-kit';
537
+ import { prepareUserOperation, useLumiaPassportAccountSession } from '@lumiapassport/ui-kit'
495
538
 
496
539
  function BackendSubmissionExample() {
497
- const { session } = useLumiaPassportSession();
540
+ const session = useLumiaPassportAccountSession()
498
541
 
499
542
  const handlePrepare = async () => {
500
- if (!session) return;
543
+ if (!session) return
501
544
 
502
545
  // Prepare and sign UserOp without sending to bundler
503
546
  const { userOp, userOpHash } = await prepareUserOperation(
@@ -507,7 +550,7 @@ function BackendSubmissionExample() {
507
550
  '0x', // data
508
551
  'standard', // fee type: 'economy' | 'standard' | 'fast'
509
552
  'v0.7' // EntryPoint version
510
- );
553
+ )
511
554
 
512
555
  // Send to backend for validation and submission
513
556
  await fetch('/api/submit-transaction', {
@@ -517,76 +560,116 @@ function BackendSubmissionExample() {
517
560
  userOp,
518
561
  userOpHash,
519
562
  ownerAddress: session.ownerAddress // for signature verification
520
- }),
521
- });
522
- };
563
+ })
564
+ })
565
+ }
523
566
 
524
- return (
525
- <button onClick={handlePrepare}>
526
- Prepare & Send to Backend
527
- </button>
528
- );
567
+ return <button onClick={handlePrepare}>Prepare & Send to Backend</button>
529
568
  }
530
569
  ```
531
570
 
532
571
  **Backend example (using @lumiapassport/core):**
533
572
 
534
573
  ```typescript
535
- import { sendUserOperationRaw, getUserOperationReceipt } from '@lumiapassport/core';
536
- import { recoverAddress } from 'viem';
574
+ import { getUserOperationReceipt, sendUserOperationRaw } from '@lumiapassport/core'
575
+ import { recoverAddress } from 'viem'
537
576
 
538
577
  // Receive from frontend
539
- const { userOp, userOpHash, ownerAddress } = await request.json();
578
+ const { userOp, userOpHash, ownerAddress } = await request.json()
540
579
 
541
580
  // Verify signature
542
581
  const recoveredAddress = await recoverAddress({
543
582
  hash: userOpHash,
544
- signature: userOp.signature,
545
- });
583
+ signature: userOp.signature
584
+ })
546
585
 
547
586
  if (recoveredAddress.toLowerCase() !== ownerAddress.toLowerCase()) {
548
- throw new Error('Invalid signature');
587
+ throw new Error('Invalid signature')
549
588
  }
550
589
 
551
590
  // Submit to bundler - returns userOpHash
552
- const submittedUserOpHash = await sendUserOperationRaw(userOp);
591
+ const submittedUserOpHash = await sendUserOperationRaw(userOp)
553
592
 
554
593
  // Poll for receipt to get transaction hash and status
555
594
  const waitForReceipt = async (userOpHash: string, maxAttempts = 60, delayMs = 1000) => {
556
595
  for (let i = 0; i < maxAttempts; i++) {
557
- const receipt = await getUserOperationReceipt(userOpHash as `0x${string}`);
596
+ const receipt = await getUserOperationReceipt(userOpHash as `0x${string}`)
558
597
  if (receipt) {
559
598
  return {
560
599
  success: receipt.success,
561
600
  transactionHash: receipt.receipt?.transactionHash,
562
- blockNumber: receipt.receipt?.blockNumber,
563
- };
601
+ blockNumber: receipt.receipt?.blockNumber
602
+ }
564
603
  }
565
- await new Promise(resolve => setTimeout(resolve, delayMs));
604
+ await new Promise((resolve) => setTimeout(resolve, delayMs))
566
605
  }
567
- throw new Error('Transaction timeout');
568
- };
606
+ throw new Error('Transaction timeout')
607
+ }
569
608
 
570
- const result = await waitForReceipt(submittedUserOpHash);
609
+ const result = await waitForReceipt(submittedUserOpHash)
571
610
  return {
572
611
  success: result.success,
573
612
  transactionHash: result.transactionHash,
574
613
  blockNumber: result.blockNumber
575
- };
614
+ }
576
615
  ```
577
616
 
578
- ## Components
617
+ ### useLumiaPassportOpen - Programmatic LumiaPassport Dialog Control
618
+
619
+ Control the Lumia Passport dialog programmatically.
620
+
621
+ ```tsx
622
+ import { PageKey, useLumiaPassportOpen } from '@lumiapassport/ui-kit'
623
+
624
+ function CustomAuthButton() {
625
+ const { isOpen, open: openLumiaPassport, close } = useLumiaPassportOpen()
626
+
627
+ return (
628
+ <div>
629
+ <button onClick={() => openLumiaPassport(PageKey.AUTH)}>Sign In</button>
630
+ <button onClick={() => openLumiaPassport(PageKey.RECEIVE)}>Receive LUMIA</button>
631
+
632
+ <button onClick={close}>Close Dialog</button>
633
+ </div>
634
+ )
635
+ }
636
+ ```
637
+
638
+ ### useLumiaPassportColorMode - Theme Control
639
+
640
+ Control light/dark mode for Lumia Passport UI. Use hook to sync colorMode inside your App instead of any local colorMode states
641
+
642
+ ```tsx
643
+ import { useLumiaPassportColorMode } from '@lumiapassport/ui-kit'
644
+
645
+ function ThemeSelector() {
646
+ const { colorMode, setColorMode } = useLumiaPassportColorMode()
647
+
648
+ return (
649
+ <div>
650
+ <p>Current theme: {colorMode}</p>
651
+ <button onClick={() => setColorMode('light')}>Light</button>
652
+ <button onClick={() => setColorMode('dark')}>Dark</button>
653
+ </div>
654
+ )
655
+ }
656
+ ```
579
657
 
580
- ### ConnectWalletButton
658
+ ### ThemeToggle - Quick Theme Switcher
581
659
 
582
- Pre-built button with authentication modal.
660
+ Pre-built theme toggle button component to use in combo with useLumiaPassportColorMode.
583
661
 
584
662
  ```tsx
585
- <ConnectWalletButton
586
- className="custom-class"
587
- onConnect={(user) => console.log('Connected:', user)}
588
- onDisconnect={() => console.log('Disconnected')}
589
- />
663
+ import { ThemeToggle } from '@lumiapassport/ui-kit'
664
+
665
+ function AppHeader() {
666
+ return (
667
+ <header>
668
+ <h1>My App</h1>
669
+ <ThemeToggle />
670
+ </header>
671
+ )
672
+ }
590
673
  ```
591
674
 
592
675
  ## Authentication Methods
@@ -635,46 +718,14 @@ Connect existing wallets (MetaMask, WalletConnect, etc.).
635
718
 
636
719
  ## Styling
637
720
 
638
- ### Using Built-in Themes
639
-
640
- ```tsx
641
- import '@lumiapassport/ui-kit/dist/styles.css';
642
-
643
- <LumiaPassportProvider
644
- projectId="your-project-id"
645
- initialConfig={{
646
- ui: {
647
- theme: 'dark', // or 'light', 'auto'
648
- }
649
- }}
650
- >
651
- ```
652
-
653
- ### Custom Styling
654
-
655
- Override CSS variables for custom branding:
656
-
657
- ```css
658
- .lumia-scope {
659
- --lumia-primary: #6366f1;
660
- --lumia-background: #0f172a;
661
- --lumia-surface: #1e293b;
662
- --lumia-text-primary: #f8fafc;
663
- --lumia-text-secondary: #cbd5e1;
664
- }
665
- ```
721
+ ...to be updated
666
722
 
667
723
  ## TypeScript Support
668
724
 
669
725
  Full TypeScript support with exported types:
670
726
 
671
727
  ```tsx
672
- import type {
673
- LumiaPassportConfig,
674
- User,
675
- AuthProvider,
676
- WalletInfo,
677
- } from '@lumiapassport/ui-kit';
728
+ import type { AuthProvider, LumiaPassportConfig, User, WalletInfo } from '@lumiapassport/ui-kit'
678
729
  ```
679
730
 
680
731
  ## Examples