@pollar/react 0.9.0-rc.1 → 0.9.0-rc.3

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.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { WalletId, AuthState, pollarPaths, PollarClient, PollarClientConfig, PollarAdapters, OnStorageDegrade, PollarLoginOptions, SessionsState, TransactionState, TxBuildBody, BuildOutcome, SubmitOutcome, SignOutcome, StellarNetwork, WalletBalanceState, EnabledAssetsState, TxHistoryState, PollarAdapter, KycStatus as KycStatus$1, RampQuote, KycProvider, KycStartResponse, RampDirection, PaymentInstructions, WalletBalanceRecord, DistributionRulesState, DistributionRule } from '@pollar/core';
2
+ import { WalletId, AuthState, pollarPaths, PollarClient, PollarClientConfig, PollarAdapters, OnStorageDegrade, PollarLoginOptions, SessionsState, TransactionState, TxBuildBody, BuildOutcome, SubmitOutcome, SignOutcome, StellarNetwork, WalletBalanceState, EnabledAssetsState, TrustlineOutcome, TxHistoryState, PollarAdapter, KycStatus as KycStatus$1, RampQuote, KycProvider, KycStartResponse, RampDirection, PaymentInstructions, EnabledAssetRecord, WalletBalanceRecord, DistributionRulesState, DistributionRule } from '@pollar/core';
3
3
  export { SessionsState } from '@pollar/core';
4
4
  import { ReactNode } from 'react';
5
5
 
