@fernolab/wallet-adapter-svelte 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/dist/components/WalletButton.svelte +152 -0
- package/dist/components/WalletButton.svelte.d.ts +6 -0
- package/dist/components/WalletListButton.svelte +48 -0
- package/dist/components/WalletListButton.svelte.d.ts +8 -0
- package/dist/components/WalletModal.svelte +360 -0
- package/dist/components/WalletModal.svelte.d.ts +7 -0
- package/dist/components/WalletProvider.svelte +25 -0
- package/dist/components/WalletProvider.svelte.d.ts +8 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +3 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +2 -0
- package/dist/environment.d.ts +1 -0
- package/dist/environment.js +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -0
- package/dist/wallet/mobile-detection.d.ts +3 -0
- package/dist/wallet/mobile-detection.js +27 -0
- package/dist/wallet/types.d.ts +3 -0
- package/dist/wallet/types.js +1 -0
- package/dist/wallet/wallet.svelte.d.ts +56 -0
- package/dist/wallet/wallet.svelte.js +672 -0
- package/package.json +71 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import WalletModal from './WalletModal.svelte';
|
|
3
|
+
import { wallet } from '../wallet/wallet.svelte.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let { class: className = '' }: Props = $props();
|
|
10
|
+
|
|
11
|
+
let showModal = $state(false);
|
|
12
|
+
let menuOpen = $state(false);
|
|
13
|
+
let container: HTMLDivElement | null = null;
|
|
14
|
+
|
|
15
|
+
function togglePrimary(): void {
|
|
16
|
+
if (wallet.connected) {
|
|
17
|
+
menuOpen = !menuOpen;
|
|
18
|
+
} else {
|
|
19
|
+
showModal = true;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function handleDisconnect(): Promise<void> {
|
|
24
|
+
await wallet.disconnect();
|
|
25
|
+
menuOpen = false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function handleSwitch(): void {
|
|
29
|
+
menuOpen = false;
|
|
30
|
+
showModal = true;
|
|
31
|
+
}
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<div class={`wallet-control ${className}`} bind:this={container}>
|
|
35
|
+
<button
|
|
36
|
+
class={`wallet-button ${wallet.connected ? 'connected' : ''}`}
|
|
37
|
+
onclick={togglePrimary}
|
|
38
|
+
type="button"
|
|
39
|
+
aria-expanded={wallet.connected ? menuOpen : undefined}
|
|
40
|
+
aria-haspopup={wallet.connected ? 'menu' : undefined}
|
|
41
|
+
disabled={wallet.connecting}
|
|
42
|
+
>
|
|
43
|
+
{#if wallet.connected && wallet.standardWallet?.icon}
|
|
44
|
+
<img
|
|
45
|
+
alt={`${wallet.standardWallet.name} icon`}
|
|
46
|
+
class="wallet-icon"
|
|
47
|
+
src={wallet.standardWallet.icon}
|
|
48
|
+
/>
|
|
49
|
+
{/if}
|
|
50
|
+
<span class="label">
|
|
51
|
+
{wallet.connected ? wallet.shortAddress || 'Connected' : 'Connect wallet'}
|
|
52
|
+
</span>
|
|
53
|
+
{#if wallet.connected}
|
|
54
|
+
<span class="chevron">▾</span>
|
|
55
|
+
{/if}
|
|
56
|
+
</button>
|
|
57
|
+
|
|
58
|
+
{#if wallet.connected && menuOpen}
|
|
59
|
+
<div class="wallet-menu" role="menu">
|
|
60
|
+
<button type="button" role="menuitem" onclick={handleSwitch}>Switch wallet</button>
|
|
61
|
+
<button type="button" role="menuitem" onclick={handleDisconnect}>Disconnect</button>
|
|
62
|
+
</div>
|
|
63
|
+
{/if}
|
|
64
|
+
|
|
65
|
+
<WalletModal bind:show={showModal} onModalClosed={() => (menuOpen = false)} />
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<style>
|
|
69
|
+
.wallet-control {
|
|
70
|
+
position: relative;
|
|
71
|
+
display: inline-flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.wallet-button {
|
|
76
|
+
display: inline-flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: 8px;
|
|
79
|
+
min-height: 38px;
|
|
80
|
+
padding: 8px 12px;
|
|
81
|
+
border-radius: 6px;
|
|
82
|
+
border: 1px solid #111111;
|
|
83
|
+
background: #ffffff;
|
|
84
|
+
color: #111111;
|
|
85
|
+
font: inherit;
|
|
86
|
+
font-weight: 700;
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
transition: background 0.15s ease, color 0.15s ease;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.wallet-button.connected {
|
|
92
|
+
background: #111111;
|
|
93
|
+
color: #ffffff;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.wallet-button:disabled {
|
|
97
|
+
opacity: 0.6;
|
|
98
|
+
cursor: not-allowed;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.wallet-button:hover:not(:disabled) {
|
|
102
|
+
background: #111111;
|
|
103
|
+
color: #ffffff;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.wallet-icon {
|
|
107
|
+
width: 22px;
|
|
108
|
+
height: 22px;
|
|
109
|
+
border-radius: 5px;
|
|
110
|
+
object-fit: cover;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.label {
|
|
114
|
+
white-space: nowrap;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.chevron {
|
|
118
|
+
font-size: 0.8rem;
|
|
119
|
+
opacity: 0.8;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.wallet-menu {
|
|
123
|
+
position: absolute;
|
|
124
|
+
top: calc(100% + 6px);
|
|
125
|
+
right: 0;
|
|
126
|
+
display: grid;
|
|
127
|
+
padding: 6px;
|
|
128
|
+
background: #ffffff;
|
|
129
|
+
border: 1px solid #d8d8d8;
|
|
130
|
+
border-radius: 8px;
|
|
131
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
132
|
+
min-width: 150px;
|
|
133
|
+
z-index: 20;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.wallet-menu button {
|
|
137
|
+
background: none;
|
|
138
|
+
border: none;
|
|
139
|
+
text-align: left;
|
|
140
|
+
padding: 8px 10px;
|
|
141
|
+
border-radius: 6px;
|
|
142
|
+
font-weight: 600;
|
|
143
|
+
font-size: 14px;
|
|
144
|
+
color: #111111;
|
|
145
|
+
cursor: pointer;
|
|
146
|
+
transition: background 0.15s ease;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.wallet-menu button:hover {
|
|
150
|
+
background: #f7f7f7;
|
|
151
|
+
}
|
|
152
|
+
</style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
icon: string;
|
|
4
|
+
name: string;
|
|
5
|
+
onclick?: () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let { icon, name, onclick }: Props = $props();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<button class="wallet-list-button" type="button" onclick={onclick}>
|
|
12
|
+
<img src={icon} alt={`${name} icon`} />
|
|
13
|
+
<span>{name}</span>
|
|
14
|
+
</button>
|
|
15
|
+
|
|
16
|
+
<style>
|
|
17
|
+
.wallet-list-button {
|
|
18
|
+
width: 100%;
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
gap: 12px;
|
|
22
|
+
padding: 11px 12px;
|
|
23
|
+
border-radius: 8px;
|
|
24
|
+
border: 1px solid #d8d8d8;
|
|
25
|
+
background: #ffffff;
|
|
26
|
+
color: #111111;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
font: inherit;
|
|
29
|
+
transition: border-color 0.15s ease, background 0.15s ease;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.wallet-list-button:hover {
|
|
33
|
+
background: #f7f7f7;
|
|
34
|
+
border-color: #b8b8b8;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.wallet-list-button img {
|
|
38
|
+
width: 34px;
|
|
39
|
+
height: 34px;
|
|
40
|
+
border-radius: 7px;
|
|
41
|
+
object-fit: cover;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.wallet-list-button span {
|
|
45
|
+
font-weight: 700;
|
|
46
|
+
color: #111111;
|
|
47
|
+
}
|
|
48
|
+
</style>
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { wallet } from "../wallet/wallet.svelte.js";
|
|
3
|
+
import type { StandardWallet } from "../wallet/types.js";
|
|
4
|
+
import WalletListButton from "./WalletListButton.svelte";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
show?: boolean;
|
|
8
|
+
onModalClosed?: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { show = $bindable(false), onModalClosed }: Props = $props();
|
|
12
|
+
|
|
13
|
+
let connectError = $state<string | null>(null);
|
|
14
|
+
|
|
15
|
+
const standardWallets = $derived(
|
|
16
|
+
wallet.availableWallets.filter(
|
|
17
|
+
(standardWallet) => standardWallet.name !== wallet.mobileWalletAdapterName
|
|
18
|
+
)
|
|
19
|
+
);
|
|
20
|
+
const showMobileActions = $derived(
|
|
21
|
+
Boolean(wallet.mobileWalletAdapterWallet || wallet.detectedWalletBrowserName)
|
|
22
|
+
);
|
|
23
|
+
const hasWallets = $derived(standardWallets.length > 0);
|
|
24
|
+
|
|
25
|
+
function getWalletDisplayName(name: string): string {
|
|
26
|
+
return name === wallet.mobileWalletAdapterName ? wallet.mobileWalletAdapterDisplayName : name;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function handleWalletSelect(
|
|
30
|
+
selectedWallet: StandardWallet
|
|
31
|
+
): Promise<void> {
|
|
32
|
+
connectError = null;
|
|
33
|
+
try {
|
|
34
|
+
await wallet.connectStandard(selectedWallet);
|
|
35
|
+
show = false;
|
|
36
|
+
onModalClosed && onModalClosed();
|
|
37
|
+
} catch (error) {
|
|
38
|
+
connectError =
|
|
39
|
+
error instanceof Error
|
|
40
|
+
? error.message
|
|
41
|
+
: "Failed to connect with the selected wallet.";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function handleMobileWalletAdapter(): Promise<void> {
|
|
46
|
+
connectError = null;
|
|
47
|
+
try {
|
|
48
|
+
await wallet.connectMobileWalletAdapter();
|
|
49
|
+
show = false;
|
|
50
|
+
onModalClosed && onModalClosed();
|
|
51
|
+
} catch (error) {
|
|
52
|
+
connectError =
|
|
53
|
+
error instanceof Error
|
|
54
|
+
? error.message
|
|
55
|
+
: "Mobile Wallet Adapter is not available.";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function handleWalletBrowser(): Promise<void> {
|
|
60
|
+
connectError = null;
|
|
61
|
+
try {
|
|
62
|
+
await wallet.connectWalletBrowser();
|
|
63
|
+
show = false;
|
|
64
|
+
onModalClosed && onModalClosed();
|
|
65
|
+
} catch (error) {
|
|
66
|
+
connectError =
|
|
67
|
+
error instanceof Error
|
|
68
|
+
? error.message
|
|
69
|
+
: "Wallet browser connection failed.";
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function handleRefresh(): Promise<void> {
|
|
74
|
+
connectError = null;
|
|
75
|
+
try {
|
|
76
|
+
await wallet.refreshAvailableWallets();
|
|
77
|
+
} catch (error) {
|
|
78
|
+
connectError =
|
|
79
|
+
error instanceof Error ? error.message : "Could not refresh wallets.";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function handleClose(): void {
|
|
84
|
+
show = false;
|
|
85
|
+
connectError = null;
|
|
86
|
+
onModalClosed && onModalClosed();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function handleOverlayKeydown(event: KeyboardEvent): void {
|
|
90
|
+
if (event.key === "Escape" || event.key === "Enter" || event.key === " ") {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
handleClose();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function handleOverlayClick(event: MouseEvent): void {
|
|
97
|
+
if (event.target === event.currentTarget) {
|
|
98
|
+
handleClose();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
{#if show}
|
|
104
|
+
<div
|
|
105
|
+
class="modal-overlay"
|
|
106
|
+
role="presentation"
|
|
107
|
+
onclick={handleOverlayClick}
|
|
108
|
+
onkeydown={handleOverlayKeydown}
|
|
109
|
+
tabindex="-1"
|
|
110
|
+
>
|
|
111
|
+
<div class="modal" role="dialog" aria-modal="true" tabindex="-1">
|
|
112
|
+
<div class="modal-header">
|
|
113
|
+
<div>
|
|
114
|
+
<h2>Connect wallet</h2>
|
|
115
|
+
<p>{wallet.runtimeLabel}</p>
|
|
116
|
+
</div>
|
|
117
|
+
<button
|
|
118
|
+
class="close-button"
|
|
119
|
+
type="button"
|
|
120
|
+
onclick={handleClose}
|
|
121
|
+
aria-label="Close">×</button
|
|
122
|
+
>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<div class="modal-content">
|
|
126
|
+
{#if showMobileActions}
|
|
127
|
+
<div class="mobile-actions">
|
|
128
|
+
{#if wallet.detectedWalletBrowserName}
|
|
129
|
+
<button
|
|
130
|
+
class="action-button primary"
|
|
131
|
+
type="button"
|
|
132
|
+
disabled={wallet.connecting}
|
|
133
|
+
onclick={handleWalletBrowser}
|
|
134
|
+
>
|
|
135
|
+
Connect {wallet.detectedWalletBrowserName}
|
|
136
|
+
</button>
|
|
137
|
+
{/if}
|
|
138
|
+
|
|
139
|
+
{#if wallet.mobileWalletAdapterWallet}
|
|
140
|
+
<button
|
|
141
|
+
class="action-button"
|
|
142
|
+
type="button"
|
|
143
|
+
disabled={wallet.connecting}
|
|
144
|
+
onclick={handleMobileWalletAdapter}
|
|
145
|
+
>
|
|
146
|
+
{wallet.mobileWalletAdapterDisplayName}
|
|
147
|
+
</button>
|
|
148
|
+
{/if}
|
|
149
|
+
</div>
|
|
150
|
+
{/if}
|
|
151
|
+
|
|
152
|
+
{#if wallet.mobileRuntime.isMobile && wallet.mobileWalletLinks.length > 0}
|
|
153
|
+
<div class="mobile-links" aria-label="Open in wallet browser">
|
|
154
|
+
{#each wallet.mobileWalletLinks as link}
|
|
155
|
+
<a href={link.url} rel="noreferrer">{link.name}</a>
|
|
156
|
+
{/each}
|
|
157
|
+
</div>
|
|
158
|
+
{/if}
|
|
159
|
+
|
|
160
|
+
<div class="wallet-list">
|
|
161
|
+
{#if standardWallets.length > 0}
|
|
162
|
+
<div class="section-title">Wallets</div>
|
|
163
|
+
{#each standardWallets as w (w.name)}
|
|
164
|
+
<WalletListButton
|
|
165
|
+
onclick={() => handleWalletSelect(w)}
|
|
166
|
+
icon={w.icon}
|
|
167
|
+
name={getWalletDisplayName(w.name)}
|
|
168
|
+
/>
|
|
169
|
+
{/each}
|
|
170
|
+
{/if}
|
|
171
|
+
|
|
172
|
+
{#if !hasWallets}
|
|
173
|
+
<div class="no-wallets">
|
|
174
|
+
<p>No wallets detected.</p>
|
|
175
|
+
</div>
|
|
176
|
+
{/if}
|
|
177
|
+
|
|
178
|
+
<button class="refresh-button" type="button" onclick={handleRefresh}>
|
|
179
|
+
Refresh wallets
|
|
180
|
+
</button>
|
|
181
|
+
|
|
182
|
+
{#if connectError}
|
|
183
|
+
<p class="error" role="alert">{connectError}</p>
|
|
184
|
+
{/if}
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
{/if}
|
|
190
|
+
|
|
191
|
+
<style>
|
|
192
|
+
.modal-overlay {
|
|
193
|
+
position: fixed;
|
|
194
|
+
inset: 0;
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: center;
|
|
197
|
+
justify-content: center;
|
|
198
|
+
padding: 20px;
|
|
199
|
+
background: rgba(0, 0, 0, 0.48);
|
|
200
|
+
z-index: 40;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.modal {
|
|
204
|
+
background: white;
|
|
205
|
+
border-radius: 10px;
|
|
206
|
+
border: 1px solid #d8d8d8;
|
|
207
|
+
width: min(430px, 100%);
|
|
208
|
+
max-height: 85vh;
|
|
209
|
+
display: flex;
|
|
210
|
+
flex-direction: column;
|
|
211
|
+
overflow: hidden;
|
|
212
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.modal-header {
|
|
216
|
+
display: flex;
|
|
217
|
+
align-items: center;
|
|
218
|
+
justify-content: space-between;
|
|
219
|
+
padding: 16px;
|
|
220
|
+
border-bottom: 1px solid #e5e5e5;
|
|
221
|
+
gap: 16px;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.close-button {
|
|
225
|
+
background: none;
|
|
226
|
+
border: 1px solid transparent;
|
|
227
|
+
font-size: 1.25rem;
|
|
228
|
+
cursor: pointer;
|
|
229
|
+
color: #111111;
|
|
230
|
+
border-radius: 8px;
|
|
231
|
+
width: 32px;
|
|
232
|
+
height: 32px;
|
|
233
|
+
line-height: 1;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.close-button:hover {
|
|
237
|
+
background: #f7f7f7;
|
|
238
|
+
border-color: #d8d8d8;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
h2 {
|
|
242
|
+
margin: 0;
|
|
243
|
+
font-size: 1.1rem;
|
|
244
|
+
font-weight: 700;
|
|
245
|
+
color: #111111;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.modal-header p {
|
|
249
|
+
margin: 3px 0 0;
|
|
250
|
+
color: #666666;
|
|
251
|
+
font-size: 0.86rem;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.modal-content {
|
|
255
|
+
padding: 16px;
|
|
256
|
+
overflow-y: auto;
|
|
257
|
+
flex: 1;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.mobile-actions {
|
|
261
|
+
display: grid;
|
|
262
|
+
gap: 8px;
|
|
263
|
+
margin-bottom: 12px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.action-button,
|
|
267
|
+
.refresh-button {
|
|
268
|
+
width: 100%;
|
|
269
|
+
border-radius: 8px;
|
|
270
|
+
border: 1px solid #d8d8d8;
|
|
271
|
+
background: #ffffff;
|
|
272
|
+
color: #111111;
|
|
273
|
+
cursor: pointer;
|
|
274
|
+
font-weight: 700;
|
|
275
|
+
padding: 11px 14px;
|
|
276
|
+
transition: background 0.15s ease, border-color 0.15s ease;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.action-button:hover:not(:disabled),
|
|
280
|
+
.refresh-button:hover {
|
|
281
|
+
background: #f7f7f7;
|
|
282
|
+
border-color: #b8b8b8;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.action-button.primary {
|
|
286
|
+
background: #111111;
|
|
287
|
+
border-color: #111111;
|
|
288
|
+
color: #ffffff;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.action-button.primary:hover:not(:disabled) {
|
|
292
|
+
background: #000000;
|
|
293
|
+
border-color: #000000;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.action-button:disabled {
|
|
297
|
+
cursor: not-allowed;
|
|
298
|
+
opacity: 0.5;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.mobile-links {
|
|
302
|
+
display: flex;
|
|
303
|
+
flex-wrap: wrap;
|
|
304
|
+
gap: 8px;
|
|
305
|
+
margin-bottom: 14px;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.mobile-links a {
|
|
309
|
+
border-radius: 8px;
|
|
310
|
+
border: 1px solid #d8d8d8;
|
|
311
|
+
color: #111111;
|
|
312
|
+
font-size: 0.86rem;
|
|
313
|
+
font-weight: 650;
|
|
314
|
+
padding: 7px 10px;
|
|
315
|
+
text-decoration: none;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.mobile-links a:hover {
|
|
319
|
+
background: #f7f7f7;
|
|
320
|
+
border-color: #b8b8b8;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.wallet-list {
|
|
324
|
+
display: grid;
|
|
325
|
+
gap: 8px;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.section-title {
|
|
329
|
+
color: #666666;
|
|
330
|
+
font-size: 0.88rem;
|
|
331
|
+
font-weight: 700;
|
|
332
|
+
margin-top: 4px;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.no-wallets {
|
|
336
|
+
padding: 14px;
|
|
337
|
+
background: #fafafa;
|
|
338
|
+
border-radius: 8px;
|
|
339
|
+
border: 1px solid #d8d8d8;
|
|
340
|
+
color: #666666;
|
|
341
|
+
font-size: 0.9rem;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.no-wallets p {
|
|
345
|
+
margin: 0;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.refresh-button {
|
|
349
|
+
margin-top: 4px;
|
|
350
|
+
padding: 9px 12px;
|
|
351
|
+
font-size: 0.9rem;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.error {
|
|
355
|
+
margin: 4px 0 0;
|
|
356
|
+
color: #111111;
|
|
357
|
+
font-weight: 600;
|
|
358
|
+
font-size: 0.85rem;
|
|
359
|
+
}
|
|
360
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { setContext, untrack } from "svelte";
|
|
3
|
+
import type { Snippet } from "svelte";
|
|
4
|
+
import { PUBLIC_SOLANA_RPC_ENDPOINT } from "../config.js";
|
|
5
|
+
import { wallet } from "../wallet/wallet.svelte.js";
|
|
6
|
+
|
|
7
|
+
let { rpcEndpoint = PUBLIC_SOLANA_RPC_ENDPOINT, children } = $props<{
|
|
8
|
+
children?: Snippet;
|
|
9
|
+
rpcEndpoint?: string;
|
|
10
|
+
}>();
|
|
11
|
+
|
|
12
|
+
$effect(() => {
|
|
13
|
+
const endpoint = rpcEndpoint;
|
|
14
|
+
|
|
15
|
+
untrack(() => {
|
|
16
|
+
void wallet.initialize(endpoint).catch(() => undefined);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
setContext("wallet", wallet);
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
{#if children}
|
|
24
|
+
{@render children()}
|
|
25
|
+
{/if}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
children?: Snippet;
|
|
4
|
+
rpcEndpoint?: string;
|
|
5
|
+
};
|
|
6
|
+
declare const WalletProvider: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type WalletProvider = ReturnType<typeof WalletProvider>;
|
|
8
|
+
export default WalletProvider;
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const browser: boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const browser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './components/index.js';
|
|
2
|
+
export { createWalletStore, wallet, type WalletStore } from './wallet/wallet.svelte.js';
|
|
3
|
+
export * from './wallet/mobile-detection.js';
|
|
4
|
+
export * from '@fernolab/wallet-adapter-core';
|
|
5
|
+
export type { WalletWithStandardCapabilities } from './wallet/types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { detectMobileRuntime } from '@fernolab/wallet-adapter-core';
|
|
2
|
+
import { browser } from '../environment.js';
|
|
3
|
+
function getRuntime() {
|
|
4
|
+
return detectMobileRuntime({
|
|
5
|
+
maxTouchPoints: browser ? navigator.maxTouchPoints : 0
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
export function isMobile() {
|
|
9
|
+
if (!browser)
|
|
10
|
+
return false;
|
|
11
|
+
return getRuntime().isMobile;
|
|
12
|
+
}
|
|
13
|
+
export function supportsWalletMobileProtocol() {
|
|
14
|
+
if (!browser)
|
|
15
|
+
return false;
|
|
16
|
+
return getRuntime().supportsMobileWalletAdapter;
|
|
17
|
+
}
|
|
18
|
+
export function getDeviceType() {
|
|
19
|
+
if (!browser)
|
|
20
|
+
return 'desktop';
|
|
21
|
+
if (!isMobile())
|
|
22
|
+
return 'desktop';
|
|
23
|
+
const width = window.innerWidth;
|
|
24
|
+
if (width < 768)
|
|
25
|
+
return 'mobile';
|
|
26
|
+
return 'tablet';
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|