@reclack/walletkit 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +341 -2
- package/assets/backpack.webp +0 -0
- package/assets/berasig.webp +0 -0
- package/assets/bestwallet.webp +0 -0
- package/assets/bifrostwallet.webp +0 -0
- package/assets/binance.webp +0 -0
- package/assets/bitcoincom.webp +0 -0
- package/assets/bitget.webp +0 -0
- package/assets/bitpay.webp +0 -0
- package/assets/bitski.webp +0 -0
- package/assets/bitverse.webp +0 -0
- package/assets/blockchaincom.webp +0 -0
- package/assets/brave.webp +0 -0
- package/assets/bybit.webp +0 -0
- package/assets/clv.webp +0 -0
- package/assets/coin98.webp +0 -0
- package/assets/coinbase.webp +0 -0
- package/assets/compass.webp +0 -0
- package/assets/core.webp +0 -0
- package/assets/crypto_com.webp +0 -0
- package/assets/ctrl.webp +0 -0
- package/assets/dawn.webp +0 -0
- package/assets/desig.webp +0 -0
- package/assets/enkrypt.webp +0 -0
- package/assets/exodus.webp +0 -0
- package/assets/foxwallet.webp +0 -0
- package/assets/frame.webp +0 -0
- package/assets/frontier.webp +0 -0
- package/assets/gate.webp +0 -0
- package/assets/gemini.webp +0 -0
- package/assets/imtoken.webp +0 -0
- package/assets/iopay.webp +0 -0
- package/assets/kaia.webp +0 -0
- package/assets/kaikas.webp +0 -0
- package/assets/kraken.webp +0 -0
- package/assets/kresuswallet.webp +0 -0
- package/assets/ledger.webp +0 -0
- package/assets/magiceden.webp +0 -0
- package/assets/meco.webp +0 -0
- package/assets/metamask.webp +0 -0
- package/assets/mew.webp +0 -0
- package/assets/nest.webp +0 -0
- package/assets/nova.webp +0 -0
- package/assets/okto.webp +0 -0
- package/assets/okx.webp +0 -0
- package/assets/oneinch.webp +0 -0
- package/assets/onekey.webp +0 -0
- package/assets/phantom.webp +0 -0
- package/assets/rabby.webp +0 -0
- package/assets/rainbow.webp +0 -0
- package/assets/ramper.webp +0 -0
- package/assets/ready.webp +0 -0
- package/assets/ronin.webp +0 -0
- package/assets/safe.webp +0 -0
- package/assets/safepal.webp +0 -0
- package/assets/solflare.webp +0 -0
- package/assets/subwallet.webp +0 -0
- package/assets/taho.webp +0 -0
- package/assets/talisman.webp +0 -0
- package/assets/tokenary.webp +0 -0
- package/assets/tokenpocket.webp +0 -0
- package/assets/trust-wallet.webp +0 -0
- package/assets/uniswap.webp +0 -0
- package/assets/universalprofiles.webp +0 -0
- package/assets/valora.webp +0 -0
- package/assets/wigwam.webp +0 -0
- package/assets/xportal.webp +0 -0
- package/assets/zeal.webp +0 -0
- package/assets/zerion.webp +0 -0
- package/custom-elements.json +207 -0
- package/dist/abi.d.ts +21 -0
- package/dist/abi.d.ts.map +1 -0
- package/dist/abi.js +50 -0
- package/dist/abi.js.map +1 -0
- package/dist/address.d.ts +15 -0
- package/dist/address.d.ts.map +1 -0
- package/dist/address.js +25 -0
- package/dist/address.js.map +1 -0
- package/dist/balance.d.ts +78 -0
- package/dist/balance.d.ts.map +1 -0
- package/dist/balance.js +146 -0
- package/dist/balance.js.map +1 -0
- package/dist/base58.d.ts +15 -0
- package/dist/base58.d.ts.map +1 -0
- package/dist/base58.js +52 -0
- package/dist/base58.js.map +1 -0
- package/dist/catalog-fetch.d.ts +18 -0
- package/dist/catalog-fetch.d.ts.map +1 -0
- package/dist/catalog-fetch.js +85 -0
- package/dist/catalog-fetch.js.map +1 -0
- package/dist/catalog.d.ts +57 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +80 -0
- package/dist/catalog.js.map +1 -0
- package/dist/chains.d.ts +32 -0
- package/dist/chains.d.ts.map +1 -0
- package/dist/chains.js +103 -0
- package/dist/chains.js.map +1 -0
- package/dist/config.d.ts +40 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +44 -0
- package/dist/config.js.map +1 -0
- package/dist/deep-links.d.ts +22 -0
- package/dist/deep-links.d.ts.map +1 -0
- package/dist/deep-links.js +201 -0
- package/dist/deep-links.js.map +1 -0
- package/dist/device.d.ts +23 -0
- package/dist/device.d.ts.map +1 -0
- package/dist/device.js +59 -0
- package/dist/device.js.map +1 -0
- package/dist/element/attributes.d.ts +48 -0
- package/dist/element/element.d.ts +92 -0
- package/dist/element/index.d.ts +4 -0
- package/dist/element/props.d.ts +67 -0
- package/dist/element/ui/app.d.ts +22 -0
- package/dist/element/ui/assets.d.ts +7 -0
- package/dist/element/ui/qr.d.ts +16 -0
- package/dist/element/ui/use-handheld.d.ts +8 -0
- package/dist/element/ui/wallet-connect-panel.d.ts +26 -0
- package/dist/element/ui/wallet-dialog.d.ts +37 -0
- package/dist/element/ui/wallet-list.d.ts +26 -0
- package/dist/element/ui/wallet-mark.d.ts +15 -0
- package/dist/element.js +2079 -0
- package/dist/errors.d.ts +34 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +64 -0
- package/dist/errors.js.map +1 -0
- package/dist/evm.d.ts +49 -0
- package/dist/evm.d.ts.map +1 -0
- package/dist/evm.js +217 -0
- package/dist/evm.js.map +1 -0
- package/dist/icons.d.ts +22 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +98 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/intent.d.ts +60 -0
- package/dist/intent.d.ts.map +1 -0
- package/dist/intent.js +2 -0
- package/dist/intent.js.map +1 -0
- package/dist/kit.d.ts +124 -0
- package/dist/kit.d.ts.map +1 -0
- package/dist/kit.js +362 -0
- package/dist/kit.js.map +1 -0
- package/dist/svm.d.ts +45 -0
- package/dist/svm.d.ts.map +1 -0
- package/dist/svm.js +201 -0
- package/dist/svm.js.map +1 -0
- package/dist/theme.d.ts +101 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +217 -0
- package/dist/theme.js.map +1 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/wallet-standard.d.ts +77 -0
- package/dist/wallet-standard.d.ts.map +1 -0
- package/dist/wallet-standard.js +89 -0
- package/dist/wallet-standard.js.map +1 -0
- package/dist/walletconnect.d.ts +74 -0
- package/dist/walletconnect.d.ts.map +1 -0
- package/dist/walletconnect.js +133 -0
- package/dist/walletconnect.js.map +1 -0
- package/package.json +71 -3
- package/vscode.html-custom-data.json +55 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { mobileOS } from './device.js';
|
|
2
|
+
const DEEP_LINKS = {
|
|
3
|
+
// https://go.cb-w.com/dapp?cb_url=<percent-encoded>, per Coinbase's own
|
|
4
|
+
// mobile dapp documentation.
|
|
5
|
+
coinbase: (url) => `https://go.cb-w.com/dapp?cb_url=${encodeURIComponent(url)}`,
|
|
6
|
+
// MetaMask takes the URL bare, with the scheme stripped.
|
|
7
|
+
metamask: (url) => `https://metamask.app.link/dapp/${url.replace(/^https?:\/\//, '')}`,
|
|
8
|
+
// coin_id 60 is Ethereum, which is what selects the dapp browser.
|
|
9
|
+
trust: (url) => `https://link.trustwallet.com/open_url?coin_id=60&url=${encodeURIComponent(url)}`,
|
|
10
|
+
// Phantom wants a referrer as well as the target.
|
|
11
|
+
phantom: (url) => `https://phantom.app/ul/browse/${encodeURIComponent(url)}` +
|
|
12
|
+
`?ref=${encodeURIComponent(new URL(url).origin)}`,
|
|
13
|
+
// Brave Wallet is part of the Brave browser rather than an app of its own,
|
|
14
|
+
// so the hand-off is to open this page in Brave, where the wallet is
|
|
15
|
+
// injected like any extension.
|
|
16
|
+
//
|
|
17
|
+
// There is no universal link for it, so each platform gets its own form
|
|
18
|
+
// and a desktop gets nothing. The Android intent carries a fallback URL,
|
|
19
|
+
// so a phone without Brave stays on the checkout rather than landing on an
|
|
20
|
+
// unknown-scheme error; iOS has no equivalent, and an uninstalled Brave
|
|
21
|
+
// means the link does nothing, which is why the install row stays below.
|
|
22
|
+
brave: (url, platform) => {
|
|
23
|
+
if (platform === 'android') {
|
|
24
|
+
const target = new URL(url);
|
|
25
|
+
return `intent://${target.host}${target.pathname}${target.search}`
|
|
26
|
+
+ '#Intent;scheme=https;package=com.brave.browser;'
|
|
27
|
+
+ `S.browser_fallback_url=${encodeURIComponent(url)};end`;
|
|
28
|
+
}
|
|
29
|
+
if (platform === 'ios') {
|
|
30
|
+
return `brave://open-url?url=${encodeURIComponent(url)}`;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
},
|
|
34
|
+
// https://imtoken.gitbook.io/developers/products/universal-links. A real
|
|
35
|
+
// universal link, so it falls back to a web page when imToken is absent.
|
|
36
|
+
imtoken: (url) => 'https://connect.token.im/link/navigate/DappView'
|
|
37
|
+
+ `?url=${encodeURIComponent(url)}`,
|
|
38
|
+
// https://docs.iopay.me/developer-guides/deep-linking. A custom scheme is
|
|
39
|
+
// all ioPay publishes: nothing to fall back to, and nothing a desktop
|
|
40
|
+
// scanner could usefully encode, so a desktop gets none.
|
|
41
|
+
iopay: (url, platform) => platform
|
|
42
|
+
? `iopay://io.iotex.iopay/open?action=web&url=${encodeURIComponent(url)}`
|
|
43
|
+
: undefined,
|
|
44
|
+
// https://web3.okx.com/build/docs/waas/app-universal-link. OKX wraps this
|
|
45
|
+
// scheme in a download page for the web, but publishes the wrapper's
|
|
46
|
+
// address nowhere this could be checked against, so the scheme goes bare
|
|
47
|
+
// and a desktop gets none.
|
|
48
|
+
okx: (url, platform) => platform
|
|
49
|
+
? `okx://wallet/dapp/url?dappUrl=${encodeURIComponent(url)}`
|
|
50
|
+
: undefined,
|
|
51
|
+
// https://web3.bitget.com/en/docs/configuration/deeplink. bkcode.vip is
|
|
52
|
+
// the https form, which Bitget's own documentation says is the only one
|
|
53
|
+
// Android honours, so it is the only one used here.
|
|
54
|
+
bitget: (url) => `https://bkcode.vip?action=dapp&url=${encodeURIComponent(url)}`,
|
|
55
|
+
// https://docs.solflare.com/solflare/technical/deeplinks/other-methods/browse
|
|
56
|
+
// and https://docs.backpack.app/deeplinks/other-methods/browse. Both took
|
|
57
|
+
// Phantom's shape: the target in the path, the caller in ref.
|
|
58
|
+
solflare: (url) => `https://solflare.com/ul/v1/browse/${encodeURIComponent(url)}` +
|
|
59
|
+
`?ref=${encodeURIComponent(new URL(url).origin)}`,
|
|
60
|
+
backpack: (url) => `https://backpack.app/ul/v1/browse/${encodeURIComponent(url)}` +
|
|
61
|
+
`?ref=${encodeURIComponent(new URL(url).origin)}`,
|
|
62
|
+
// https://help.tokenpocket.pro/developer-en/wallet/pull-up-wallet-with-deeplink.
|
|
63
|
+
// The parameters arrive as a JSON object, encoded whole. Another custom
|
|
64
|
+
// scheme, so a desktop gets none.
|
|
65
|
+
//
|
|
66
|
+
// ETH rather than the chain being paid on: the field picks which of
|
|
67
|
+
// TokenPocket's wallets opens the page, and every chain this checkout
|
|
68
|
+
// settles on is reached by the EVM one, which the page then asks to
|
|
69
|
+
// switch like any other provider.
|
|
70
|
+
tokenpocket: (url, platform) => platform
|
|
71
|
+
? 'tpdapp://open?params='
|
|
72
|
+
+ encodeURIComponent(JSON.stringify({ url, chain: 'ETH' }))
|
|
73
|
+
: undefined,
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Where to send a pairing string so that one wallet receives it.
|
|
77
|
+
*
|
|
78
|
+
* A bare `wc:` URI is a scheme, not an address. Whichever application claimed
|
|
79
|
+
* the scheme answers it, which on a phone with MetaMask installed is MetaMask,
|
|
80
|
+
* whatever wallet the payer picked. These carry the same string to one named
|
|
81
|
+
* application instead.
|
|
82
|
+
*
|
|
83
|
+
* The links are each wallet's own entry in the WalletConnect registry, the
|
|
84
|
+
* list the wallets themselves maintain, taken as published rather than
|
|
85
|
+
* guessed at. A universal link where one exists, since it falls back to a web
|
|
86
|
+
* page when the wallet is absent, and the custom scheme where the universal
|
|
87
|
+
* is a redirect through an install tracker or already carries its own query.
|
|
88
|
+
*
|
|
89
|
+
* A wallet with no entry here is one the registry gives no mobile link for,
|
|
90
|
+
* which generally means it has no phone application at all. That is why this
|
|
91
|
+
* table doubles as the answer to walletScans below: on a phone the panel can
|
|
92
|
+
* still offer the code to copy, but a desktop payer has nothing to paste into
|
|
93
|
+
* and a wallet that lives only in a browser cannot scan.
|
|
94
|
+
*/
|
|
95
|
+
const PAIRING_LINKS = {
|
|
96
|
+
binance: 'https://app.binance.com/cedefi',
|
|
97
|
+
cryptocom: 'https://wallet.crypto.com/deeplink',
|
|
98
|
+
rainbow: 'https://rnbwapp.com',
|
|
99
|
+
rabby: 'rabby://',
|
|
100
|
+
exodus: 'https://exodus.com/m',
|
|
101
|
+
bybit: 'bybitapp://open/route?targetUrl=by://web3/walletconnect/',
|
|
102
|
+
ledger: 'ledgerlive://',
|
|
103
|
+
safe: 'https://app.safe.global/',
|
|
104
|
+
kraken: 'krakenwallet://',
|
|
105
|
+
bitpay: 'https://link.bitpay.com',
|
|
106
|
+
bitcoincom: 'https://wallet.bitcoin.com/',
|
|
107
|
+
blockchaincom: 'https://login.blockchain.com/app',
|
|
108
|
+
// An extension and an iOS application, and it was the extension that hid
|
|
109
|
+
// the application: a wallet that injects used to be taken as reachable.
|
|
110
|
+
berasig: 'berasig://',
|
|
111
|
+
bestwallet: 'https://best-wallet-prod.web.app/connect',
|
|
112
|
+
bifrostwallet: 'https://app.bifrostwallet.com/',
|
|
113
|
+
bitski: 'bitski://',
|
|
114
|
+
bitverse: 'bitverseapp://open/wallet',
|
|
115
|
+
coin98: 'coin98://',
|
|
116
|
+
compass: 'leapcompass://',
|
|
117
|
+
core: 'https://core.app',
|
|
118
|
+
foxwallet: 'https://link.foxwallet.com',
|
|
119
|
+
frontier: 'frontier://',
|
|
120
|
+
gate: 'gtweb3wallet://',
|
|
121
|
+
// This one, okx and tokenpocket have a browser of their own as well, and
|
|
122
|
+
// are reached through it on a phone. They are here for the desktop, where
|
|
123
|
+
// the link into that browser needs a platform nothing has named yet, and
|
|
124
|
+
// the wallet's own scanner is what is left.
|
|
125
|
+
iopay: 'iopay://',
|
|
126
|
+
kaia: 'https://app.kaiawallet.io',
|
|
127
|
+
kresuswallet: 'com.kresus.superapp://',
|
|
128
|
+
magiceden: 'magiceden://',
|
|
129
|
+
meco: 'mecowallet://',
|
|
130
|
+
mew: 'https://mewwallet.com',
|
|
131
|
+
nest: 'nestwallet://',
|
|
132
|
+
nova: 'novawallet://',
|
|
133
|
+
okto: 'okto://',
|
|
134
|
+
// The exchange application's scheme, not the standalone wallet's
|
|
135
|
+
// (okxwallet://main) and not the universal link, which is a download page
|
|
136
|
+
// carrying a query of its own.
|
|
137
|
+
okx: 'okex://main',
|
|
138
|
+
oneinch: 'https://wallet.1inch.io/app/nobodywilleveruseit',
|
|
139
|
+
onekey: 'https://app.onekey.so/wc/connect',
|
|
140
|
+
ready: 'readywallet://',
|
|
141
|
+
ronin: 'https://wallet.roninchain.com',
|
|
142
|
+
safepal: 'https://link.safepal.io',
|
|
143
|
+
subwallet: 'https://mobile.subwallet.app/',
|
|
144
|
+
talisman: 'talisman://',
|
|
145
|
+
// Not the tpdapp:// above: that one opens a page in TokenPocket, this one
|
|
146
|
+
// hands it a session.
|
|
147
|
+
tokenpocket: 'tpoutside://',
|
|
148
|
+
uniswap: 'https://uniswap.org/app',
|
|
149
|
+
universalprofiles: 'io.universaleverything.universalprofiles://wallet-connect',
|
|
150
|
+
valora: 'https://valoraapp.com',
|
|
151
|
+
wigwam: 'https://wigwam.app/',
|
|
152
|
+
xportal: 'https://xportal.app.link',
|
|
153
|
+
zeal: 'zeal://walletconnect/',
|
|
154
|
+
zerion: 'zerion://',
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Whether this wallet has a phone application that can read a pairing code.
|
|
158
|
+
*
|
|
159
|
+
* Read off the table above rather than kept as a second list of its own. Every
|
|
160
|
+
* entry there is a mobile link the wallet published to the WalletConnect
|
|
161
|
+
* registry, and a wallet with no phone application publishes none.
|
|
162
|
+
*
|
|
163
|
+
* Asked by a desktop checkout, where a code can only be scanned. On a phone it
|
|
164
|
+
* can be pasted instead, so one is offered there whatever this says.
|
|
165
|
+
*/
|
|
166
|
+
export function walletScans(id) {
|
|
167
|
+
return id in PAIRING_LINKS;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The link that hands this pairing string to one named wallet, or nothing
|
|
171
|
+
* where that wallet publishes no way to be reached.
|
|
172
|
+
*/
|
|
173
|
+
export function walletPairingLink(id, uri) {
|
|
174
|
+
const base = PAIRING_LINKS[id];
|
|
175
|
+
if (!base) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
// `<link>/wc?uri=<encoded>` is the shape WalletConnect settled on and every
|
|
179
|
+
// link above is published to be used that way, trailing slash included or
|
|
180
|
+
// not, so the only thing to normalise is the slash.
|
|
181
|
+
const prefix = base.endsWith('/') ? base : `${base}/`;
|
|
182
|
+
return `${prefix}wc?uri=${encodeURIComponent(uri)}`;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The link that opens this checkout in one wallet, or nothing if that wallet
|
|
186
|
+
* has no known one.
|
|
187
|
+
*/
|
|
188
|
+
export function walletDeepLink(id, url, platform = mobileOS()) {
|
|
189
|
+
const build = DEEP_LINKS[id];
|
|
190
|
+
if (!build) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
return build(url, platform);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// new URL() on something that is not a URL. Nothing to offer.
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=deep-links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deep-links.js","sourceRoot":"","sources":["../src/deep-links.ts"],"names":[],"mappings":"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"}
|
package/dist/device.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare function isHandheld(): boolean;
|
|
2
|
+
/**
|
|
3
|
+
* isHandheld, kept current: a tablet can be docked to a keyboard mid-session.
|
|
4
|
+
*
|
|
5
|
+
* A subscription rather than a hook, because this package renders nothing.
|
|
6
|
+
* Every UI layer over it has its own way of listening, and all of them can
|
|
7
|
+
* drive this one; the reverse is not true.
|
|
8
|
+
*
|
|
9
|
+
* Returns a cleanup function, and calls back once immediately so a caller
|
|
10
|
+
* never has to read the value separately before subscribing to it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function subscribeHandheld(onChange: (handheld: boolean) => void): () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Which mobile platform this is, if either.
|
|
15
|
+
*
|
|
16
|
+
* Only for picking between two hand-off links that do the same job: a wallet
|
|
17
|
+
* with no universal link needs a custom scheme on iOS and an intent URL on
|
|
18
|
+
* Android, and neither does anything on the other. Nothing else should read
|
|
19
|
+
* this: the feature queries above say what a device can do, which a
|
|
20
|
+
* user-agent string only guesses at.
|
|
21
|
+
*/
|
|
22
|
+
export type MobileOS = 'ios' | 'android';
|
|
23
|
+
export declare function mobileOS(): MobileOS | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AAeA,wBAAgB,UAAU,IAAK,OAAO,CAIrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,GACnC,MAAM,IAAI,CAaZ;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAA;AAExC,wBAAgB,QAAQ,IAAK,QAAQ,GAAG,SAAS,CAgBhD"}
|
package/dist/device.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether this is a touch-primary device: a phone or a tablet.
|
|
3
|
+
*
|
|
4
|
+
* `hover: none` and `pointer: coarse` together, not either alone. A laptop
|
|
5
|
+
* with a touchscreen reports a coarse pointer the moment somebody touches it
|
|
6
|
+
* but still hovers, and treating that as a phone would take the QR away from
|
|
7
|
+
* a payer who needs it. Screen width is deliberately not part of this: a
|
|
8
|
+
* narrow desktop window is still a desktop.
|
|
9
|
+
*
|
|
10
|
+
* Matters because the wallet hand-off is the opposite on each. A desktop
|
|
11
|
+
* payer scans a code to carry the checkout to their phone; a phone payer
|
|
12
|
+
* cannot scan their own screen and needs a link into the wallet instead.
|
|
13
|
+
*/
|
|
14
|
+
const HANDHELD = '(hover: none) and (pointer: coarse)';
|
|
15
|
+
export function isHandheld() {
|
|
16
|
+
return typeof window !== 'undefined'
|
|
17
|
+
&& typeof window.matchMedia === 'function'
|
|
18
|
+
&& window.matchMedia(HANDHELD).matches;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* isHandheld, kept current: a tablet can be docked to a keyboard mid-session.
|
|
22
|
+
*
|
|
23
|
+
* A subscription rather than a hook, because this package renders nothing.
|
|
24
|
+
* Every UI layer over it has its own way of listening, and all of them can
|
|
25
|
+
* drive this one; the reverse is not true.
|
|
26
|
+
*
|
|
27
|
+
* Returns a cleanup function, and calls back once immediately so a caller
|
|
28
|
+
* never has to read the value separately before subscribing to it.
|
|
29
|
+
*/
|
|
30
|
+
export function subscribeHandheld(onChange) {
|
|
31
|
+
if (typeof window === 'undefined'
|
|
32
|
+
|| typeof window.matchMedia !== 'function') {
|
|
33
|
+
onChange(false);
|
|
34
|
+
return () => undefined;
|
|
35
|
+
}
|
|
36
|
+
const query = window.matchMedia(HANDHELD);
|
|
37
|
+
const update = () => onChange(query.matches);
|
|
38
|
+
update();
|
|
39
|
+
query.addEventListener('change', update);
|
|
40
|
+
return () => query.removeEventListener('change', update);
|
|
41
|
+
}
|
|
42
|
+
export function mobileOS() {
|
|
43
|
+
if (typeof navigator === 'undefined') {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const ua = navigator.userAgent;
|
|
47
|
+
if (/android/i.test(ua)) {
|
|
48
|
+
return 'android';
|
|
49
|
+
}
|
|
50
|
+
if (/iphone|ipad|ipod/i.test(ua)) {
|
|
51
|
+
return 'ios';
|
|
52
|
+
}
|
|
53
|
+
// An iPad reports itself as a Mac. A desktop Mac has no touch points.
|
|
54
|
+
if (/macintosh/i.test(ua) && navigator.maxTouchPoints > 1) {
|
|
55
|
+
return 'ios';
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=device.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,QAAQ,GAAG,qCAAqC,CAAA;AAEtD,MAAM,UAAU,UAAU;IACzB,OAAO,OAAO,MAAM,KAAK,WAAW;WAChC,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;WACvC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAA;AACxC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAChC,QAAqC;IAErC,IACC,OAAO,MAAM,KAAK,WAAW;WAC1B,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU,EACzC,CAAC;QACF,QAAQ,CAAC,KAAK,CAAC,CAAA;QACf,OAAO,GAAG,EAAE,CAAC,SAAS,CAAA;IACvB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;IACzC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAC5C,MAAM,EAAE,CAAA;IACR,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IACxC,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;AACzD,CAAC;AAaD,MAAM,UAAU,QAAQ;IACvB,IAAI,OAAO,SAAS,KAAK,WAAW,EAAE,CAAC;QACtC,OAAO,SAAS,CAAA;IACjB,CAAC;IACD,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAA;IAC9B,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QACzB,OAAO,SAAS,CAAA;IACjB,CAAC;IACD,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QAClC,OAAO,KAAK,CAAA;IACb,CAAC;IACD,sEAAsE;IACtE,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC;QAC3D,OAAO,KAAK,CAAA;IACb,CAAC;IACD,OAAO,SAAS,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ConnectRequest, WalletKit, WalletKitTheme } from '@reclack/walletkit';
|
|
2
|
+
/**
|
|
3
|
+
* The attributes `<reclack-connect>` understands.
|
|
4
|
+
*
|
|
5
|
+
* Exported so a typed host does not have to guess them, and so the JSX
|
|
6
|
+
* declarations for each framework are written against one list rather than
|
|
7
|
+
* three that drift.
|
|
8
|
+
*
|
|
9
|
+
* Everything here is a string, because attributes are. The richer settings,
|
|
10
|
+
* an intent carrying assets or a theme carrying per-mode overrides, are
|
|
11
|
+
* properties on the element instead: an attribute cannot hold either.
|
|
12
|
+
*/
|
|
13
|
+
export interface ReclackConnectAttributes {
|
|
14
|
+
/** `inline` for a list on the page, `modal` for the whole picker over it. */
|
|
15
|
+
variant?: 'inline' | 'modal';
|
|
16
|
+
/** Restricts the list to one chain family. Both when absent. */
|
|
17
|
+
family?: 'evm' | 'svm';
|
|
18
|
+
/** The EVM chain the wallet must end up on. No switch is forced without it. */
|
|
19
|
+
'chain-id'?: string | number;
|
|
20
|
+
/** Comma separated: `address`, `balance`. */
|
|
21
|
+
intent?: string;
|
|
22
|
+
/** Hold the connection open after the result, for a page that signs later. */
|
|
23
|
+
'keep-alive'?: boolean | '';
|
|
24
|
+
'theme-mode'?: 'light' | 'dark' | 'system';
|
|
25
|
+
/** `#rrggbb`. Anything else is ignored and the default stands. */
|
|
26
|
+
brand?: string;
|
|
27
|
+
radius?: string;
|
|
28
|
+
font?: string;
|
|
29
|
+
/** Where the host serves this package's `assets/` directory from. */
|
|
30
|
+
'asset-base'?: string;
|
|
31
|
+
/** A different Reclack to read the wallet catalogue from, such as a sandbox. */
|
|
32
|
+
'api-url'?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Everything a framework can pass in JSX: the attributes above, plus the
|
|
36
|
+
* properties that carry more than a string.
|
|
37
|
+
*
|
|
38
|
+
* A framework sets a property when the element has one of that name and an
|
|
39
|
+
* attribute otherwise, which is why these can sit in one list.
|
|
40
|
+
*/
|
|
41
|
+
export interface ReclackConnectProps extends ReclackConnectAttributes {
|
|
42
|
+
/** A kit to share rather than one this element would make for itself. */
|
|
43
|
+
kit?: WalletKit;
|
|
44
|
+
/** The full request, for an intent carrying assets. */
|
|
45
|
+
request?: ConnectRequest;
|
|
46
|
+
/** The full theme, for per-mode overrides. */
|
|
47
|
+
theme?: WalletKitTheme;
|
|
48
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { type ColorScheme, type ConnectRequest, type ConnectResult, type WalletKit, type WalletKitOptions, type WalletKitTheme } from '@reclack/walletkit';
|
|
2
|
+
/**
|
|
3
|
+
* `<reclack-connect>`: the wallet picker as an element.
|
|
4
|
+
*
|
|
5
|
+
* A custom element rather than a component, because the pages that need it
|
|
6
|
+
* are not all React. A merchant's dashboard, a partner's checkout and a plain
|
|
7
|
+
* HTML page all create elements; only one of them has a framework in common
|
|
8
|
+
* with us. Everything here is the platform: an element, attributes, events
|
|
9
|
+
* and a shadow root.
|
|
10
|
+
*
|
|
11
|
+
* The renderer inside is Preact, bundled. That is an implementation detail no
|
|
12
|
+
* host installs, imports or can collide with.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ReclackConnectElement extends HTMLElement {
|
|
15
|
+
#private;
|
|
16
|
+
static readonly tagName = "reclack-connect";
|
|
17
|
+
static get observedAttributes(): string[];
|
|
18
|
+
/**
|
|
19
|
+
* The kit this element drives.
|
|
20
|
+
*
|
|
21
|
+
* Made on first use rather than in the constructor, so the attributes
|
|
22
|
+
* that configure it have been parsed by the time it is built: an element
|
|
23
|
+
* written in HTML has its attributes set after construction, and a kit
|
|
24
|
+
* made too early would have read none of them.
|
|
25
|
+
*
|
|
26
|
+
* A host with several pickers on a page, or one that already holds a
|
|
27
|
+
* connection, passes its own through `useKit`: discovery is a window
|
|
28
|
+
* listener and a catalogue fetch, and a second kit runs both again to
|
|
29
|
+
* answer the same question.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Hands this element a kit to share, as a property.
|
|
33
|
+
*
|
|
34
|
+
* A property rather than only `useKit`, because that is what a framework
|
|
35
|
+
* can set: React and Preact both create the element, set properties, and
|
|
36
|
+
* only then insert it, so a kit assigned this way is in place before the
|
|
37
|
+
* element mounts and no throwaway kit is ever built.
|
|
38
|
+
*/
|
|
39
|
+
set kit(kit: WalletKit);
|
|
40
|
+
get kit(): WalletKit;
|
|
41
|
+
/**
|
|
42
|
+
* What the caller wants out of connecting.
|
|
43
|
+
*
|
|
44
|
+
* A property rather than only attributes, because an intent carries a
|
|
45
|
+
* list and an asset, and an attribute carries a string. Attributes cover
|
|
46
|
+
* the simple case; this covers the rest.
|
|
47
|
+
*/
|
|
48
|
+
set request(request: ConnectRequest);
|
|
49
|
+
get request(): ConnectRequest;
|
|
50
|
+
/**
|
|
51
|
+
* Colours, corner radius, type and light or dark.
|
|
52
|
+
*
|
|
53
|
+
* An accessor rather than a field, and that is load-bearing. A framework
|
|
54
|
+
* can only assign a property once it holds the element, which is after it
|
|
55
|
+
* has been inserted and `connectedCallback` has run. A plain field would
|
|
56
|
+
* be set too late for anything to notice, and the picker would keep
|
|
57
|
+
* whatever the attributes said: absent a `theme-mode`, that is `system`,
|
|
58
|
+
* so a theme pinned to light rendered dark on anyone's dark machine.
|
|
59
|
+
*/
|
|
60
|
+
set theme(theme: WalletKitTheme | undefined);
|
|
61
|
+
get theme(): WalletKitTheme | undefined;
|
|
62
|
+
/** What this element's mode resolved to, for a host that wants to match it. */
|
|
63
|
+
get scheme(): ColorScheme;
|
|
64
|
+
constructor();
|
|
65
|
+
connectedCallback(): void;
|
|
66
|
+
disconnectedCallback(): void;
|
|
67
|
+
attributeChangedCallback(): void;
|
|
68
|
+
/** Hands this element a kit to share instead of the one it would make. */
|
|
69
|
+
useKit(kit: WalletKit): void;
|
|
70
|
+
}
|
|
71
|
+
/** Registers the element, once, under its own name. */
|
|
72
|
+
export declare function defineWalletElement(tagName?: string): void;
|
|
73
|
+
export interface ConnectWalletOptions extends ConnectRequest {
|
|
74
|
+
/** A kit to share rather than one made for this prompt. */
|
|
75
|
+
kit?: WalletKit;
|
|
76
|
+
/** Options for the kit this prompt makes, when it is making one. */
|
|
77
|
+
kitOptions?: WalletKitOptions;
|
|
78
|
+
theme?: WalletKitTheme;
|
|
79
|
+
/** Where to mount. A detached element on `document.body` by default. */
|
|
80
|
+
container?: HTMLElement;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Opens the picker and resolves with what the caller asked for.
|
|
84
|
+
*
|
|
85
|
+
* The whole point of the element for a host that only wants a value: filling
|
|
86
|
+
* a settlement address should be one call, not an element, two listeners and
|
|
87
|
+
* a piece of state.
|
|
88
|
+
*
|
|
89
|
+
* Rejects when the person closes it. That is a refusal, not a failure, and a
|
|
90
|
+
* caller that wants to ignore it can.
|
|
91
|
+
*/
|
|
92
|
+
export declare function connectWallet(options?: ConnectWalletOptions): Promise<ConnectResult>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { ReclackConnectAttributes, ReclackConnectProps, } from './attributes.js';
|
|
2
|
+
export { ATTRIBUTES, attributesOf, EVENTS } from './props.js';
|
|
3
|
+
export type { ConnectProps } from './props.js';
|
|
4
|
+
export { connectWallet, defineWalletElement, ReclackConnectElement, type ConnectWalletOptions, } from './element.js';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ConnectRequest, ConnectResult, WalletKit, WalletKitTheme } from '@reclack/walletkit';
|
|
2
|
+
/**
|
|
3
|
+
* What a framework component takes, as that framework's users expect it.
|
|
4
|
+
*
|
|
5
|
+
* The element underneath is `<reclack-connect>`, because a custom element's
|
|
6
|
+
* tag must be lowercase and contain a hyphen; that is the HTML spec, not a
|
|
7
|
+
* style choice. Nobody writing React or Preact should have to know it, so
|
|
8
|
+
* these wrappers exist: camelCase props, callbacks instead of
|
|
9
|
+
* `addEventListener`, and a component name that reads like every other
|
|
10
|
+
* component on the page.
|
|
11
|
+
*/
|
|
12
|
+
export interface ConnectProps {
|
|
13
|
+
/** A kit to share rather than one the element would make for itself. */
|
|
14
|
+
kit?: WalletKit;
|
|
15
|
+
/** The whole request, for an intent carrying assets. */
|
|
16
|
+
request?: ConnectRequest;
|
|
17
|
+
/** The whole theme, for per-mode overrides. */
|
|
18
|
+
theme?: WalletKitTheme;
|
|
19
|
+
/** `inline` for a list on the page, `modal` for the picker over it. */
|
|
20
|
+
variant?: 'inline' | 'modal';
|
|
21
|
+
/** Restricts the list to one chain family. Both when absent. */
|
|
22
|
+
family?: 'evm' | 'svm';
|
|
23
|
+
/** The EVM chain the wallet must end up on. No switch is forced without it. */
|
|
24
|
+
chainId?: number;
|
|
25
|
+
/** Shorthand for `request.intent`. */
|
|
26
|
+
intent?: Array<'address' | 'balance'>;
|
|
27
|
+
/** Hold the connection open afterwards, for a page that signs later. */
|
|
28
|
+
keepAlive?: boolean;
|
|
29
|
+
themeMode?: 'light' | 'dark' | 'system';
|
|
30
|
+
/** `#rrggbb`. Anything else is ignored and the default stands. */
|
|
31
|
+
brand?: string;
|
|
32
|
+
radius?: string;
|
|
33
|
+
fontFamily?: string;
|
|
34
|
+
/** Where the host serves this package's `assets/` directory from. */
|
|
35
|
+
assetBase?: string;
|
|
36
|
+
/** A different Reclack to read the wallet catalogue from, such as a sandbox. */
|
|
37
|
+
apiUrl?: string;
|
|
38
|
+
onConnect?: (result: ConnectResult) => void;
|
|
39
|
+
onCancel?: () => void;
|
|
40
|
+
onError?: (message: string) => void;
|
|
41
|
+
}
|
|
42
|
+
/** The props that are plain attributes, and what each is called in the DOM. */
|
|
43
|
+
export declare const ATTRIBUTES: {
|
|
44
|
+
readonly variant: "variant";
|
|
45
|
+
readonly family: "family";
|
|
46
|
+
readonly chainId: "chain-id";
|
|
47
|
+
readonly themeMode: "theme-mode";
|
|
48
|
+
readonly brand: "brand";
|
|
49
|
+
readonly radius: "radius";
|
|
50
|
+
readonly fontFamily: "font";
|
|
51
|
+
readonly assetBase: "asset-base";
|
|
52
|
+
readonly apiUrl: "api-url";
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Props to attributes, for whichever framework is rendering.
|
|
56
|
+
*
|
|
57
|
+
* Shared so the two wrappers cannot drift. Values are strings because
|
|
58
|
+
* attributes are; `undefined` is left out so the element falls back to its
|
|
59
|
+
* own default rather than parsing the word "undefined".
|
|
60
|
+
*/
|
|
61
|
+
export declare function attributesOf(props: ConnectProps): Record<string, string>;
|
|
62
|
+
/** The events the element dispatches, and the callback each one answers. */
|
|
63
|
+
export declare const EVENTS: {
|
|
64
|
+
readonly connect: "onConnect";
|
|
65
|
+
readonly cancel: "onCancel";
|
|
66
|
+
readonly 'connect-error': "onError";
|
|
67
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ConnectRequest, type ConnectResult, type WalletKit } from '@reclack/walletkit';
|
|
2
|
+
/**
|
|
3
|
+
* Where the picker sits.
|
|
4
|
+
*
|
|
5
|
+
* `inline` is the short list a checkout puts on the page, with the full
|
|
6
|
+
* catalogue folded behind one row. `modal` is the whole picker over the page,
|
|
7
|
+
* which is what a button marked "Connect wallet" opens.
|
|
8
|
+
*
|
|
9
|
+
* A modal here rather than a host wrapping the inline list in one: the dialog
|
|
10
|
+
* is a native `<dialog>`, so focus trapping, Esc, an inert background and a
|
|
11
|
+
* backdrop come from the platform rather than from a focus-trap library
|
|
12
|
+
* shipped on a page that takes payments.
|
|
13
|
+
*/
|
|
14
|
+
export type Variant = 'inline' | 'modal';
|
|
15
|
+
export declare function ConnectApp({ kit, request, variant, onResult, onError, onClose, }: {
|
|
16
|
+
kit: WalletKit;
|
|
17
|
+
request: ConnectRequest;
|
|
18
|
+
variant: Variant;
|
|
19
|
+
onResult: (result: ConnectResult) => void;
|
|
20
|
+
onError: (message: string) => void;
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
}): import("preact").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ComponentChildren } from 'preact';
|
|
2
|
+
export declare function AssetProvider({ base, children, }: {
|
|
3
|
+
base: string;
|
|
4
|
+
children: ComponentChildren;
|
|
5
|
+
}): import("preact").JSX.Element;
|
|
6
|
+
/** The artwork for a wallet, or nothing where this package carries none. */
|
|
7
|
+
export declare function useWalletLogo(): (id: string) => string | undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QR rendering for the wallet hand-off.
|
|
3
|
+
*
|
|
4
|
+
* The encoder is a dependency on purpose. QR generation is not something to
|
|
5
|
+
* hand-roll. Reed-Solomon over GF(256), mask selection and format bits are
|
|
6
|
+
* easy to get subtly wrong, and a code that looks right but does not scan is
|
|
7
|
+
* worse than none on a payment page.
|
|
8
|
+
*
|
|
9
|
+
* It is also NOT rendered through a remote service: the checkout URL is the
|
|
10
|
+
* credential for this payment, and handing it to an image API would leak every
|
|
11
|
+
* link a payer opens to a third party. uqr runs entirely in the page.
|
|
12
|
+
*
|
|
13
|
+
* Callers still handle `undefined`, so a failure to encode degrades to the
|
|
14
|
+
* copyable link rather than an empty frame.
|
|
15
|
+
*/
|
|
16
|
+
export declare function qrSvg(text: string): string | undefined;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether this is a touch-primary device: a phone or a tablet.
|
|
3
|
+
*
|
|
4
|
+
* Matters because the wallet hand-off is the opposite on each. A desktop
|
|
5
|
+
* payer scans a code to carry the page to their phone; a phone payer cannot
|
|
6
|
+
* scan their own screen and needs a link into the wallet instead.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useHandheld(): boolean;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { WalletChoice } from '@reclack/walletkit';
|
|
2
|
+
/**
|
|
3
|
+
* The hand-off screen for one wallet.
|
|
4
|
+
*
|
|
5
|
+
* The way forward depends on the device. On a desktop the wallet is either in
|
|
6
|
+
* this browser or in the payer's pocket, so the panel offers a code to carry
|
|
7
|
+
* the checkout across. On a phone there is nothing to scan: the wallet is on
|
|
8
|
+
* this device, and the way in is a link that opens it.
|
|
9
|
+
*/
|
|
10
|
+
export declare function WalletConnectPanel<T extends WalletChoice>({ id, name, icon, detected, installUrl, connecting, error, onRemote, onConnect, }: {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
icon?: string;
|
|
14
|
+
detected?: T;
|
|
15
|
+
installUrl?: string;
|
|
16
|
+
connecting: boolean;
|
|
17
|
+
/** What the wallet said when it refused, empty when it has not. */
|
|
18
|
+
error?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Pairs with a wallet that puts nothing in the page, over WalletConnect.
|
|
21
|
+
* Absent when this wallet can be found some other way, or when the
|
|
22
|
+
* checkout has no project id to pair with.
|
|
23
|
+
*/
|
|
24
|
+
onRemote?: (onUri: (uri: string) => void) => void;
|
|
25
|
+
onConnect: (wallet: T) => void;
|
|
26
|
+
}): import("preact").JSX.Element;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { WalletChoice, WalletOption } from '@reclack/walletkit';
|
|
2
|
+
/**
|
|
3
|
+
* The full wallet picker.
|
|
4
|
+
*
|
|
5
|
+
* Built on the native <dialog>: showModal() gives focus trapping, Esc to close,
|
|
6
|
+
* an inert background and a backdrop for free. A checkout should not ship a
|
|
7
|
+
* focus-trap library to reimplement what the platform already does correctly.
|
|
8
|
+
*/
|
|
9
|
+
export declare function WalletDialog<T extends WalletChoice>({ open, wallets, registry, connecting, connected, error, initialWalletId, remotePairing, onSelect, onClose, }: {
|
|
10
|
+
open: boolean;
|
|
11
|
+
wallets: T[];
|
|
12
|
+
/**
|
|
13
|
+
* The wallets that exist, installed or not, so one that is missing can
|
|
14
|
+
* still be found and installed. Empty when the catalogue has not loaded,
|
|
15
|
+
* which leaves the detected wallets listed and nothing to install.
|
|
16
|
+
*/
|
|
17
|
+
registry?: WalletOption[];
|
|
18
|
+
connecting: boolean;
|
|
19
|
+
/** True once a wallet is connected, which is what closes the dialog. */
|
|
20
|
+
connected?: boolean;
|
|
21
|
+
/** What the wallet said when it refused, empty when it has not. */
|
|
22
|
+
error?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Open straight into this wallet's hand-off rather than the list, for a
|
|
25
|
+
* payer who already named the wallet they want outside the dialog.
|
|
26
|
+
*/
|
|
27
|
+
initialWalletId?: string;
|
|
28
|
+
/**
|
|
29
|
+
* How to pair with one wallet over WalletConnect, or undefined for a
|
|
30
|
+
* wallet the page can see for itself. Asked per wallet rather than given
|
|
31
|
+
* as a list, because only the checkout knows which chain family is on
|
|
32
|
+
* screen and which chain a pairing is for.
|
|
33
|
+
*/
|
|
34
|
+
remotePairing?: (walletId: string) => ((onUri: (uri: string) => void) => void) | undefined;
|
|
35
|
+
onSelect: (wallet: T) => void;
|
|
36
|
+
onClose: () => void;
|
|
37
|
+
}): import("preact").JSX.Element;
|