@@ -78,6 +78,19 @@ interface PollarContextValue {
78
78
  */
79
79
  enabledAssets: EnabledAssetsState;
80
80
  refreshAssets: () => Promise<void>;
81
+ /**
82
+ * Establishes (omit `limit`) or removes (`limit: '0'`) a trustline for an
83
+ * asset. Pass the asset's `sponsored` flag so the app covers the reserve + fee
84
+ * when eligible; otherwise the user's own wallet pays. Mirrors
85
+ * {@link PollarClient.setTrustline}.
86
+ */
87
+ setTrustline: (asset: {
88
+ code: string;
89
+ issuer: string;
90
+ }, opts?: {
91
+ limit?: string;
92
+ sponsored?: boolean;
93
+ }) => Promise<TrustlineOutcome>;
81
94
  /** Open the enabled-assets / trustline-state modal. */
82
95
  openEnabledAssetsModal: () => void;
83
96
  openKycModal: (options?: {
@@ -245,7 +258,10 @@ interface LoginModalTemplateProps {
245
258
  onEmailSubmit?: () => void;
246
259
  onSocialLogin?: (provider: 'google' | 'github') => void;
247
260
  onWalletConnect?: (id: WalletId) => void;
248
- onSmartWallet?: () => void;
261
+ /** Log in with an existing passkey (returning user). */
262
+ onLoginSmartWallet?: () => void;
263
+ /** Create a new passkey + smart wallet (new user). */
264
+ onCreateSmartWallet?: () => void;
249
265
  /** Optional override for the wallet picker view. Defaults to a Freighter+Albedo list. */
250
266
  renderWallets?: RenderWalletsSlot;
251
267
  authState: AuthState;
@@ -255,7 +271,7 @@ interface LoginModalTemplateProps {
255
271
  onCancel: () => void;
256
272
  onRetry: () => void;
257
273
  }
258
- declare function LoginModalTemplate({ theme, accentColor, logoUrl, emailEnabled, embeddedWallets, smartWallet, providers, appName, email, onEmailChange, onEmailSubmit, onSocialLogin, onWalletConnect, onSmartWallet, renderWallets, authState, codeInputKey, onCodeSubmit, onBack, onCancel, onRetry, }: LoginModalTemplateProps): react_jsx_runtime.JSX.Element;
274
+ declare function LoginModalTemplate({ theme, accentColor, logoUrl, emailEnabled, embeddedWallets, smartWallet, providers, appName, email, onEmailChange, onEmailSubmit, onSocialLogin, onWalletConnect, onLoginSmartWallet, onCreateSmartWallet, renderWallets, authState, codeInputKey, onCodeSubmit, onBack, onCancel, onRetry, }: LoginModalTemplateProps): react_jsx_runtime.JSX.Element;
259
275
 
260
276
  type KycStep = 'select_provider' | 'verifying' | 'polling' | 'done';
261
277
  interface KycModalTemplateProps {
@@ -353,10 +369,15 @@ interface EnabledAssetsModalTemplateProps {
353
369
  accentColor: string;
354
370
  enabledAssets: EnabledAssetsState;
355
371
  walletAddress: string;
372
+ /** Key (`code+issuer`) of the asset whose trustline action is in flight. */
373
+ busyKey: string | null;
374
+ actionError: string | null;
356
375
  onRefresh: () => void;
357
376
  onClose: () => void;
377
+ onToggleTrustline: (record: EnabledAssetRecord) => void;
378
+ onAddCustom: () => void;
358
379
  }
359
- declare function EnabledAssetsModalTemplate({ theme, accentColor, enabledAssets, walletAddress, onRefresh, onClose, }: EnabledAssetsModalTemplateProps): react_jsx_runtime.JSX.Element;
380
+ declare function EnabledAssetsModalTemplate({ theme, accentColor, enabledAssets, walletAddress, busyKey, actionError, onRefresh, onClose, onToggleTrustline, onAddCustom, }: EnabledAssetsModalTemplateProps): react_jsx_runtime.JSX.Element;
360
381
 
361
382
  interface SendModalTemplateProps {
362
383
  theme: string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { WalletId, AuthState, pollarPaths, PollarClient, PollarClientConfig, PollarAdapters, OnStorageDegrade, PollarLoginOptions, SessionsState, TransactionState, TxBuildBody, BuildOutcome, SubmitOutcome, SignOutcome, StellarNetwork, WalletBalanceState, EnabledAssetsState, TxHistoryState, PollarAdapter, KycStatus as KycStatus$1, RampQuote, KycProvider, KycStartResponse, RampDirection, PaymentInstructions, WalletBalanceRecord, DistributionRulesState, DistributionRule } from '@pollar/core';
2
+ import { WalletId, AuthState, pollarPaths, PollarClient, PollarClientConfig, PollarAdapters, OnStorageDegrade, PollarLoginOptions, SessionsState, TransactionState, TxBuildBody, BuildOutcome, SubmitOutcome, SignOutcome, StellarNetwork, WalletBalanceState, EnabledAssetsState, TrustlineOutcome, TxHistoryState, PollarAdapter, KycStatus as KycStatus$1, RampQuote, KycProvider, KycStartResponse, RampDirection, PaymentInstructions, EnabledAssetRecord, WalletBalanceRecord, DistributionRulesState, DistributionRule } from '@pollar/core';
3
3
  export { SessionsState } from '@pollar/core';
4
4
  import { ReactNode } from 'react';
5
5
 
@@ -78,6 +78,19 @@ interface PollarContextValue {
78
78
  */
79
79
  enabledAssets: EnabledAssetsState;
80
80
  refreshAssets: () => Promise<void>;
81
+ /**
82
+ * Establishes (omit `limit`) or removes (`limit: '0'`) a trustline for an
83
+ * asset. Pass the asset's `sponsored` flag so the app covers the reserve + fee
84
+ * when eligible; otherwise the user's own wallet pays. Mirrors
85
+ * {@link PollarClient.setTrustline}.
86
+ */
87
+ setTrustline: (asset: {
88
+ code: string;
89
+ issuer: string;
90
+ }, opts?: {
91
+ limit?: string;
92
+ sponsored?: boolean;
93
+ }) => Promise<TrustlineOutcome>;
81
94
  /** Open the enabled-assets / trustline-state modal. */
82
95
  openEnabledAssetsModal: () => void;
83
96
  openKycModal: (options?: {
@@ -245,7 +258,10 @@ interface LoginModalTemplateProps {
245
258
  onEmailSubmit?: () => void;
246
259
  onSocialLogin?: (provider: 'google' | 'github') => void;
247
260
  onWalletConnect?: (id: WalletId) => void;
248
- onSmartWallet?: () => void;
261
+ /** Log in with an existing passkey (returning user). */
262
+ onLoginSmartWallet?: () => void;
263
+ /** Create a new passkey + smart wallet (new user). */
264
+ onCreateSmartWallet?: () => void;
249
265
  /** Optional override for the wallet picker view. Defaults to a Freighter+Albedo list. */
250
266
  renderWallets?: RenderWalletsSlot;
251
267
  authState: AuthState;
@@ -255,7 +271,7 @@ interface LoginModalTemplateProps {
255
271
  onCancel: () => void;
256
272
  onRetry: () => void;
257
273
  }
258
- declare function LoginModalTemplate({ theme, accentColor, logoUrl, emailEnabled, embeddedWallets, smartWallet, providers, appName, email, onEmailChange, onEmailSubmit, onSocialLogin, onWalletConnect, onSmartWallet, renderWallets, authState, codeInputKey, onCodeSubmit, onBack, onCancel, onRetry, }: LoginModalTemplateProps): react_jsx_runtime.JSX.Element;
274
+ declare function LoginModalTemplate({ theme, accentColor, logoUrl, emailEnabled, embeddedWallets, smartWallet, providers, appName, email, onEmailChange, onEmailSubmit, onSocialLogin, onWalletConnect, onLoginSmartWallet, onCreateSmartWallet, renderWallets, authState, codeInputKey, onCodeSubmit, onBack, onCancel, onRetry, }: LoginModalTemplateProps): react_jsx_runtime.JSX.Element;
259
275
 
260
276
  type KycStep = 'select_provider' | 'verifying' | 'polling' | 'done';
261
277
  interface KycModalTemplateProps {
@@ -353,10 +369,15 @@ interface EnabledAssetsModalTemplateProps {
353
369
  accentColor: string;
354
370
  enabledAssets: EnabledAssetsState;
355
371
  walletAddress: string;
372
+ /** Key (`code+issuer`) of the asset whose trustline action is in flight. */
373
+ busyKey: string | null;
374
+ actionError: string | null;
356
375
  onRefresh: () => void;
357
376
  onClose: () => void;
377
+ onToggleTrustline: (record: EnabledAssetRecord) => void;
378
+ onAddCustom: () => void;
358
379
  }
359
- declare function EnabledAssetsModalTemplate({ theme, accentColor, enabledAssets, walletAddress, onRefresh, onClose, }: EnabledAssetsModalTemplateProps): react_jsx_runtime.JSX.Element;
380
+ declare function EnabledAssetsModalTemplate({ theme, accentColor, enabledAssets, walletAddress, busyKey, actionError, onRefresh, onClose, onToggleTrustline, onAddCustom, }: EnabledAssetsModalTemplateProps): react_jsx_runtime.JSX.Element;
360
381
 
361
382
  interface SendModalTemplateProps {
362
383
  theme: string;
package/dist/index.js CHANGED
@@ -1035,7 +1035,7 @@ var PollarModalFooter = () => {
1035
1035
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
1036
1036
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
1037
1037
  "v",
1038
- "0.9.0-rc.1"
1038
+ "0.9.0-rc.3"
1039
1039
  ] })
1040
1040
  ] })
1041
1041
  ] });
@@ -1270,26 +1270,9 @@ function cropAddress(address) {
1270
1270
  if (address.length <= 16) return address;
1271
1271
  return `${address.slice(0, 8)}...${address.slice(-8)}`;
1272
1272
  }
1273
- function AssetItem({ record }) {
1274
- const established = record.trustlineEstablished;
1275
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-item", children: [
1276
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-info", children: [
1277
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-code", children: record.code }),
1278
- record.name && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-name", children: record.name })
1279
- ] }),
1280
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `pollar-asset-trustline${established ? " established" : ""}`, children: established ? "Trustline active" : "Needs trustline" })
1281
- ] });
1282
- }
1283
- function EnabledAssetsModalTemplate({
1284
- theme,
1285
- accentColor,
1286
- enabledAssets,
1287
- walletAddress,
1288
- onRefresh,
1289
- onClose
1290
- }) {
1273
+ function cssVarsFor(theme, accentColor) {
1291
1274
  const isDark = theme === "dark";
1292
- const cssVars = {
1275
+ return {
1293
1276
  "--pollar-accent": accentColor,
1294
1277
  "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
1295
1278
  "--pollar-border": isDark ? "#374151" : "#e5e7eb",
@@ -1306,13 +1289,62 @@ function EnabledAssetsModalTemplate({
1306
1289
  "--pollar-input-border-radius": "0.5rem",
1307
1290
  "--pollar-card-border-radius": "10px"
1308
1291
  };
1292
+ }
1293
+ function assetKey(record) {
1294
+ return record.code + (record.issuer ?? "");
1295
+ }
1296
+ function AssetItem({
1297
+ record,
1298
+ busy,
1299
+ disabled,
1300
+ onToggle
1301
+ }) {
1302
+ const established = record.trustlineEstablished;
1303
+ const isNative = record.type === "native";
1304
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-item", children: [
1305
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-info", children: [
1306
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-code-row", children: [
1307
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-code", children: record.code }),
1308
+ record.enabledInApp && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-tag", children: "App" })
1309
+ ] }),
1310
+ record.name && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-name", children: record.name }),
1311
+ !isNative && record.enabledInApp && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-sponsor", children: record.sponsored ? "Reserve sponsored by the app" : "You pay the reserve (~0.5 XLM)" })
1312
+ ] }),
1313
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-actions", children: [
1314
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `pollar-asset-trustline${established ? " established" : ""}`, children: established ? "Trustline active" : "Needs trustline" }),
1315
+ !isNative && /* @__PURE__ */ jsxRuntime.jsx(
1316
+ "button",
1317
+ {
1318
+ className: `pollar-asset-btn${established ? " danger" : ""}`,
1319
+ onClick: () => onToggle(record),
1320
+ disabled: busy || disabled,
1321
+ children: busy ? "\u2026" : established ? "Disable" : "Enable"
1322
+ }
1323
+ )
1324
+ ] })
1325
+ ] });
1326
+ }
1327
+ function EnabledAssetsModalTemplate({
1328
+ theme,
1329
+ accentColor,
1330
+ enabledAssets,
1331
+ walletAddress,
1332
+ busyKey,
1333
+ actionError,
1334
+ onRefresh,
1335
+ onClose,
1336
+ onToggleTrustline,
1337
+ onAddCustom
1338
+ }) {
1339
+ const cssVars = cssVarsFor(theme, accentColor);
1309
1340
  const isLoading = enabledAssets.step === "loading";
1310
1341
  const data = enabledAssets.step === "loaded" ? enabledAssets.data : null;
1342
+ const busy = busyKey !== null;
1311
1343
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-asset-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
1312
1344
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
1313
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Enabled Assets" }),
1345
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Trustlines" }),
1314
1346
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header-actions", children: [
1315
- /* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-modal-refresh-btn", onClick: onRefresh, disabled: isLoading, children: [
1347
+ /* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-modal-refresh-btn", onClick: onRefresh, disabled: isLoading || busy, children: [
1316
1348
  /* @__PURE__ */ jsxRuntime.jsxs(
1317
1349
  "svg",
1318
1350
  {
@@ -1336,31 +1368,199 @@ function EnabledAssetsModalTemplate({
1336
1368
  walletAddress && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-asset-address", children: cropAddress(walletAddress) }),
1337
1369
  isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
1338
1370
  enabledAssets.step === "error" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: enabledAssets.message }),
1371
+ actionError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-action-error", children: actionError }),
1339
1372
  data && !data.exists && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-empty", children: [
1340
1373
  "Account not found on ",
1341
1374
  data.network,
1342
1375
  "."
1343
1376
  ] }),
