@txnlab/use-wallet-ui-react 1.3.0 → 1.4.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 -2
- package/dist/cjs/chunks/passkey-C8Dw6sNL.cjs +2 -0
- package/dist/cjs/chunks/passkey-C8Dw6sNL.cjs.map +1 -0
- package/dist/cjs/index.cjs +14 -14
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/plugins/passkey.cjs +2 -0
- package/dist/cjs/plugins/passkey.cjs.map +1 -0
- package/dist/esm/chunks/passkey-BbgvIGki.js +44 -0
- package/dist/esm/chunks/passkey-BbgvIGki.js.map +1 -0
- package/dist/esm/index.js +2966 -2679
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/plugins/passkey.js +578 -0
- package/dist/esm/plugins/passkey.js.map +1 -0
- package/dist/style.css +152 -0
- package/dist/types/components/ConnectWalletMenu.d.ts +7 -1
- package/dist/types/components/ConnectWalletMenu.d.ts.map +1 -1
- package/dist/types/components/ConnectedWalletMenu.d.ts.map +1 -1
- package/dist/types/components/PasskeyConnect.d.ts +29 -0
- package/dist/types/components/PasskeyConnect.d.ts.map +1 -0
- package/dist/types/components/WalletButton.d.ts +7 -1
- package/dist/types/components/WalletButton.d.ts.map +1 -1
- package/dist/types/components/WalletGroupLabel.d.ts +6 -0
- package/dist/types/components/WalletGroupLabel.d.ts.map +1 -0
- package/dist/types/components/WalletIcon.d.ts +6 -0
- package/dist/types/components/WalletIcon.d.ts.map +1 -0
- package/dist/types/components/WalletList.d.ts.map +1 -1
- package/dist/types/index.d.cts +5 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/plugins/passkey/PasskeyDisclosure.d.ts +11 -0
- package/dist/types/plugins/passkey/PasskeyDisclosure.d.ts.map +1 -0
- package/dist/types/plugins/passkey/PasskeyRecoveryDialog.d.ts +10 -0
- package/dist/types/plugins/passkey/PasskeyRecoveryDialog.d.ts.map +1 -0
- package/dist/types/plugins/passkey/PasskeyRecoveryMenuButton.d.ts +5 -0
- package/dist/types/plugins/passkey/PasskeyRecoveryMenuButton.d.ts.map +1 -0
- package/dist/types/plugins/passkey/PasskeySessionControl.d.ts +6 -0
- package/dist/types/plugins/passkey/PasskeySessionControl.d.ts.map +1 -0
- package/dist/types/plugins/passkey/constants.d.ts +3 -0
- package/dist/types/plugins/passkey/constants.d.ts.map +1 -0
- package/dist/types/plugins/passkey/index.d.cts +36 -0
- package/dist/types/plugins/passkey/index.d.ts +36 -0
- package/dist/types/plugins/passkey/index.d.ts.map +1 -0
- package/dist/types/plugins/passkey/index.test.d.ts +2 -0
- package/dist/types/plugins/passkey/index.test.d.ts.map +1 -0
- package/dist/types/plugins/passkey/storage.d.ts +5 -0
- package/dist/types/plugins/passkey/storage.d.ts.map +1 -0
- package/dist/types/plugins/passkey/storage.test.d.ts +2 -0
- package/dist/types/plugins/passkey/storage.test.d.ts.map +1 -0
- package/dist/types/plugins/passkey/usePasskeyAdapter.d.ts +10 -0
- package/dist/types/plugins/passkey/usePasskeyAdapter.d.ts.map +1 -0
- package/dist/types/providers/WalletUIProvider.d.ts +15 -1
- package/dist/types/providers/WalletUIProvider.d.ts.map +1 -1
- package/dist/types/utils/passkey.d.ts +59 -0
- package/dist/types/utils/passkey.d.ts.map +1 -0
- package/dist/types/utils/passkey.test.d.ts +2 -0
- package/dist/types/utils/passkey.test.d.ts.map +1 -0
- package/package.json +13 -2
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ Ready-to-use React UI components for Algorand wallet integration, built as a com
|
|
|
18
18
|
- [Hooks](#hooks)
|
|
19
19
|
- [Tanstack Query Integration](#tanstack-query-integration)
|
|
20
20
|
- [Plugins](#plugins)
|
|
21
|
+
- [Passkey Wallet](#passkey-wallet)
|
|
21
22
|
- [Migration from v0.x](#migration-from-v0x)
|
|
22
23
|
- [License](#license)
|
|
23
24
|
|
|
@@ -322,6 +323,7 @@ Required wrapper that enables theming, NFD lookups, and data prefetching.
|
|
|
322
323
|
enablePrefetching={true} // Prefetch data for all wallet accounts
|
|
323
324
|
prefetchNfdView="thumbnail" // NFD data view: 'tiny' | 'thumbnail' | 'brief' | 'full'
|
|
324
325
|
queryClient={queryClient} // Optional: your existing Tanstack Query client
|
|
326
|
+
passkeyLayout="list" // Passkey wallet layout: 'list' | 'featured'
|
|
325
327
|
>
|
|
326
328
|
{children}
|
|
327
329
|
</WalletUIProvider>
|
|
@@ -336,6 +338,7 @@ All-in-one wallet connection component.
|
|
|
336
338
|
size="md" // 'sm' | 'md' | 'lg'
|
|
337
339
|
className="..." // Additional CSS classes
|
|
338
340
|
style={{...}} // Inline styles (supports CSS variable overrides)
|
|
341
|
+
passkeyLayout="featured" // Optional: overrides WalletUIProvider's passkeyLayout
|
|
339
342
|
/>
|
|
340
343
|
```
|
|
341
344
|
|
|
@@ -356,6 +359,9 @@ Dropdown menu for wallet selection (disconnected state).
|
|
|
356
359
|
<ConnectWalletMenu>
|
|
357
360
|
<button>My Custom Button</button>
|
|
358
361
|
</ConnectWalletMenu>
|
|
362
|
+
|
|
363
|
+
// With its own passkey layout (overrides WalletUIProvider's passkeyLayout)
|
|
364
|
+
<ConnectWalletMenu passkeyLayout="featured" />
|
|
359
365
|
```
|
|
360
366
|
|
|
361
367
|
### ConnectWalletButton
|
|
@@ -426,12 +432,31 @@ function Profile() {
|
|
|
426
432
|
|
|
427
433
|
### WalletList
|
|
428
434
|
|
|
429
|
-
Renders a list of
|
|
435
|
+
Renders a list of wallets (used internally by ConnectWalletMenu). The dialog renders the passkey wallet in its own section above the list, so pass the other wallets here.
|
|
436
|
+
|
|
437
|
+
```jsx
|
|
438
|
+
<WalletList
|
|
439
|
+
wallets={wallets}
|
|
440
|
+
handleWalletClick={(wallet) => wallet.connect()}
|
|
441
|
+
/>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### PasskeyConnect
|
|
445
|
+
|
|
446
|
+
The passkey section of the connect dialog, for custom connect menus. Signing in (**Continue with passkey**, or **Sign in with passkey** in the list layout) calls `handleWalletClick(wallet)`, and **Create a passkey** calls `handleWalletClick(wallet, { create: true })`. Forward `args` to `wallet.connect(args)` before any `await`, or Safari and iOS browsers drop the passkey prompt. Pass `status` (`{ walletId, pending, error }`) to disable the controls while the prompt is open and to show an error.
|
|
430
447
|
|
|
431
448
|
```jsx
|
|
432
|
-
<
|
|
449
|
+
<PasskeyConnect
|
|
450
|
+
wallet={passkeyWallet}
|
|
451
|
+
handleWalletClick={(wallet, args) => wallet.connect(args)}
|
|
452
|
+
layout="list" // 'list' (default) | 'featured'
|
|
453
|
+
showLabel={true} // 'list' only: show the "Passkey" group label
|
|
454
|
+
/>
|
|
433
455
|
```
|
|
434
456
|
|
|
457
|
+
In the list layout, label your own wallet group to match (the dialog uses "Wallets").
|
|
458
|
+
|
|
459
|
+
|
|
435
460
|
## Hooks
|
|
436
461
|
|
|
437
462
|
### useNfd
|
|
@@ -581,6 +606,74 @@ function App() {
|
|
|
581
606
|
|
|
582
607
|
See the [Plugin Architecture Guide](PLUGINS.md) for full documentation.
|
|
583
608
|
|
|
609
|
+
## Passkey Wallet
|
|
610
|
+
|
|
611
|
+
[`@txnlab/use-wallet-passkey`](https://github.com/TxnLab/use-wallet/tree/main/packages/wallets/passkey#readme) (use-wallet 5.2+) derives an app-scoped Falcon-1024 account from a passkey. Register it, and the connect dialog shows a Passkey group with **Sign in with passkey** and **Create a passkey**, above your other wallets. The [`passkeyLayout`](#passkey-layout) option can lead with a **Continue with passkey** button instead. A missing passkey and a cancelled prompt raise the same browser error, so creating stays a separate choice.
|
|
612
|
+
|
|
613
|
+
```bash
|
|
614
|
+
npm install @txnlab/use-wallet-passkey
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
```tsx
|
|
618
|
+
import { lute } from '@galaxypay/use-wallet-lute'
|
|
619
|
+
import { pera } from '@perawallet/use-wallet-pera'
|
|
620
|
+
import { passkey } from '@txnlab/use-wallet-passkey'
|
|
621
|
+
import { WalletManager, WalletProvider } from '@txnlab/use-wallet-react'
|
|
622
|
+
import { WalletButton, WalletUIProvider } from '@txnlab/use-wallet-ui-react'
|
|
623
|
+
import { passkeyPlugin } from '@txnlab/use-wallet-ui-react/plugins/passkey'
|
|
624
|
+
|
|
625
|
+
const manager = new WalletManager({
|
|
626
|
+
wallets: [passkey({ session: true }), lute(), pera()],
|
|
627
|
+
})
|
|
628
|
+
|
|
629
|
+
const plugins = [passkeyPlugin({ session: true })]
|
|
630
|
+
|
|
631
|
+
function App() {
|
|
632
|
+
return (
|
|
633
|
+
<WalletProvider manager={manager}>
|
|
634
|
+
<WalletUIProvider plugins={plugins}>
|
|
635
|
+
<WalletButton />
|
|
636
|
+
</WalletUIProvider>
|
|
637
|
+
</WalletProvider>
|
|
638
|
+
)
|
|
639
|
+
}
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
The connect dialog:
|
|
643
|
+
|
|
644
|
+
- Starts the passkey prompt straight from the tap, as Safari and iOS browsers require
|
|
645
|
+
- While the prompt is open, shows "Waiting for your passkey…" on the control the user pressed and dims the other
|
|
646
|
+
- Stays open on passkey errors and explains them: a cancelled or timed-out prompt (or no passkey found), an in-app browser (open the page in Safari or Chrome), or a passkey provider without the PRF extension (try another provider)
|
|
647
|
+
|
|
648
|
+
The connected wallet menu tags a passkey account with its domain (for example, `Passkey · localhost`), since the account belongs to the site that created it.
|
|
649
|
+
|
|
650
|
+
`passkeyPlugin()` adds to the connected wallet menu, only while the passkey wallet is active:
|
|
651
|
+
|
|
652
|
+
- **Back up account**: a dialog that reveals the account's 25-word recovery phrase after a fresh passkey prompt, and tells users to import it as a Falcon / quantum account (in Lute, Add account → Falcon25 account → Import; in Pera, the quantum import). It hides the phrase after a timeout and clears the clipboard when it closes, if it can.
|
|
653
|
+
- **Session status** (with `session: true`): Locked or Unlocked, with Unlock and Lock buttons
|
|
654
|
+
- **A note on whose account it is** (with `disclosure: true`): "This account is created by and for example.com. Keep only what you need here, and move larger amounts to a wallet you control." It shows until the user chooses **Got it**, once per account.
|
|
655
|
+
|
|
656
|
+
The plugin uses `useWalletManager()`, so it requires `@txnlab/use-wallet-react` 5.2 or later, which any app with the passkey wallet has. The main entry still supports v4.6+. See [Passkey Plugin](PLUGINS.md#passkey-plugin) for options, and the adapter's [security model](https://github.com/TxnLab/use-wallet/tree/main/packages/wallets/passkey#security-model) before you ship it.
|
|
657
|
+
|
|
658
|
+
For your own connect UI, `getPasskeyErrorMessage(error)` returns a message for a `PasskeyError`, or `null` for any other error.
|
|
659
|
+
|
|
660
|
+
### Passkey layout
|
|
661
|
+
|
|
662
|
+
Choose how the connect dialog presents the passkey wallet with `passkeyLayout`:
|
|
663
|
+
|
|
664
|
+
- **`'list'`** (default): **Sign in with passkey** and **Create a passkey** rows in a "Passkey" group, above a "Wallets" group. For crypto-native apps where most users bring a wallet like Pera or Lute, and the passkey is one choice among many.
|
|
665
|
+
- **`'featured'`**: a full-width **Continue with passkey** button and a "New here? **Create a passkey**" link, then the other wallets under "or connect a wallet". For consumer apps where most users have no wallet, so the passkey is the main way in.
|
|
666
|
+
|
|
667
|
+
```tsx
|
|
668
|
+
// App-wide
|
|
669
|
+
<WalletUIProvider passkeyLayout="featured">
|
|
670
|
+
|
|
671
|
+
// Per menu: a WalletButton or ConnectWalletMenu prop wins over the provider
|
|
672
|
+
<WalletButton passkeyLayout="list" />
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
With only the passkey wallet configured, neither layout shows the other-wallets heading. Without a passkey wallet, the dialog is the same in both.
|
|
676
|
+
|
|
584
677
|
## License
|
|
585
678
|
|
|
586
679
|
MIT
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const n="passkey";function a(e,s){return e??s??"list"}function i(e){return(e==null?void 0:e.id)===n}function t(e){if(!(e instanceof Error)||e.name!=="PasskeyError")return null;const{code:s}=e;return typeof s=="string"?s:null}function u(e){const s=t(e);if(!s)return null;switch(s){case"cancelled":return"The passkey request was cancelled or timed out, or no passkey was found.";case"unsupported":return"This browser can't use passkeys here. If you opened this page inside another app, open it in Safari or Chrome instead.";case"prf-unsupported":return"Your passkey provider doesn't support passkey accounts. Try a different provider, such as iCloud Keychain or Google Password Manager.";case"key-mismatch":return"This passkey belongs to a different account. Choose the passkey you used for this account.";default:return e.message||"The passkey request failed."}}function c(e){const r=(e==null?void 0:e.lastIndexOf(" · "))??-1;if(e&&r!==-1){const o=e.slice(r+3).trim();if(o)return o}return typeof location<"u"?location.hostname:""}exports.getPasskeyAccountDomain=c;exports.getPasskeyErrorCode=t;exports.getPasskeyErrorMessage=u;exports.isPasskeyWallet=i;exports.resolvePasskeyLayout=a;
|
|
2
|
+
//# sourceMappingURL=passkey-C8Dw6sNL.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey-C8Dw6sNL.cjs","sources":["../../../src/utils/passkey.ts"],"sourcesContent":["/** The wallet id registered by `passkey()` from `@txnlab/use-wallet-passkey` */\nexport const PASSKEY_WALLET_ID = 'passkey'\n\n/**\n * The `PasskeyAdapter` members this library uses. Typed structurally so the\n * library needs no dependency on `@txnlab/use-wallet-passkey`.\n */\nexport interface PasskeyWalletAdapter {\n /** True when the session key is unlocked */\n readonly isUnlocked: boolean\n /** Unlock the session with one passkey prompt */\n unlock: () => Promise<void>\n /** Drop the session key; the account stays connected */\n lock: () => void\n /** Return the account's recovery phrase after a fresh passkey prompt */\n exportRecoveryPhrase: () => Promise<{ scheme: 'falcon-1024'; phrase: string }>\n}\n\n/** The status of a passkey connect request, shown under the passkey section */\nexport interface PasskeyConnectStatus {\n walletId: string\n pending: boolean\n error: string | null\n /** Which control started the request, so it can show the pending state */\n action?: 'sign-in' | 'create'\n}\n\n/**\n * How the connect dialog presents a passkey wallet:\n * - `'list'` (default): \"Sign in with passkey\" and \"Create a passkey\" rows in\n * a Passkey group above a Wallets group. Suits apps where most users bring\n * a wallet.\n * - `'featured'`: a \"Continue with passkey\" button leads, with the other\n * wallets below. Suits apps where most users have no wallet.\n */\nexport type PasskeyConnectLayout = 'featured' | 'list'\n\n/** A menu's own layout wins over the provider's; the default is `'list'` */\nexport function resolvePasskeyLayout(\n menuLayout?: PasskeyConnectLayout,\n providerLayout?: PasskeyConnectLayout,\n): PasskeyConnectLayout {\n return menuLayout ?? providerLayout ?? 'list'\n}\n\n/** Arguments for connecting the passkey wallet */\nexport interface PasskeyConnectArgs {\n /** Create a new passkey (and account) instead of signing in */\n create?: boolean\n}\n\nexport function isPasskeyWallet(\n wallet: { id: string } | null | undefined,\n): boolean {\n return wallet?.id === PASSKEY_WALLET_ID\n}\n\n/** Returns a `PasskeyError`'s code, or null for any other error */\nexport function getPasskeyErrorCode(error: unknown): string | null {\n if (!(error instanceof Error) || error.name !== 'PasskeyError') return null\n const { code } = error as Error & { code?: unknown }\n return typeof code === 'string' ? code : null\n}\n\n/**\n * Returns a message to show users for a `PasskeyError`, or null for any other\n * error.\n */\nexport function getPasskeyErrorMessage(error: unknown): string | null {\n const code = getPasskeyErrorCode(error)\n if (!code) return null\n\n switch (code) {\n case 'cancelled':\n return 'The passkey request was cancelled or timed out, or no passkey was found.'\n case 'unsupported':\n return \"This browser can't use passkeys here. If you opened this page inside another app, open it in Safari or Chrome instead.\"\n case 'prf-unsupported':\n return \"Your passkey provider doesn't support passkey accounts. Try a different provider, such as iCloud Keychain or Google Password Manager.\"\n case 'key-mismatch':\n return 'This passkey belongs to a different account. Choose the passkey you used for this account.'\n default:\n return (error as Error).message || 'The passkey request failed.'\n }\n}\n\n/**\n * The domain a passkey account belongs to. The adapter names the account\n * `Passkey · <domain>`; fall back to the page's hostname.\n */\nexport function getPasskeyAccountDomain(accountName?: string | null): string {\n const separator = ' · '\n const index = accountName?.lastIndexOf(separator) ?? -1\n if (accountName && index !== -1) {\n const domain = accountName.slice(index + separator.length).trim()\n if (domain) return domain\n }\n return typeof location !== 'undefined' ? location.hostname : ''\n}\n"],"names":["PASSKEY_WALLET_ID","resolvePasskeyLayout","menuLayout","providerLayout","isPasskeyWallet","wallet","getPasskeyErrorCode","error","code","getPasskeyErrorMessage","getPasskeyAccountDomain","accountName","index","domain"],"mappings":"aACO,MAAMA,EAAoB,UAqC1B,SAASC,EACdC,EACAC,EACsB,CACtB,OAAOD,GAAcC,GAAkB,MACzC,CAQO,SAASC,EACdC,EACS,CACT,OAAOA,GAAA,YAAAA,EAAQ,MAAOL,CACxB,CAGO,SAASM,EAAoBC,EAA+B,CACjE,GAAI,EAAEA,aAAiB,QAAUA,EAAM,OAAS,eAAgB,OAAO,KACvE,KAAM,CAAE,KAAAC,GAASD,EACjB,OAAO,OAAOC,GAAS,SAAWA,EAAO,IAC3C,CAMO,SAASC,EAAuBF,EAA+B,CACpE,MAAMC,EAAOF,EAAoBC,CAAK,EACtC,GAAI,CAACC,EAAM,OAAO,KAElB,OAAQA,EAAA,CACN,IAAK,YACH,MAAO,2EACT,IAAK,cACH,MAAO,yHACT,IAAK,kBACH,MAAO,wIACT,IAAK,eACH,MAAO,6FACT,QACE,OAAQD,EAAgB,SAAW,6BAAA,CAEzC,CAMO,SAASG,EAAwBC,EAAqC,CAE3E,MAAMC,GAAQD,GAAA,YAAAA,EAAa,YAAY,SAAc,GACrD,GAAIA,GAAeC,IAAU,GAAI,CAC/B,MAAMC,EAASF,EAAY,MAAMC,EAAQ,CAAgB,EAAE,KAAA,EAC3D,GAAIC,EAAQ,OAAOA,CACrB,CACA,OAAO,OAAO,SAAa,IAAc,SAAS,SAAW,EAC/D"}
|