@pollar/react 0.3.9

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/index.mjs ADDED
@@ -0,0 +1,575 @@
1
+ 'use client';
2
+ import { PollarClient, StellarClient, StateStatus, STATE_VAR_CODES, PollarStateVar, isValidSession, WalletType } from '@pollar/core';
3
+ import { createContext, useState, useEffect, useMemo, useContext, useRef } from 'react';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
+
6
+ // src/context.tsx
7
+
8
+ // src/constants.ts
9
+ var LOGO_POLLAR = "https://pollar.xyz/assets/logo_pollar.png";
10
+ var LOGO_GITHUB = "https://pollar.xyz/assets/GitHub_Invertocat_White.png";
11
+ var LOGO_FREIGHTER = "https://pollar.xyz/assets/logo_freighter.png";
12
+ var LOGO_ALBEDO = "https://pollar.xyz/assets/logo_albedo.svg";
13
+ function EmailCodeInput({ email, onSubmit }) {
14
+ const [digits, setDigits] = useState(["", "", "", "", "", ""]);
15
+ const inputRefs = useRef([]);
16
+ function submit(next) {
17
+ if (next.every(Boolean)) onSubmit(next.join(""));
18
+ }
19
+ function handleChange(index, value) {
20
+ const cleaned = value.replace(/\D/g, "").slice(-1);
21
+ const next = digits.map((d, i) => i === index ? cleaned : d);
22
+ setDigits(next);
23
+ if (cleaned && index < 5) inputRefs.current[index + 1]?.focus();
24
+ submit(next);
25
+ }
26
+ function handleKeyDown(index, e) {
27
+ if (e.key === "Backspace" && !digits[index] && index > 0) {
28
+ inputRefs.current[index - 1]?.focus();
29
+ }
30
+ }
31
+ function handlePaste(e) {
32
+ e.preventDefault();
33
+ const text = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, 6);
34
+ const next = Array.from({ length: 6 }, (_, i) => text[i] ?? "");
35
+ setDigits(next);
36
+ inputRefs.current[Math.min(text.length - 1, 5)]?.focus();
37
+ submit(next);
38
+ }
39
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-code-section", children: [
40
+ /* @__PURE__ */ jsxs("p", { className: "pollar-code-label", children: [
41
+ "Enter the 6-digit code sent to",
42
+ " ",
43
+ email ? /* @__PURE__ */ jsx("strong", { children: email }) : "your email"
44
+ ] }),
45
+ /* @__PURE__ */ jsx("div", { className: "pollar-code-inputs", children: digits.map((digit, i) => /* @__PURE__ */ jsx(
46
+ "input",
47
+ {
48
+ ref: (el) => {
49
+ inputRefs.current[i] = el;
50
+ },
51
+ type: "text",
52
+ inputMode: "numeric",
53
+ maxLength: 2,
54
+ value: digit,
55
+ className: "pollar-code-input",
56
+ onChange: (e) => handleChange(i, e.target.value),
57
+ onKeyDown: (e) => handleKeyDown(i, e),
58
+ onPaste: handlePaste
59
+ },
60
+ i
61
+ )) })
62
+ ] });
63
+ }
64
+ var GithubButton = ({ disabled, onClick }) => {
65
+ return /* @__PURE__ */ jsxs("button", { className: "github-button", disabled, onClick, children: [
66
+ /* @__PURE__ */ jsx("img", { src: LOGO_GITHUB, alt: "GitHub", className: "github-button-icon" }),
67
+ /* @__PURE__ */ jsx("span", { className: "github-button-contents", children: "Continue with GitHub" })
68
+ ] });
69
+ };
70
+ var GoogleButton = ({ disabled, onClick }) => {
71
+ return /* @__PURE__ */ jsxs("button", { className: "gsi-material-button", disabled, onClick, children: [
72
+ /* @__PURE__ */ jsx("div", { className: "gsi-material-button-state" }),
73
+ /* @__PURE__ */ jsxs("div", { className: "gsi-material-button-content-wrapper", children: [
74
+ /* @__PURE__ */ jsx("div", { className: "gsi-material-button-icon", children: /* @__PURE__ */ jsxs(
75
+ "svg",
76
+ {
77
+ version: "1.1",
78
+ xmlns: "http://www.w3.org/2000/svg",
79
+ viewBox: "0 0 48 48",
80
+ style: { display: "block" },
81
+ children: [
82
+ /* @__PURE__ */ jsx(
83
+ "path",
84
+ {
85
+ fill: "#EA4335",
86
+ d: "M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"
87
+ }
88
+ ),
89
+ /* @__PURE__ */ jsx(
90
+ "path",
91
+ {
92
+ fill: "#4285F4",
93
+ d: "M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"
94
+ }
95
+ ),
96
+ /* @__PURE__ */ jsx(
97
+ "path",
98
+ {
99
+ fill: "#FBBC05",
100
+ d: "M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"
101
+ }
102
+ ),
103
+ /* @__PURE__ */ jsx(
104
+ "path",
105
+ {
106
+ fill: "#34A853",
107
+ d: "M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"
108
+ }
109
+ ),
110
+ /* @__PURE__ */ jsx("path", { fill: "none", d: "M0 0h48v48H0z" })
111
+ ]
112
+ }
113
+ ) }),
114
+ /* @__PURE__ */ jsx("span", { className: "gsi-material-button-contents", children: "Continue with Google" }),
115
+ /* @__PURE__ */ jsx("span", { style: { display: "none" }, children: "Continue with Google" })
116
+ ] })
117
+ ] });
118
+ };
119
+ var LOGIN_CODE_MESSAGES = {
120
+ LOGOUT: { text: "Logged out" },
121
+ CREATE_SESSION_START: { text: "Starting session\u2026" },
122
+ CREATE_SESSION_ERROR: { text: "Failed to start session" },
123
+ CREATE_SESSION_SUCCESS: { text: "Session ready" },
124
+ EMAIL_AUTH_START: { text: "Sending code\u2026" },
125
+ EMAIL_AUTH_START_ERROR: { text: "Failed to send code" },
126
+ EMAIL_AUTH_START_SUCCESS: { text: "Code sent \u2014 check your inbox" },
127
+ EMAIL_AUTH_CODE_ERROR: { text: "Invalid code \u2014 try again" },
128
+ EMAIL_AUTH_CODE_SUCCESS: { text: "Code verified!" },
129
+ WALLET_AUTH_START: { text: "Connecting wallet\u2026" },
130
+ WALLET_AUTH_FREIGHTER_NOT_INSTALLED: { text: "Freighter is not installed" },
131
+ WALLET_AUTH_ALBEDO_NOT_INSTALLED: { text: "Albedo is not installed" },
132
+ WALLET_AUTH_CONNECTED: { text: "Wallet connected" },
133
+ WALLET_AUTH_LOGIN_START: { text: "Signing in with wallet\u2026" },
134
+ WALLET_AUTH_LOGIN_START_SUCCESS: { text: "Wallet signed in" },
135
+ WALLET_AUTH_LOGIN_START_ERROR: { text: "Failed to sign in with wallet" },
136
+ WALLET_AUTH_ERROR: { text: "Unknow wallet error" },
137
+ STREAM_POLL_START: { text: "Waiting for authentication\u2026" },
138
+ STREAM_POLL_EVENT: { text: "Waiting for authentication\u2026" },
139
+ STREAM_POLL_READY: { text: "Authenticated!" },
140
+ FETCH_SESSION_START: { text: "Loading session\u2026" },
141
+ FETCH_SESSION_SUCCESS: { text: "Welcome back!" },
142
+ FETCH_SESSION_ERROR: { text: "Failed to load session" },
143
+ ERROR_UNKNOWN: { text: "Something went wrong" },
144
+ ABORTED: { text: "Login cancelled" }
145
+ };
146
+ function LoginStatusBanner({ code, status, onCancel, onRetry }) {
147
+ if (!code) return /* @__PURE__ */ jsx("div", { className: "pollar-status" });
148
+ const { text } = LOGIN_CODE_MESSAGES[code] || { text: "" };
149
+ const isLoading = status === StateStatus.LOADING;
150
+ const icon = status === StateStatus.ERROR ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
151
+ /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
152
+ /* @__PURE__ */ jsx("path", { d: "M4.5 4.5l5 5M9.5 4.5l-5 5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" })
153
+ ] }) : status === StateStatus.SUCCESS ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
154
+ /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
155
+ /* @__PURE__ */ jsx("path", { d: "M3.5 7l2.5 2.5 4.5-5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
156
+ ] }) : status === StateStatus.LOADING ? /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeDasharray: "22 10" }) }) : null;
157
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-status", "data-kind": status, children: [
158
+ icon,
159
+ /* @__PURE__ */ jsx("span", { children: text }),
160
+ isLoading && onCancel && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onCancel, children: "Cancel" }),
161
+ status === StateStatus.ERROR && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onRetry, children: "Retry" })
162
+ ] });
163
+ }
164
+ function LoginModalTemplate({
165
+ theme,
166
+ accentColor,
167
+ logoUrl,
168
+ emailEnabled,
169
+ embeddedWallets,
170
+ providers,
171
+ appName,
172
+ email = "",
173
+ status,
174
+ error,
175
+ onEmailChange,
176
+ onEmailSubmit,
177
+ onSocialLogin,
178
+ onFreighterConnect,
179
+ onAlbedoConnect,
180
+ loginStateCode,
181
+ awaitingEmailCode = false,
182
+ onCodeSubmit,
183
+ cancelLoginRef,
184
+ onRetry
185
+ }) {
186
+ const isDark = theme === "dark";
187
+ const enabledSocial = Object.entries(providers).filter(([, enabled]) => enabled);
188
+ const cssVars = {
189
+ "--pollar-accent": accentColor,
190
+ "--pollar-buttons-border-radius": "6px",
191
+ "--pollar-buttons-height": "44px",
192
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
193
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
194
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
195
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
196
+ "--pollar-input-bg": isDark ? "#374151" : "#ffffff",
197
+ "--pollar-error-bg": isDark ? "#2a1515" : "#fef2f2",
198
+ "--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
199
+ "--pollar-error-text": isDark ? "#f87171" : "#dc2626"
200
+ };
201
+ const isLoading = status === StateStatus.LOADING;
202
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
203
+ /* @__PURE__ */ jsxs("div", { className: "pollar-header", children: [
204
+ /* @__PURE__ */ jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsx("img", { src: logoUrl ?? LOGO_POLLAR, alt: "Logo", className: "pollar-logo" }) }),
205
+ /* @__PURE__ */ jsx("h2", { className: "pollar-title", children: appName }),
206
+ /* @__PURE__ */ jsx("p", { className: "pollar-subtitle", children: "Log in or sign up" })
207
+ ] }),
208
+ awaitingEmailCode ? /* @__PURE__ */ jsx(EmailCodeInput, { email, onSubmit: onCodeSubmit ?? (() => {
209
+ }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
210
+ error && /* @__PURE__ */ jsx("div", { className: "pollar-error", children: error }),
211
+ emailEnabled && /* @__PURE__ */ jsxs("div", { className: "pollar-email-section", children: [
212
+ /* @__PURE__ */ jsx(
213
+ "input",
214
+ {
215
+ type: "email",
216
+ placeholder: "you@email.com",
217
+ value: email,
218
+ disabled: isLoading,
219
+ className: "pollar-email-input",
220
+ onChange: (e) => onEmailChange?.(e.target.value),
221
+ onKeyDown: (e) => e.key === "Enter" && onEmailSubmit?.()
222
+ }
223
+ ),
224
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: isLoading || !email, className: "pollar-submit-btn", onClick: onEmailSubmit, children: "Submit" })
225
+ ] }),
226
+ emailEnabled && enabledSocial.length > 0 && /* @__PURE__ */ jsxs("div", { className: "pollar-divider", children: [
227
+ /* @__PURE__ */ jsx("div", { className: "pollar-divider-line" }),
228
+ /* @__PURE__ */ jsx("div", { className: "pollar-divider-label", children: /* @__PURE__ */ jsx("span", { className: "pollar-divider-text", children: "or continue with" }) })
229
+ ] }),
230
+ enabledSocial.length > 0 && /* @__PURE__ */ jsxs("div", { className: "pollar-social-list", children: [
231
+ enabledSocial.some(([key]) => key === "google") && /* @__PURE__ */ jsx(GoogleButton, { disabled: isLoading, onClick: () => onSocialLogin?.("google") }),
232
+ enabledSocial.some(([key]) => key === "github") && /* @__PURE__ */ jsx(GithubButton, { disabled: isLoading, onClick: () => onSocialLogin?.("github") })
233
+ ] }),
234
+ embeddedWallets && /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-section", children: [
235
+ /* @__PURE__ */ jsx("p", { className: "pollar-wallet-label", children: "Continue with a wallet" }),
236
+ /* @__PURE__ */ jsxs("button", { type: "button", disabled: isLoading, className: "pollar-wallet-btn", onClick: onFreighterConnect, children: [
237
+ /* @__PURE__ */ jsx("img", { src: LOGO_FREIGHTER, alt: "Freighter", className: "pollar-wallet-icon" }),
238
+ "Freighter"
239
+ ] }),
240
+ /* @__PURE__ */ jsxs("button", { type: "button", disabled: isLoading, className: "pollar-wallet-btn", onClick: onAlbedoConnect, children: [
241
+ /* @__PURE__ */ jsx("img", { src: LOGO_ALBEDO, alt: "Albedo", className: "pollar-wallet-icon" }),
242
+ "Albedo"
243
+ ] })
244
+ ] })
245
+ ] }),
246
+ /* @__PURE__ */ jsx(LoginStatusBanner, { code: loginStateCode, status, onCancel: () => cancelLoginRef.current?.(), onRetry }),
247
+ /* @__PURE__ */ jsxs("div", { className: "pollar-footer", children: [
248
+ /* @__PURE__ */ jsx("span", { className: "pollar-footer-protected", children: "Protected by" }),
249
+ /* @__PURE__ */ jsxs("div", { className: "pollar-footer-brand", children: [
250
+ /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR, alt: "Pollar", className: "pollar-footer-logo" }),
251
+ /* @__PURE__ */ jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
252
+ /* @__PURE__ */ jsxs("span", { className: "pollar-footer-version", children: [
253
+ "v",
254
+ "0.3.9"
255
+ ] })
256
+ ] })
257
+ ] })
258
+ ] });
259
+ }
260
+ function isLoginCode(code) {
261
+ return Object.values(STATE_VAR_CODES[PollarStateVar.LOGIN]).includes(code);
262
+ }
263
+ function LoginModal({ onClose }) {
264
+ const [email, setEmail] = useState("");
265
+ const { getClient, styles, config } = usePollar();
266
+ const [status, setStatus] = useState(StateStatus.NONE);
267
+ const [error, setError] = useState(null);
268
+ const [loginStateCode, setLoginStateCode] = useState(null);
269
+ const [awaitingEmailCode, setAwaitingEmailCode] = useState(false);
270
+ const [clientSessionId, setClientSessionId] = useState(null);
271
+ useEffect(() => {
272
+ return getClient().onStateChange((stateEntry) => {
273
+ if (stateEntry.var === PollarStateVar.LOGIN && isLoginCode(stateEntry.code)) {
274
+ setLoginStateCode(stateEntry.code);
275
+ setStatus(stateEntry.status);
276
+ if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.LOGIN].STREAM_POLL_START) {
277
+ const data = stateEntry.data;
278
+ setClientSessionId(data.clientSessionId);
279
+ }
280
+ if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.LOGIN].STREAM_POLL_EVENT) {
281
+ const data = stateEntry.data;
282
+ if (data?.status === "AWAITING_EMAIL") {
283
+ setAwaitingEmailCode(true);
284
+ }
285
+ }
286
+ if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.LOGIN].FETCH_SESSION_SUCCESS) {
287
+ setAwaitingEmailCode(false);
288
+ setTimeout(onClose, 1e3);
289
+ }
290
+ }
291
+ });
292
+ }, []);
293
+ const { theme = "light", accentColor = "#005DB4", logoUrl, emailEnabled, embeddedWallets, providers } = styles;
294
+ function handleClose() {
295
+ setEmail("");
296
+ setError(null);
297
+ setAwaitingEmailCode(false);
298
+ setClientSessionId(null);
299
+ onClose();
300
+ }
301
+ const cancelLoginRef = useRef(null);
302
+ function handleEmail() {
303
+ if (!email) {
304
+ return;
305
+ }
306
+ const { cancelLogin } = getClient().login({ provider: "email", email });
307
+ cancelLoginRef.current = cancelLogin;
308
+ }
309
+ function handleSocialLogin(provider) {
310
+ const { cancelLogin } = getClient().login({ provider });
311
+ cancelLoginRef.current = cancelLogin;
312
+ }
313
+ function handleWalletConnect(type) {
314
+ const { cancelLogin } = getClient().login({ provider: "wallet", type });
315
+ cancelLoginRef.current = cancelLogin;
316
+ }
317
+ async function handleVerifyCode(code) {
318
+ if (!clientSessionId) return;
319
+ void getClient().verifyEmailCode(clientSessionId, code);
320
+ }
321
+ function handleRetry() {
322
+ getClient().logout();
323
+ }
324
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: handleClose, children: /* @__PURE__ */ jsx(
325
+ LoginModalTemplate,
326
+ {
327
+ theme,
328
+ accentColor,
329
+ logoUrl: logoUrl ?? null,
330
+ emailEnabled: !!emailEnabled,
331
+ embeddedWallets: !!embeddedWallets,
332
+ providers: {
333
+ google: !!providers?.google,
334
+ discord: !!providers?.discord,
335
+ x: !!providers?.x,
336
+ github: !!providers?.github,
337
+ apple: !!providers?.apple
338
+ },
339
+ appName: config.application?.name ?? "Pollar",
340
+ email,
341
+ status,
342
+ error,
343
+ onEmailChange: setEmail,
344
+ onEmailSubmit: handleEmail,
345
+ onSocialLogin: handleSocialLogin,
346
+ onFreighterConnect: () => handleWalletConnect(WalletType.FREIGHTER),
347
+ onAlbedoConnect: () => handleWalletConnect(WalletType.ALBEDO),
348
+ loginStateCode,
349
+ awaitingEmailCode,
350
+ onCodeSubmit: handleVerifyCode,
351
+ cancelLoginRef,
352
+ onRetry: handleRetry
353
+ }
354
+ ) });
355
+ }
356
+ var emptyResponse = {
357
+ application: {
358
+ name: ""
359
+ },
360
+ styles: {}
361
+ };
362
+ async function fetchRemoteConfig(api) {
363
+ try {
364
+ const { data, error } = await api.GET(`/config`);
365
+ if (!data || error) {
366
+ return emptyResponse;
367
+ }
368
+ return data.content;
369
+ } catch {
370
+ return emptyResponse;
371
+ }
372
+ }
373
+ var PollarContext = createContext(null);
374
+ function PollarProvider({ config, styles: propStyles, children }) {
375
+ const [pollarClient] = useState(() => new PollarClient(config));
376
+ const [stellarClient] = useState(() => new StellarClient(config.stellarNetwork || "testnet"));
377
+ const [sessionState, setSessionState] = useState(null);
378
+ const [state, setState] = useState({
379
+ [PollarStateVar.LOGIN]: {
380
+ var: PollarStateVar.LOGIN,
381
+ code: STATE_VAR_CODES[PollarStateVar.LOGIN].NONE,
382
+ status: StateStatus.NONE,
383
+ level: "info",
384
+ ts: 0
385
+ },
386
+ [PollarStateVar.WALLET_ADDRESS]: {
387
+ var: PollarStateVar.WALLET_ADDRESS,
388
+ code: STATE_VAR_CODES[PollarStateVar.WALLET_ADDRESS].NONE,
389
+ status: StateStatus.NONE,
390
+ level: "info",
391
+ ts: 0
392
+ }
393
+ });
394
+ const [remoteConfig, setRemoteConfig] = useState(emptyResponse);
395
+ const [styles, setStyles] = useState(propStyles ?? {});
396
+ useEffect(() => {
397
+ return pollarClient.onStateChange((stateEntry) => {
398
+ setState((prevState) => {
399
+ if (JSON.stringify(prevState[stateEntry.var]) !== JSON.stringify(stateEntry)) {
400
+ return {
401
+ ...prevState,
402
+ [stateEntry.var]: stateEntry
403
+ };
404
+ }
405
+ return prevState;
406
+ });
407
+ if (stateEntry.var === PollarStateVar.WALLET_ADDRESS) {
408
+ if (stateEntry.code === STATE_VAR_CODES[PollarStateVar.WALLET_ADDRESS].UPDATED_ADDRESS && isValidSession(stateEntry.data)) {
409
+ setSessionState((prevState) => {
410
+ if (JSON.stringify(prevState) !== JSON.stringify(stateEntry.data)) {
411
+ return stateEntry.data;
412
+ }
413
+ return prevState;
414
+ });
415
+ }
416
+ }
417
+ if (stateEntry.var === PollarStateVar.WALLET_ADDRESS && stateEntry.code === STATE_VAR_CODES[PollarStateVar.WALLET_ADDRESS].REMOVED_ADDRESS || stateEntry.var === PollarStateVar.LOGIN && stateEntry.code === STATE_VAR_CODES[PollarStateVar.LOGIN].LOGOUT) {
418
+ setSessionState(null);
419
+ }
420
+ });
421
+ }, [pollarClient]);
422
+ useEffect(() => {
423
+ fetchRemoteConfig(pollarClient.getApi()).then((fetched) => {
424
+ setRemoteConfig(fetched);
425
+ setStyles({
426
+ ...fetched.styles,
427
+ ...propStyles,
428
+ providers: { ...fetched.styles?.providers, ...propStyles?.providers }
429
+ });
430
+ }).catch(() => {
431
+ setStyles(propStyles ?? {});
432
+ });
433
+ }, [pollarClient]);
434
+ const [modalOpen, setModalOpen] = useState(false);
435
+ const contextValue = useMemo(
436
+ () => ({
437
+ walletAddress: sessionState?.wallet?.publicKey || "",
438
+ getClient: () => pollarClient,
439
+ openLoginModal: () => setModalOpen(true),
440
+ isAuthenticated: pollarClient.isAuthenticated(),
441
+ login: (options) => pollarClient.login(options),
442
+ logout: () => pollarClient.logout(),
443
+ config: remoteConfig,
444
+ state,
445
+ styles,
446
+ async getBalance(publicKey) {
447
+ const pk = publicKey || sessionState?.wallet?.publicKey;
448
+ if (pk) {
449
+ return stellarClient.getBalances(pk);
450
+ }
451
+ return null;
452
+ }
453
+ }),
454
+ [sessionState, remoteConfig, styles, pollarClient, state]
455
+ );
456
+ return /* @__PURE__ */ jsxs(PollarContext.Provider, { value: contextValue, children: [
457
+ children,
458
+ modalOpen && /* @__PURE__ */ jsx(LoginModal, { onClose: () => setModalOpen(false) })
459
+ ] });
460
+ }
461
+ function usePollar() {
462
+ const ctx = useContext(PollarContext);
463
+ if (!ctx) {
464
+ throw new Error("usePollar must be used inside <PollarProvider>");
465
+ }
466
+ return ctx;
467
+ }
468
+ function cropWallet(address) {
469
+ if (address.length <= 12) return address;
470
+ return `${address.slice(0, 6)}...${address.slice(-4)}`;
471
+ }
472
+ function ButtonLogo() {
473
+ return /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR, alt: "Pollar", width: 22, height: 22, className: "wallet-btn-logo" });
474
+ }
475
+ function WalletButton() {
476
+ const { getClient, walletAddress, styles, openLoginModal } = usePollar();
477
+ const [open, setOpen] = useState(false);
478
+ const [copied, setCopied] = useState(false);
479
+ const wrapperRef = useRef(null);
480
+ const { theme = "light", accentColor = "#005DB4" } = styles;
481
+ const isDark = theme === "dark";
482
+ const dropdownBg = isDark ? "#18181b" : "#fff";
483
+ const dropdownBorder = isDark ? "#3f3f46" : "#e4e4e7";
484
+ const itemColor = isDark ? "#fafafa" : "#18181b";
485
+ useEffect(() => {
486
+ function handleClickOutside(e) {
487
+ if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
488
+ setOpen(false);
489
+ }
490
+ }
491
+ document.addEventListener("mousedown", handleClickOutside);
492
+ return () => document.removeEventListener("mousedown", handleClickOutside);
493
+ }, []);
494
+ async function handleCopy() {
495
+ if (!walletAddress) return;
496
+ await navigator.clipboard.writeText(walletAddress);
497
+ setCopied(true);
498
+ setTimeout(() => setCopied(false), 1500);
499
+ }
500
+ function handleLogout() {
501
+ setOpen(false);
502
+ getClient().logout();
503
+ }
504
+ if (!walletAddress) {
505
+ return /* @__PURE__ */ jsxs("button", { type: "button", className: "wallet-login-btn", style: { backgroundColor: accentColor }, onClick: openLoginModal, children: [
506
+ /* @__PURE__ */ jsx(ButtonLogo, {}),
507
+ "Login with Pollar"
508
+ ] });
509
+ }
510
+ return /* @__PURE__ */ jsxs("div", { className: "wallet-wrapper", ref: wrapperRef, children: [
511
+ /* @__PURE__ */ jsxs("button", { className: "wallet-btn", style: { backgroundColor: accentColor }, onClick: () => setOpen((v) => !v), children: [
512
+ cropWallet(walletAddress),
513
+ /* @__PURE__ */ jsx(
514
+ "svg",
515
+ {
516
+ className: `wallet-chevron${open ? " open" : ""}`,
517
+ viewBox: "0 0 12 12",
518
+ fill: "none",
519
+ stroke: "currentColor",
520
+ strokeWidth: "2",
521
+ strokeLinecap: "round",
522
+ strokeLinejoin: "round",
523
+ children: /* @__PURE__ */ jsx("polyline", { points: "2,4 6,8 10,4" })
524
+ }
525
+ )
526
+ ] }),
527
+ open && /* @__PURE__ */ jsxs("div", { className: "wallet-dropdown", style: { backgroundColor: dropdownBg, borderColor: dropdownBorder }, children: [
528
+ /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item", style: { color: itemColor }, onClick: handleCopy, children: [
529
+ /* @__PURE__ */ jsxs(
530
+ "svg",
531
+ {
532
+ width: "14",
533
+ height: "14",
534
+ viewBox: "0 0 24 24",
535
+ fill: "none",
536
+ stroke: "currentColor",
537
+ strokeWidth: "2",
538
+ strokeLinecap: "round",
539
+ strokeLinejoin: "round",
540
+ children: [
541
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
542
+ /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
543
+ ]
544
+ }
545
+ ),
546
+ copied ? "Copied!" : "Copy address"
547
+ ] }),
548
+ /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item danger", onClick: handleLogout, children: [
549
+ /* @__PURE__ */ jsxs(
550
+ "svg",
551
+ {
552
+ width: "14",
553
+ height: "14",
554
+ viewBox: "0 0 24 24",
555
+ fill: "none",
556
+ stroke: "currentColor",
557
+ strokeWidth: "2",
558
+ strokeLinecap: "round",
559
+ strokeLinejoin: "round",
560
+ children: [
561
+ /* @__PURE__ */ jsx("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
562
+ /* @__PURE__ */ jsx("polyline", { points: "16,17 21,12 16,7" }),
563
+ /* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
564
+ ]
565
+ }
566
+ ),
567
+ "Log out"
568
+ ] })
569
+ ] })
570
+ ] });
571
+ }
572
+
573
+ export { PollarProvider, WalletButton, usePollar };
574
+ //# sourceMappingURL=index.mjs.map
575
+ //# sourceMappingURL=index.mjs.map