1344
- data && data.assets.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No assets enabled for this application." }),
1345
- data && data.assets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-asset-list", children: data.assets.map((a) => /* @__PURE__ */ jsxRuntime.jsx(AssetItem, { record: a }, a.code + (a.issuer ?? ""))) }),
1377
+ data && data.assets.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No trustlines found." }),
1378
+ data && data.assets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-asset-list", children: data.assets.map((a) => /* @__PURE__ */ jsxRuntime.jsx(
1379
+ AssetItem,
1380
+ {
1381
+ record: a,
1382
+ busy: busyKey === assetKey(a),
1383
+ disabled: busy && busyKey !== assetKey(a),
1384
+ onToggle: onToggleTrustline
1385
+ },
1386
+ assetKey(a)
1387
+ )) }),
1388
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-asset-add-custom", onClick: onAddCustom, disabled: busy, children: "+ Add custom trustline" }),
1346
1389
  /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
1347
1390
  ] });
1348
1391
  }
1392
+ function isValidIssuer(issuer) {
1393
+ return issuer.length === 56 && issuer.startsWith("G");
1394
+ }
1395
+ function CustomTrustlineModalTemplate({
1396
+ theme,
1397
+ accentColor,
1398
+ busy,
1399
+ actionError,
1400
+ onBack,
1401
+ onClose,
1402
+ onSubmit
1403
+ }) {
1404
+ const cssVars = cssVarsFor(theme, accentColor);
1405
+ const [code, setCode] = react.useState("");
1406
+ const [issuer, setIssuer] = react.useState("");
1407
+ const [limit, setLimit] = react.useState("");
1408
+ const codeOk = code.trim().length >= 1 && code.trim().length <= 12;
1409
+ const issuerOk = isValidIssuer(issuer.trim());
1410
+ const canSubmit = codeOk && issuerOk && !busy;
1411
+ const submit = () => {
1412
+ if (!canSubmit) return;
1413
+ const trimmedLimit = limit.trim();
1414
+ onSubmit({ code: code.trim(), issuer: issuer.trim(), ...trimmedLimit ? { limit: trimmedLimit } : {} });
1415
+ };
1416
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-asset-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
1417
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
1418
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header-actions", children: [
1419
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-modal-back", onClick: onBack, disabled: busy, "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 3L5 8l5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
1420
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Add custom trustline" })
1421
+ ] }),
1422
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
1423
+ ] }),
1424
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-asset-custom-hint", children: "Custom trustlines aren't sponsored \u2014 your wallet pays the 0.5 XLM reserve and the transaction fee." }),
1425
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-field", children: [
1426
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-label", htmlFor: "pollar-trustline-code", children: "Asset code" }),
1427
+ /* @__PURE__ */ jsxRuntime.jsx(
1428
+ "input",
1429
+ {
1430
+ id: "pollar-trustline-code",
1431
+ className: "pollar-input",
1432
+ value: code,
1433
+ onChange: (e) => setCode(e.target.value),
1434
+ placeholder: "USDC",
1435
+ maxLength: 12,
1436
+ autoComplete: "off",
1437
+ spellCheck: false,
1438
+ disabled: busy
1439
+ }
1440
+ )
1441
+ ] }),
1442
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-field", children: [
1443
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-label", htmlFor: "pollar-trustline-issuer", children: "Issuer" }),
1444
+ /* @__PURE__ */ jsxRuntime.jsx(
1445
+ "input",
1446
+ {
1447
+ id: "pollar-trustline-issuer",
1448
+ className: "pollar-input",
1449
+ value: issuer,
1450
+ onChange: (e) => setIssuer(e.target.value),
1451
+ placeholder: "G\u2026",
1452
+ autoComplete: "off",
1453
+ spellCheck: false,
1454
+ disabled: busy
1455
+ }
1456
+ ),
1457
+ issuer.trim().length > 0 && !issuerOk && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-field-error", children: "Issuer must be a 56-character Stellar address starting with G." })
1458
+ ] }),
1459
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-field", children: [
1460
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-label", htmlFor: "pollar-trustline-limit", children: [
1461
+ "Limit ",
1462
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-label-optional", children: "(optional)" })
1463
+ ] }),
1464
+ /* @__PURE__ */ jsxRuntime.jsx(
1465
+ "input",
1466
+ {
1467
+ id: "pollar-trustline-limit",
1468
+ className: "pollar-input",
1469
+ value: limit,
1470
+ onChange: (e) => setLimit(e.target.value),
1471
+ placeholder: "Maximum",
1472
+ inputMode: "decimal",
1473
+ autoComplete: "off",
1474
+ spellCheck: false,
1475
+ disabled: busy
1476
+ }
1477
+ )
1478
+ ] }),
1479
+ actionError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-action-error", children: actionError }),
1480
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-asset-submit", onClick: submit, disabled: !canSubmit, children: busy ? "Enabling\u2026" : "Enable trustline" }),
1481
+ /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
1482
+ ] });
1483
+ }
1484
+ function assetKey2(record) {
1485
+ return record.code + (record.issuer ?? "");
1486
+ }
1349
1487
  function EnabledAssetsModal({ onClose }) {
1350
- const { enabledAssets, refreshAssets, walletAddress, styles } = usePollar();
1488
+ const { enabledAssets, refreshAssets, setTrustline, walletAddress, styles } = usePollar();
1351
1489
  const { theme = "light", accentColor = "#005DB4" } = styles;
1490
+ const [view, setView] = react.useState("list");
1491
+ const [busyKey, setBusyKey] = react.useState(null);
1492
+ const [actionError, setActionError] = react.useState(null);
1352
1493
  react.useEffect(() => {
1353
1494
  void refreshAssets();
1354
1495
  }, [refreshAssets]);
1355
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
1496
+ const runAction = react.useCallback(
1497
+ async (key, asset, opts) => {
1498
+ setBusyKey(key);
1499
+ setActionError(null);
1500
+ const res = await setTrustline(asset, opts);
1501
+ if (res.status === "error") {
1502
+ setActionError(res.details || "Trustline update failed. Please try again.");
1503
+ setBusyKey(null);
1504
+ return false;
1505
+ }
1506
+ await refreshAssets();
1507
+ setBusyKey(null);
1508
+ return true;
1509
+ },
1510
+ [setTrustline, refreshAssets]
1511
+ );
1512
+ const handleToggle = react.useCallback(
1513
+ (record) => {
1514
+ const removing = record.trustlineEstablished;
1515
+ void runAction(
1516
+ assetKey2(record),
1517
+ { code: record.code, issuer: record.issuer ?? "" },
1518
+ { ...removing ? { limit: "0" } : {}, sponsored: record.sponsored ?? false }
1519
+ );
1520
+ },
1521
+ [runAction]
1522
+ );
1523
+ const handleCustomSubmit = react.useCallback(
1524
+ async (input) => {
1525
+ const ok = await runAction(
1526
+ "custom",
1527
+ { code: input.code, issuer: input.issuer },
1528
+ { ...input.limit ? { limit: input.limit } : {}, sponsored: false }
1529
+ );
1530
+ if (ok) setView("list");
1531
+ },
1532
+ [runAction]
1533
+ );
1534
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: onClose, children: view === "list" ? /* @__PURE__ */ jsxRuntime.jsx(
1356
1535
  EnabledAssetsModalTemplate,
1357
1536
  {
1358
1537
  theme,
1359
1538
  accentColor,
1360
1539
  enabledAssets,
1361
1540
  walletAddress,
1541
+ busyKey,
1542
+ actionError,
1362
1543
  onRefresh: () => refreshAssets(),
1363
- onClose
1544
+ onClose,
1545
+ onToggleTrustline: handleToggle,
1546
+ onAddCustom: () => {
1547
+ setActionError(null);
1548
+ setView("custom");
1549
+ }
1550
+ }
1551
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1552
+ CustomTrustlineModalTemplate,
1553
+ {
1554
+ theme,
1555
+ accentColor,
1556
+ busy: busyKey === "custom",
1557
+ actionError,
1558
+ onBack: () => {
1559
+ setActionError(null);
1560
+ setView("list");
1561
+ },
1562
+ onClose,
1563
+ onSubmit: handleCustomSubmit
1364
1564
  }
1365
1565
  ) });
