@asseteragmbh/wallet-connector 0.2.3 → 0.2.4

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/README.md CHANGED
@@ -211,12 +211,80 @@ While the pop-up is open the partner page shows a dimming overlay (`overlay: tru
211
211
  `overlay: { title, body, focus, cancel, blocked }` to translate the built-in text; `partnerName` only shows up
212
212
  in that text.
213
213
 
214
+ The overlay is plain DOM with inline styles, so it needs no React and no stylesheet, and it never reads your
215
+ page CSS. Give it your colours and radii with `overlay.theme`. A dark host takes the `"dark"` base palette and
216
+ overrides what it needs:
217
+
218
+ ```ts
219
+ await openAsseteraOnboarding({
220
+ walletUrl: "https://wallet.wallet-staging.assetera.com",
221
+ chain: "eip155:80002",
222
+ overlay: {
223
+ title: "Continue in the Assetera Wallet",
224
+ body: "Finish the wallet setup in the Assetera window, then come back here.",
225
+ focus: "Open the wallet window",
226
+ cancel: "Not now",
227
+ theme: { scheme: "dark", surface: "#1d1f27", primary: "#7b61ff", radius: "36px" },
228
+ },
229
+ });
230
+ ```
231
+
232
+ Every `theme` key is optional. `scheme` picks the base palette, `"light"` (today's look, unchanged) or
233
+ `"dark"`; any other key the host passes wins over that palette. So the example above only changes the card
234
+ colour, the focus button colour and the card radius.
235
+
236
+ | Key | Default (light) | Contract |
237
+ | -------------- | -------------------- | -------------------------------------------------- |
238
+ | `scheme` | `"light"` | Base palette, `"light"` or `"dark"`. |
239
+ | `backdrop` | `rgba(15,20,30,0.6)` | The dimming layer, a CSS colour. |
240
+ | `surface` | `#ffffff` | The card background, a CSS colour. |
241
+ | `text` | `#101828` | The title colour, a CSS colour. |
242
+ | `mutedText` | `#475467` | The body text and the Cancel button, a CSS colour. |
243
+ | `primary` | `#101828` | The focus button background, a CSS colour. |
244
+ | `primaryText` | `#ffffff` | The focus button text, a CSS colour. |
245
+ | `border` | `"none"` | The card border, CSS `border` shorthand. |
246
+ | `radius` | `"16px"` | The card corner radius, for example `"36px"`. |
247
+ | `buttonRadius` | `"10px"` | The button corner radius, for example `"9999px"`. |
248
+ | `fontFamily` | `system-ui` stack | The overlay font, CSS `font-family`. |
249
+
250
+ The `"dark"` preset is a neutral card: `surface` `#1b1d24`, white title, `#9aa2b1` body text and a white focus
251
+ button with dark text. Its text keeps WCAG AA contrast on that surface.
252
+
253
+ Each host value is applied to its own CSS property with `style.setProperty`, never concatenated into the style
254
+ text. A value the browser cannot parse is dropped and the rest of the overlay stays as it is. All overlay text
255
+ still goes through `textContent`.
256
+
257
+ ### Rendering your own dialog (`overlay: false` with `onControls`)
258
+
259
+ Set `overlay: false` and pass `onControls` to drive the run from your own dialog. The callback runs once,
260
+ synchronously, right after the pop-up opened, whether or not an overlay is shown:
261
+
262
+ ```ts
263
+ import type { OnboardingControls } from "@asseteragmbh/wallet-connector";
264
+
265
+ let controls: OnboardingControls | undefined;
266
+ const wallet = await openAsseteraOnboarding({
267
+ walletUrl: "https://wallet.wallet-staging.assetera.com",
268
+ chain: "eip155:80002",
269
+ overlay: false,
270
+ onControls: (handles) => {
271
+ controls = handles;
272
+ showMyOwnDialog();
273
+ },
274
+ });
275
+ ```
276
+
277
+ `controls.focus()` brings the pop-up to the front. `controls.cancel()` behaves like the overlay's Cancel
278
+ button: it rejects with `OnboardingError` code `"cancelled"` before the address arrived, and calls `close()`
279
+ after it. Both are safe to call once the run finished.
280
+
214
281
  The promise rejects with an `OnboardingError`; branch on `code`:
215
282
 
216
283
  - `invalid_options`: the chain is not a CAIP-2 EVM id (for example `eip155:80002`) or the wallet URL is invalid.
217
284
  - `popup_blocked`: the browser blocked the pop-up. No overlay is shown; ask the user to allow pop-ups.
218
285
  - `closed`: the pop-up was closed before the wizard finished (or, from `signMessage`, before the signature).
219
- - `cancelled`: the user cancelled in the wizard or in the overlay, or declined the signature.
286
+ - `cancelled`: the user cancelled in the wizard, in the overlay or through `controls.cancel()`, or declined the
287
+ signature.
220
288
  - `refused`: the wallet refused the onboarding.
221
289
  - `failed`: something else went wrong in the wallet (the optional `message` carries the detail).
222
290
 
package/dist/index.cjs CHANGED
@@ -479,6 +479,48 @@ var DEFAULT_LABELS = {
479
479
  cancel: "Cancel",
480
480
  blocked: "Your browser blocked the Assetera Wallet window. Allow pop-ups for this site and try again."
481
481
  };
482
+ var LIGHT_THEME = {
483
+ scheme: "light",
484
+ backdrop: "rgba(15,20,30,0.6)",
485
+ surface: "#ffffff",
486
+ text: "#101828",
487
+ mutedText: "#475467",
488
+ primary: "#101828",
489
+ primaryText: "#ffffff",
490
+ border: "none",
491
+ radius: "16px",
492
+ buttonRadius: "10px",
493
+ fontFamily: "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif"
494
+ };
495
+ var DARK_THEME = {
496
+ scheme: "dark",
497
+ backdrop: "rgba(8,10,14,0.72)",
498
+ surface: "#1b1d24",
499
+ text: "#f7f8fa",
500
+ mutedText: "#9aa2b1",
501
+ primary: "#ffffff",
502
+ primaryText: "#101828",
503
+ border: "1px solid rgba(255,255,255,0.14)",
504
+ radius: "16px",
505
+ buttonRadius: "10px",
506
+ fontFamily: "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif"
507
+ };
508
+ function resolveTheme(theme) {
509
+ const base = theme?.scheme === "dark" ? DARK_THEME : LIGHT_THEME;
510
+ return {
511
+ scheme: base.scheme,
512
+ backdrop: theme?.backdrop ?? base.backdrop,
513
+ surface: theme?.surface ?? base.surface,
514
+ text: theme?.text ?? base.text,
515
+ mutedText: theme?.mutedText ?? base.mutedText,
516
+ primary: theme?.primary ?? base.primary,
517
+ primaryText: theme?.primaryText ?? base.primaryText,
518
+ border: theme?.border ?? base.border,
519
+ radius: theme?.radius ?? base.radius,
520
+ buttonRadius: theme?.buttonRadius ?? base.buttonRadius,
521
+ fontFamily: theme?.fontFamily ?? base.fontFamily
522
+ };
523
+ }
482
524
  function resolveLabels(options) {
483
525
  const overrides = typeof options.overlay === "object" && options.overlay !== null ? options.overlay : {};
484
526
  const partnerName = options.partnerName;
@@ -491,6 +533,10 @@ function resolveLabels(options) {
491
533
  blocked: overrides.blocked ?? DEFAULT_LABELS.blocked
492
534
  };
493
535
  }
536
+ function resolveThemeOption(options) {
537
+ const overlay = typeof options.overlay === "object" && options.overlay !== null ? options.overlay : {};
538
+ return resolveTheme(overlay.theme);
539
+ }
494
540
  function cancelCode(reason) {
495
541
  if (reason === "user") return "cancelled";
496
542
  if (reason === "refused") return "refused";
@@ -504,7 +550,7 @@ function cancelMessage(reason) {
504
550
  function copyAccountNames(accounts) {
505
551
  return accounts.map((account) => ({ address: account.address, name: account.name }));
506
552
  }
507
- function showOverlay(win, labels, handlers) {
553
+ function showOverlay(win, labels, theme, handlers) {
508
554
  const doc = win.document;
509
555
  const root = doc.createElement("div");
510
556
  root.setAttribute("role", "dialog");
@@ -518,40 +564,43 @@ function showOverlay(win, labels, handlers) {
518
564
  "justify-content: center",
519
565
  "padding: 24px",
520
566
  "box-sizing: border-box",
521
- "background: rgba(15,20,30,0.6)",
522
- `z-index: ${OVERLAY_Z_INDEX}`,
523
- "font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif"
567
+ `z-index: ${OVERLAY_Z_INDEX}`
524
568
  ].join("; ");
569
+ root.style.setProperty("background-color", theme.backdrop);
570
+ root.style.setProperty("font-family", theme.fontFamily);
525
571
  const card = doc.createElement("div");
526
572
  card.style.cssText = [
527
573
  "box-sizing: border-box",
528
574
  "width: 100%",
529
575
  "max-width: 420px",
530
- "border-radius: 16px",
531
576
  "padding: 24px",
532
- "background: #ffffff",
533
- "color: #101828",
534
577
  "box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35)"
535
578
  ].join("; ");
579
+ card.style.setProperty("background-color", theme.surface);
580
+ card.style.setProperty("color", theme.text);
581
+ card.style.setProperty("border", theme.border);
582
+ card.style.setProperty("border-radius", theme.radius);
536
583
  const title = doc.createElement("h2");
537
584
  title.textContent = labels.title;
538
585
  title.style.cssText = "margin: 0 0 10px; font-size: 18px; line-height: 1.3; font-weight: 600;";
586
+ title.style.setProperty("color", theme.text);
539
587
  const body = doc.createElement("p");
540
588
  body.textContent = labels.body;
541
- body.style.cssText = "margin: 0 0 20px; font-size: 14px; line-height: 1.5; color: #475467;";
589
+ body.style.cssText = "margin: 0 0 20px; font-size: 14px; line-height: 1.5;";
590
+ body.style.setProperty("color", theme.mutedText);
542
591
  const focus = doc.createElement("button");
543
592
  focus.type = "button";
544
593
  focus.textContent = labels.focus;
545
594
  focus.style.cssText = [
546
595
  "padding: 10px 16px",
547
596
  "border: 0",
548
- "border-radius: 10px",
549
- "background: #101828",
550
- "color: #ffffff",
551
597
  "font: inherit",
552
598
  "font-weight: 600",
553
599
  "cursor: pointer"
554
600
  ].join("; ");
601
+ focus.style.setProperty("background-color", theme.primary);
602
+ focus.style.setProperty("color", theme.primaryText);
603
+ focus.style.setProperty("border-radius", theme.buttonRadius);
555
604
  focus.addEventListener("click", handlers.onFocus);
556
605
  const cancel = doc.createElement("button");
557
606
  cancel.type = "button";
@@ -561,10 +610,11 @@ function showOverlay(win, labels, handlers) {
561
610
  "border: 0",
562
611
  "border-radius: 10px",
563
612
  "background: transparent",
564
- "color: #475467",
565
613
  "font: inherit",
566
614
  "cursor: pointer"
567
615
  ].join("; ");
616
+ cancel.style.setProperty("color", theme.mutedText);
617
+ cancel.style.setProperty("border-radius", theme.buttonRadius);
568
618
  cancel.addEventListener("click", handlers.onCancel);
569
619
  const actions = doc.createElement("div");
570
620
  actions.style.cssText = "display: flex; gap: 8px; align-items: center;";
@@ -599,6 +649,7 @@ function openAsseteraOnboarding(options) {
599
649
  );
600
650
  }
601
651
  const labels = resolveLabels(options);
652
+ const theme = resolveThemeOption(options);
602
653
  const overlayEnabled = options.overlay !== false;
603
654
  const popup = targetWindow.open(
604
655
  onboardUrl(options.walletUrl, targetWindow.location.origin, {
@@ -653,6 +704,16 @@ function openAsseteraOnboarding(options) {
653
704
  activePopup.close();
654
705
  fail(new OnboardingError("cancelled", "The user cancelled the Assetera Wallet onboarding."));
655
706
  }
707
+ const controls = {
708
+ focus() {
709
+ if (finished) return;
710
+ activePopup.focus();
711
+ },
712
+ cancel() {
713
+ if (finished) return;
714
+ cancel();
715
+ }
716
+ };
656
717
  function signMessage(message) {
657
718
  if (finished || activePopup.closed) {
658
719
  return Promise.reject(new OnboardingError("closed", "The Assetera Wallet window was closed."));
@@ -731,11 +792,12 @@ function openAsseteraOnboarding(options) {
731
792
  );
732
793
  }, CLOSE_POLL_MS2);
733
794
  if (overlayEnabled) {
734
- overlay = showOverlay(targetWindow, labels, {
735
- onFocus: () => activePopup.focus(),
736
- onCancel: cancel
795
+ overlay = showOverlay(targetWindow, labels, theme, {
796
+ onFocus: () => controls.focus(),
797
+ onCancel: () => controls.cancel()
737
798
  });
738
799
  }
800
+ options.onControls?.(controls);
739
801
  });
740
802
  }
741
803