@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.
Files changed (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +341 -2
  3. package/assets/backpack.webp +0 -0
  4. package/assets/berasig.webp +0 -0
  5. package/assets/bestwallet.webp +0 -0
  6. package/assets/bifrostwallet.webp +0 -0
  7. package/assets/binance.webp +0 -0
  8. package/assets/bitcoincom.webp +0 -0
  9. package/assets/bitget.webp +0 -0
  10. package/assets/bitpay.webp +0 -0
  11. package/assets/bitski.webp +0 -0
  12. package/assets/bitverse.webp +0 -0
  13. package/assets/blockchaincom.webp +0 -0
  14. package/assets/brave.webp +0 -0
  15. package/assets/bybit.webp +0 -0
  16. package/assets/clv.webp +0 -0
  17. package/assets/coin98.webp +0 -0
  18. package/assets/coinbase.webp +0 -0
  19. package/assets/compass.webp +0 -0
  20. package/assets/core.webp +0 -0
  21. package/assets/crypto_com.webp +0 -0
  22. package/assets/ctrl.webp +0 -0
  23. package/assets/dawn.webp +0 -0
  24. package/assets/desig.webp +0 -0
  25. package/assets/enkrypt.webp +0 -0
  26. package/assets/exodus.webp +0 -0
  27. package/assets/foxwallet.webp +0 -0
  28. package/assets/frame.webp +0 -0
  29. package/assets/frontier.webp +0 -0
  30. package/assets/gate.webp +0 -0
  31. package/assets/gemini.webp +0 -0
  32. package/assets/imtoken.webp +0 -0
  33. package/assets/iopay.webp +0 -0
  34. package/assets/kaia.webp +0 -0
  35. package/assets/kaikas.webp +0 -0
  36. package/assets/kraken.webp +0 -0
  37. package/assets/kresuswallet.webp +0 -0
  38. package/assets/ledger.webp +0 -0
  39. package/assets/magiceden.webp +0 -0
  40. package/assets/meco.webp +0 -0
  41. package/assets/metamask.webp +0 -0
  42. package/assets/mew.webp +0 -0
  43. package/assets/nest.webp +0 -0
  44. package/assets/nova.webp +0 -0
  45. package/assets/okto.webp +0 -0
  46. package/assets/okx.webp +0 -0
  47. package/assets/oneinch.webp +0 -0
  48. package/assets/onekey.webp +0 -0
  49. package/assets/phantom.webp +0 -0
  50. package/assets/rabby.webp +0 -0
  51. package/assets/rainbow.webp +0 -0
  52. package/assets/ramper.webp +0 -0
  53. package/assets/ready.webp +0 -0
  54. package/assets/ronin.webp +0 -0
  55. package/assets/safe.webp +0 -0
  56. package/assets/safepal.webp +0 -0
  57. package/assets/solflare.webp +0 -0
  58. package/assets/subwallet.webp +0 -0
  59. package/assets/taho.webp +0 -0
  60. package/assets/talisman.webp +0 -0
  61. package/assets/tokenary.webp +0 -0
  62. package/assets/tokenpocket.webp +0 -0
  63. package/assets/trust-wallet.webp +0 -0
  64. package/assets/uniswap.webp +0 -0
  65. package/assets/universalprofiles.webp +0 -0
  66. package/assets/valora.webp +0 -0
  67. package/assets/wigwam.webp +0 -0
  68. package/assets/xportal.webp +0 -0
  69. package/assets/zeal.webp +0 -0
  70. package/assets/zerion.webp +0 -0
  71. package/custom-elements.json +207 -0
  72. package/dist/abi.d.ts +21 -0
  73. package/dist/abi.d.ts.map +1 -0
  74. package/dist/abi.js +50 -0
  75. package/dist/abi.js.map +1 -0
  76. package/dist/address.d.ts +15 -0
  77. package/dist/address.d.ts.map +1 -0
  78. package/dist/address.js +25 -0
  79. package/dist/address.js.map +1 -0
  80. package/dist/balance.d.ts +78 -0
  81. package/dist/balance.d.ts.map +1 -0
  82. package/dist/balance.js +146 -0
  83. package/dist/balance.js.map +1 -0
  84. package/dist/base58.d.ts +15 -0
  85. package/dist/base58.d.ts.map +1 -0
  86. package/dist/base58.js +52 -0
  87. package/dist/base58.js.map +1 -0
  88. package/dist/catalog-fetch.d.ts +18 -0
  89. package/dist/catalog-fetch.d.ts.map +1 -0
  90. package/dist/catalog-fetch.js +85 -0
  91. package/dist/catalog-fetch.js.map +1 -0
  92. package/dist/catalog.d.ts +57 -0
  93. package/dist/catalog.d.ts.map +1 -0
  94. package/dist/catalog.js +80 -0
  95. package/dist/catalog.js.map +1 -0
  96. package/dist/chains.d.ts +32 -0
  97. package/dist/chains.d.ts.map +1 -0
  98. package/dist/chains.js +103 -0
  99. package/dist/chains.js.map +1 -0
  100. package/dist/config.d.ts +40 -0
  101. package/dist/config.d.ts.map +1 -0
  102. package/dist/config.js +44 -0
  103. package/dist/config.js.map +1 -0
  104. package/dist/deep-links.d.ts +22 -0
  105. package/dist/deep-links.d.ts.map +1 -0
  106. package/dist/deep-links.js +201 -0
  107. package/dist/deep-links.js.map +1 -0
  108. package/dist/device.d.ts +23 -0
  109. package/dist/device.d.ts.map +1 -0
  110. package/dist/device.js +59 -0
  111. package/dist/device.js.map +1 -0
  112. package/dist/element/attributes.d.ts +48 -0
  113. package/dist/element/element.d.ts +92 -0
  114. package/dist/element/index.d.ts +4 -0
  115. package/dist/element/props.d.ts +67 -0
  116. package/dist/element/ui/app.d.ts +22 -0
  117. package/dist/element/ui/assets.d.ts +7 -0
  118. package/dist/element/ui/qr.d.ts +16 -0
  119. package/dist/element/ui/use-handheld.d.ts +8 -0
  120. package/dist/element/ui/wallet-connect-panel.d.ts +26 -0
  121. package/dist/element/ui/wallet-dialog.d.ts +37 -0
  122. package/dist/element/ui/wallet-list.d.ts +26 -0
  123. package/dist/element/ui/wallet-mark.d.ts +15 -0
  124. package/dist/element.js +2079 -0
  125. package/dist/errors.d.ts +34 -0
  126. package/dist/errors.d.ts.map +1 -0
  127. package/dist/errors.js +64 -0
  128. package/dist/errors.js.map +1 -0
  129. package/dist/evm.d.ts +49 -0
  130. package/dist/evm.d.ts.map +1 -0
  131. package/dist/evm.js +217 -0
  132. package/dist/evm.js.map +1 -0
  133. package/dist/icons.d.ts +22 -0
  134. package/dist/icons.d.ts.map +1 -0
  135. package/dist/icons.js +98 -0
  136. package/dist/icons.js.map +1 -0
  137. package/dist/index.d.ts +39 -0
  138. package/dist/index.d.ts.map +1 -0
  139. package/dist/index.js +43 -0
  140. package/dist/index.js.map +1 -0
  141. package/dist/intent.d.ts +60 -0
  142. package/dist/intent.d.ts.map +1 -0
  143. package/dist/intent.js +2 -0
  144. package/dist/intent.js.map +1 -0
  145. package/dist/kit.d.ts +124 -0
  146. package/dist/kit.d.ts.map +1 -0
  147. package/dist/kit.js +362 -0
  148. package/dist/kit.js.map +1 -0
  149. package/dist/svm.d.ts +45 -0
  150. package/dist/svm.d.ts.map +1 -0
  151. package/dist/svm.js +201 -0
  152. package/dist/svm.js.map +1 -0
  153. package/dist/theme.d.ts +101 -0
  154. package/dist/theme.d.ts.map +1 -0
  155. package/dist/theme.js +217 -0
  156. package/dist/theme.js.map +1 -0
  157. package/dist/types.d.ts +144 -0
  158. package/dist/types.d.ts.map +1 -0
  159. package/dist/types.js +2 -0
  160. package/dist/types.js.map +1 -0
  161. package/dist/wallet-standard.d.ts +77 -0
  162. package/dist/wallet-standard.d.ts.map +1 -0
  163. package/dist/wallet-standard.js +89 -0
  164. package/dist/wallet-standard.js.map +1 -0
  165. package/dist/walletconnect.d.ts +74 -0
  166. package/dist/walletconnect.d.ts.map +1 -0
  167. package/dist/walletconnect.js +133 -0
  168. package/dist/walletconnect.js.map +1 -0
  169. package/package.json +71 -3
  170. 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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"}
@@ -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;