1366
1566
  }
@@ -1713,7 +1913,8 @@ function LoginModalTemplate({
1713
1913
  onEmailSubmit,
1714
1914
  onSocialLogin,
1715
1915
  onWalletConnect,
1716
- onSmartWallet,
1916
+ onLoginSmartWallet,
1917
+ onCreateSmartWallet,
1717
1918
  renderWallets,
1718
1919
  authState,
1719
1920
  codeInputKey,
@@ -1723,6 +1924,7 @@ function LoginModalTemplate({
1723
1924
  onRetry
1724
1925
  }) {
1725
1926
  const [showWalletPicker, setShowWalletPicker] = react.useState(false);
1927
+ const [showPasskeyChooser, setShowPasskeyChooser] = react.useState(false);
1726
1928
  const isDark = theme === "dark";
1727
1929
  const enabledSocial = Object.entries(providers).filter(([, enabled]) => enabled);
1728
1930
  const cssVars = {
@@ -1793,6 +1995,31 @@ function LoginModalTemplate({
1793
1995
  renderWallets ? renderWallets({ onConnect: onWalletConnect ?? (() => {
1794
1996
  }), authState }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultFreighterAlbedoButtons, { onConnect: onWalletConnect ?? (() => {
1795
1997
  }), isLoading })
1998
+ ] }) : showPasskeyChooser ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1999
+ /* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: () => setShowPasskeyChooser(false) }),
2000
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-section", children: [
2001
+ /* @__PURE__ */ jsxRuntime.jsx(
2002
+ "button",
2003
+ {
2004
+ type: "button",
2005
+ disabled: isLoading,
2006
+ className: "pollar-btn-primary",
2007
+ style: { width: "100%" },
2008
+ onClick: onCreateSmartWallet,
2009
+ children: "Create a new wallet"
2010
+ }
2011
+ ),
2012
+ /* @__PURE__ */ jsxRuntime.jsx(
2013
+ "button",
2014
+ {
2015
+ type: "button",
2016
+ disabled: isLoading,
2017
+ className: "pollar-wallet-entry-btn",
2018
+ onClick: onLoginSmartWallet,
2019
+ children: "Log in with an existing wallet"
2020
+ }
2021
+ )
2022
+ ] })
1796
2023
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1797
2024
  emailEnabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-email-section", children: [
1798
2025
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1860,7 +2087,7 @@ function LoginModalTemplate({
1860
2087
  type: "button",
1861
2088
  disabled: isLoading,
1862
2089
  className: "pollar-wallet-entry-btn",
1863
- onClick: onSmartWallet,
2090
+ onClick: () => setShowPasskeyChooser(true),
1864
2091
  children: [
1865
2092
  /* @__PURE__ */ jsxRuntime.jsx(
1866
2093
  "svg",
@@ -1914,6 +2141,9 @@ function LoginModal({ onClose }) {
1914
2141
  setCodeInputKey((k) => k + 1);
1915
2142
  }
1916
2143
  if (next.step === "authenticated") {
2144
+ if (autoCloseTimer.current !== null) {
2145
+ clearTimeout(autoCloseTimer.current);
2146
+ }
1917
2147
  autoCloseTimer.current = setTimeout(() => {
1918
2148
  autoCloseTimer.current = null;
1919
2149
  onCloseRef.current();
@@ -1928,8 +2158,8 @@ function LoginModal({ onClose }) {
1928
2158
  }
1929
2159
  };
1930
2160
  }, [getClient]);
1931
- const { theme = "light", accentColor = "#005DB4", logoUrl, emailEnabled, embeddedWallets, providers } = styles;
1932
- const smartWallet = styles.smartWallet ?? true;
2161
+ const { theme = "light", accentColor = "#005DB4", logoUrl, emailEnabled, embeddedWallets, smartWallet, providers } = styles;
2162
+ const smartWalletEnabled = smartWallet ?? false;
1933
2163
  function handleClose() {
1934
2164
  setEmail("");
1935
2165
  getClient().cancelLogin();
@@ -1946,9 +2176,12 @@ function LoginModal({ onClose }) {
1946
2176
  function handleWalletConnect(type) {
1947
2177
  getClient().loginWallet(type);
1948
2178
  }
1949
- function handleSmartWallet() {
2179
+ function handleLoginSmartWallet() {
1950
2180
  getClient().loginSmartWallet();
1951
2181
  }
2182
+ function handleCreateSmartWallet() {
2183
+ getClient().createSmartWallet();
2184
+ }
1952
2185
  function handleVerifyCode(code) {
1953
2186
  getClient().verifyEmailCode(code);
1954
2187
  }
@@ -1970,7 +2203,7 @@ function LoginModal({ onClose }) {
1970
2203
  logoUrl: logoUrl ?? null,
1971
2204
  emailEnabled: !!emailEnabled,
1972
2205
  embeddedWallets: !!embeddedWallets,
1973
- smartWallet,
2206
+ smartWallet: smartWalletEnabled,
1974
2207
  providers: {
1975
2208
  google: !!providers?.google,
1976
2209
  discord: !!providers?.discord,
@@ -1984,7 +2217,8 @@ function LoginModal({ onClose }) {
1984
2217
  onEmailSubmit: handleEmailSubmit,
1985
2218
  onSocialLogin: handleSocialLogin,
1986
2219
  onWalletConnect: handleWalletConnect,
1987
- onSmartWallet: handleSmartWallet,
2220
+ onLoginSmartWallet: handleLoginSmartWallet,
2221
+ onCreateSmartWallet: handleCreateSmartWallet,
1988
2222
  ...renderWallets !== void 0 && { renderWallets },
1989
2223
  authState,
1990
2224
  codeInputKey,
@@ -2747,7 +2981,7 @@ function formatBalance(balance) {
2747
2981
  const n = parseFloat(balance);
2748
2982
  return isNaN(n) ? balance : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
2749
2983
  }
2750
- function assetKey(record) {
2984
+ function assetKey3(record) {
2751
2985
  return `${record.code}:${record.issuer ?? "native"}`;
2752
2986
  }
2753
2987
  function SendModalTemplate({
@@ -2800,7 +3034,7 @@ function SendModalTemplate({
2800
3034
  };
2801
3035
  const enabledAssets = assets.filter((a) => a.enabledInApp);
2802
3036
  const otherAssets = assets.filter((a) => !a.enabledInApp);
2803
- const selectedKey = selectedAsset ? assetKey(selectedAsset) : "";
3037
+ const selectedKey = selectedAsset ? assetKey3(selectedAsset) : "";
2804
3038
  const canSubmit = !!selectedAsset && !!amount && !!destination.trim() && !isLoadingBalance;
2805
3039
  const title = step === "form" ? "Send" : txTitle;
2806
3040
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2828,23 +3062,23 @@ function SendModalTemplate({
2828
3062
  value: selectedKey,
2829
3063
  onChange: (e) => {
2830
3064
  const all = [...enabledAssets, ...otherAssets];
2831
- const found = all.find((a) => assetKey(a) === e.target.value);
3065
+ const found = all.find((a) => assetKey3(a) === e.target.value);
2832
3066
  if (found) onSelectAsset(found);
2833
3067
  },
2834
3068
  children: [
2835
3069
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select asset" }),
2836
- enabledAssets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: "App assets", children: enabledAssets.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: assetKey(a), children: [
3070
+ enabledAssets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: "App assets", children: enabledAssets.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: assetKey3(a), children: [
2837
3071
  a.code,
2838
3072
  " \u2014 ",
2839
3073
  formatBalance(a.available),
2840
3074
  " available"
2841
- ] }, assetKey(a))) }),
2842
- otherAssets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: "Other assets", children: otherAssets.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: assetKey(a), children: [
3075
+ ] }, assetKey3(a))) }),
3076
+ otherAssets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: "Other assets", children: otherAssets.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: assetKey3(a), children: [
2843
3077
  a.code,
2844
3078
  " \u2014 ",
2845
3079
  formatBalance(a.available),
2846
3080
  " available"
2847
- ] }, assetKey(a))) })
3081
+ ] }, assetKey3(a))) })
2848
3082
  ]
2849
3083
  }
2850
3084
  )
@@ -3686,14 +3920,13 @@ function randomUserId() {
3686
3920
  for (const b of bytes) bin += String.fromCharCode(b);
3687
3921
  return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
3688
3922
  }
3689
- var browserPasskeyCeremony = async ({ challenge }) => {
3923
+ var browserPasskeyCeremony = async ({ challenge, mode }) => {
3690
3924
  const rpId = window.location.hostname;
3691
- try {
3925
+ if (mode === "login") {
3692
3926
  const response2 = await browser.startAuthentication({
3693
3927
  optionsJSON: { challenge, rpId, userVerification: "required" }
3694
3928
  });
3695
3929
  return { kind: "login", response: response2 };
3696
- } catch {
3697
3930
  }
3698
3931
  const userId = randomUserId();
3699
3932
  const response = await browser.startRegistration({
@@ -3857,6 +4090,7 @@ function PollarProvider({
3857
4090
  // enabled assets
3858
4091
  enabledAssets,
3859
4092
  refreshAssets,
4093
+ setTrustline: (asset, opts) => pollarClient.setTrustline(asset, opts),
3860
4094
  openEnabledAssetsModal: () => setEnabledAssetsModalOpen(true),
3861
4095
  // send / receive
3862
4096
  openSendModal: () => setSendModalOpen(true),