@moonbase.sh/storefront 3.12.0 → 3.14.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/README.md CHANGED
@@ -68,15 +68,18 @@ Hosts that ship a fixed-width legacy mobile viewport (for example Wix's classic
68
68
 
69
69
  ### Captchas
70
70
 
71
- A merchant can ask customers to solve a captcha before they sign up. With that turned on, the
72
- widget's sign-up form shows one, drawn in a frame from the store's own
73
- `https://<account-id>.moonbase.sh`. A site with a Content-Security-Policy only has to allow that
74
- address in `frame-src`, which it already needs for the checkout overlay, and nothing for the
75
- captcha provider itself.
71
+ A merchant can ask customers to solve a captcha before they sign up or subscribe to the
72
+ newsletter. With that turned on, the widget's sign-up and subscribe forms show one, drawn in a
73
+ frame from the store's own `https://<account-id>.moonbase.sh`. A site with a
74
+ Content-Security-Policy only has to allow that address in `frame-src`, which it already needs for
75
+ the checkout overlay, and nothing for the captcha provider itself. A newsletter form of your own
76
+ cannot hold the frame, so the widget draws it in the drawer instead (see
77
+ [On a store that asks for a captcha](#on-a-store-that-asks-for-a-captcha)).
76
78
 
77
79
  Widget versions from before captchas (3.7 and earlier) cannot show one, so while captchas are on,
78
- signing up from a site pinned to one of those fails. Checkout is unaffected by the widget version:
79
- it runs in Moonbase's own checkout, which shows its own captcha.
80
+ signing up from a site pinned to one of those fails. The same goes for newsletter sign-ups from a
81
+ site pinned to 3.12 or earlier, which predate the captcha on them. Checkout is unaffected by the
82
+ widget version: it runs in Moonbase's own checkout, which shows its own captcha.
80
83
 
81
84
  ## Trigger intents
82
85
 
@@ -152,6 +155,35 @@ A redirected buyer is always brought back to your page once they've paid, so
152
155
  The hosted checkout stays anonymous for the trip — it prefills from the order rather
153
156
  than signing the buyer into a Moonbase account, matching the overlay's behavior.
154
157
 
158
+ `checkout.backdrop` sets what the overlay draws behind the checkout:
159
+
160
+ ```ts
161
+ Moonbase.configure({
162
+ checkout: {
163
+ backdrop: { color: 'brand', opacity: 'strong', blur: true },
164
+ },
165
+ })
166
+ ```
167
+
168
+ | Part | Values |
169
+ | --- | --- |
170
+ | `color` | `'dark'`, `'light'`, or `'brand'`, a dark shade of your brand color. |
171
+ | `opacity` | `'subtle'`, `'standard'` or `'strong'`: how much of your page it covers. |
172
+ | `blur` | `true` blurs your page behind the checkout. |
173
+
174
+ Leave the option out, or any part of it, and that part follows the theme in your
175
+ Moonbase account, which draws a dark backdrop at standard opacity with no blur until
176
+ you change it there. A later `configure` changes only the parts it names; pass
177
+ `backdrop: null` to hand all of it back to the account's theme.
178
+
179
+ The blur happens on your page itself. The checkout runs in a frame of its own and can't
180
+ reach outside it, so the widget blurs the page behind the frame and clears it again as
181
+ the checkout closes. The loading state shown while the checkout opens draws the same
182
+ backdrop, taking `'brand'` from the 900 shade of `theme.colors.primary`.
183
+
184
+ The popup for updating a subscription's payment method draws the same color and opacity,
185
+ but never blurs your page.
186
+
155
187
  ### Customer groups
156
188
 
157
189
  If you keep customer lists in Moonbase and have opened one to public sign-ups,
@@ -208,7 +240,7 @@ success. Joining a list twice is not an error.
208
240
  | `{ family, stylesheet }` | The stylesheet you name, from wherever you host it. |
209
241
 
210
242
  The built-in families are `Inter`, `Roboto`, `EB Garamond`, `Merriweather`, `Poppins`,
211
- `PT Serif`, `Montserrat` and `Aleo`. Either slot accepts any of them.
243
+ `PT Serif`, `Montserrat`, `Aleo` and `Space Mono`. Either slot accepts any of them.
212
244
 
213
245
  They are served from Moonbase's own asset host — the same origin that serves the widget
214
246
  itself, and the same payload the hosted checkout uses, so the two share a cache entry.
@@ -333,6 +365,96 @@ you pass replaces the previous one; pass `{}` to remove it. No minimum by defaul
333
365
 
334
366
  You can also control where the widget mounts by providing `target`.
335
367
 
368
+ ### Typography, spacing and buttons
369
+
370
+ A few more `theme` options tune how the widget reads. Each takes one of a fixed set of
371
+ values, and the first of each is the default, which is how the widget has always looked:
372
+
373
+ | Option | Values | What it does |
374
+ | --- | --- | --- |
375
+ | `headingWeight` | `'standard'`, `'light'`, `'regular'`, `'medium'`, `'semibold'`, `'bold'`, `'extrabold'` | One weight for every heading, from 300 to 800. `'standard'` keeps each heading's own. |
376
+ | `bodyWeight` | `'regular'`, `'light'` | Running text at 400 or at 300. Bold text stays bold. |
377
+ | `headingLetterSpacing` | `'standard'`, `'tight'`, `'wide'` | Letter spacing for headings only, `-0.02em` or `0.04em`. |
378
+ | `spacing` | `'standard'`, `'compact'`, `'relaxed'` | The room around and between blocks in the drawer, at 0.75 or 1.25 times the standard. |
379
+ | `buttonLabels` | `'normal'`, `'uppercase'` | Button labels in capitals, a size smaller and spaced out. |
380
+ | `colors.button` | `{ background, text, hover? }` | The fill, label and hover of primary buttons, as CSS colors. |
381
+
382
+ ```ts
383
+ Moonbase.configure({
384
+ theme: {
385
+ headingWeight: 'semibold',
386
+ spacing: 'relaxed',
387
+ buttonLabels: 'uppercase',
388
+ colors: {
389
+ button: { background: '#E5A000', text: '#000000' },
390
+ },
391
+ },
392
+ })
393
+ ```
394
+
395
+ `spacing` never reaches inside a control: buttons and fields keep their height, and icons
396
+ and text keep their size. `'relaxed'` only applies from 640px wide, so a phone keeps its
397
+ width. Uppercase labels keep the button's height too, and subtle buttons, which read as
398
+ links, keep their case.
399
+
400
+ Without `colors.button`, primary buttons are drawn from `colors.primary` as before. Leave
401
+ out `hover` and the widget works one out, moving the fill a tenth of the way towards white
402
+ under a dark label or towards black under a light one, so the label never loses contrast.
403
+ A `colors.button` you pass replaces the previous one as a whole, so give `background` and
404
+ `text` together; pass `null` to go back to `colors.primary`.
405
+
406
+ ### Match your Moonbase theme
407
+
408
+ The theme in your Moonbase account styles the hosted storefront and the checkout. The
409
+ widget is styled from your own code instead, so to make it match, open Account settings >
410
+ Storefront > Theme in Moonbase and copy the ready-made `Moonbase.configure` snippet under
411
+ "Match your storefront widget". It is generated from your account's theme, and looks
412
+ like this:
413
+
414
+ ```js
415
+ Moonbase.configure({
416
+ theme: {
417
+ colors: {
418
+ primary: { 50: '#EEF2FF', 100: '#E0E7FF', /* ... */ 900: '#312E81' },
419
+ button: { background: '#4F46E5', text: '#FFFFFF', hover: '#4338CA' },
420
+ },
421
+ fonts: { heading: 'Montserrat', body: 'Inter' },
422
+ corners: 'soft',
423
+ buttons: 'light',
424
+ cards: 'outlined',
425
+ buttonLabels: 'normal',
426
+ headingWeight: 'standard',
427
+ bodyWeight: 'regular',
428
+ headingLetterSpacing: 'standard',
429
+ spacing: 'standard',
430
+ },
431
+ checkout: {
432
+ backdrop: { color: 'dark', opacity: 'standard', blur: false },
433
+ },
434
+ })
435
+ ```
436
+
437
+ Paste it as is, or keep only the parts you want. Each theme setting maps onto one widget
438
+ option:
439
+
440
+ | Theme setting | Widget option |
441
+ | --- | --- |
442
+ | Brand color, as its shades | `theme.colors.primary` |
443
+ | Brand and contrast color, as checkout draws primary buttons | `theme.colors.button` |
444
+ | Heading font, body font | `theme.fonts.heading`, `theme.fonts.body` |
445
+ | Corner style | `theme.corners` |
446
+ | Button style | `theme.buttons` |
447
+ | Button labels | `theme.buttonLabels` |
448
+ | Heading weight | `theme.headingWeight` |
449
+ | Body weight | `theme.bodyWeight` |
450
+ | Heading letter spacing | `theme.headingLetterSpacing` |
451
+ | Spacing | `theme.spacing` |
452
+ | Overlay checkout backdrop | `checkout.backdrop` |
453
+
454
+ Change the theme later and the snippet changes with it, so copy it again. The snippet
455
+ spells out the backdrop too, which the overlay checkout then keeps over the account's
456
+ theme; leave `checkout.backdrop` out if you would rather it followed the theme on its own.
457
+
336
458
  ## Promotions
337
459
 
338
460
  When you run a sale across your catalogue, the widget surfaces it on its own — as a
@@ -426,10 +548,10 @@ closed, and the widget reports progress on the form itself for you to style:
426
548
 
427
549
  | `data-moonbase-state` | When |
428
550
  | --- | --- |
429
- | `submitting` | The request is out. The form's submit buttons are disabled until it returns. |
551
+ | `submitting` | The request is out. The form's submit buttons are disabled until it returns, and on a store that asks for a captcha until the visitor has solved it. |
430
552
  | `subscribed` | The visitor is on the list. |
431
553
  | `confirmation_sent` | Double opt-in: a confirmation email went out, and the visitor is on the list once they click it. |
432
- | `error` | The server turned the email down, or the request failed. |
554
+ | `error` | The server turned the email down, the request failed, or the visitor closed the captcha unsolved. |
433
555
 
434
556
  A `[data-moonbase-message]` element inside the form gets the outcome as text, worded as the
435
557
  drawer words it, and is made a live region so screen readers announce it. Leave it out to show
@@ -452,6 +574,18 @@ who is subscribed already. With double opt-in on, nearly every sign-up ends in
452
574
  `data-moonbase-state` is set in the default mode as well, so a spinner can cover the moment
453
575
  before the drawer opens.
454
576
 
577
+ ### On a store that asks for a captcha
578
+
579
+ With the captcha on, the store refuses a newsletter sign-up until the visitor has solved it, and
580
+ your form has no room for the challenge. So the drawer opens with the challenge alone, "Confirm
581
+ you're not a robot to finish subscribing", in either mode. It usually solves itself within a
582
+ second or two. Once it is solved, the widget sends the form again: the drawer then shows the
583
+ outcome, or with `data-moonbase-feedback="inline"` closes, and the outcome goes on your form as
584
+ above.
585
+
586
+ If the visitor closes the drawer without solving it, nothing is sent, and the form ends in
587
+ `error` with "Please confirm you're not a robot." Sending it again opens the challenge again.
588
+
455
589
  ### Reacting in code
456
590
 
457
591
  Every successful sign-up emits `subscribed`, from these forms and from the drawer's own:
@@ -1,5 +1,7 @@
1
1
  import { ActivationRequestFulfillmentType } from '@moonbase.sh/vue';
2
2
  import { CartItem } from '@moonbase.sh/vue';
3
+ import { CheckoutBackdropColor } from '@moonbase.sh/vue';
4
+ import { CheckoutBackdropOpacity } from '@moonbase.sh/vue';
3
5
  import { CheckoutPaymentFailure } from '@moonbase.sh/vue';
4
6
  import { CheckoutRedirectMode } from '@moonbase.sh/vue';
5
7
  import { CurrencyDisplay } from '@moonbase.sh/vue';
@@ -55,7 +57,29 @@ declare const Moonbase_2: MoonbaseImpl;
55
57
  export default Moonbase_2;
56
58
 
57
59
  /** Families the widget ships with, served from Moonbase's own asset host. */
58
- export declare type MoonbaseBuiltInFont = 'Inter' | 'Roboto' | 'EB Garamond' | 'Merriweather' | 'Poppins' | 'PT Serif' | 'Montserrat' | 'Aleo';
60
+ export declare type MoonbaseBuiltInFont = 'Inter' | 'Roboto' | 'EB Garamond' | 'Merriweather' | 'Poppins' | 'PT Serif' | 'Montserrat' | 'Aleo' | 'Space Mono';
61
+
62
+ /** Primary button colours, as any CSS colour. */
63
+ export declare interface MoonbaseButtonColors {
64
+ background: string;
65
+ /** The label, on `background`. */
66
+ text: string;
67
+ /**
68
+ * The fill on hover. Left out, it is `background` moved 10% towards white under a dark label, or
69
+ * towards black under a light one, so the label never loses contrast.
70
+ */
71
+ hover?: string;
72
+ }
73
+
74
+ /** What the popup checkout draws behind it. A part left out follows the account's theme in Moonbase. */
75
+ export declare interface MoonbaseCheckoutBackdrop {
76
+ /** `'dark'`, `'light'`, or `'brand'`: a tint of the darkest shade of the brand colour. */
77
+ color?: CheckoutBackdropColor;
78
+ /** How much of the page shows through: `'subtle'` (50% cover), `'standard'` (75%) or `'strong'` (90%). */
79
+ opacity?: CheckoutBackdropOpacity;
80
+ /** Blur the page behind the checkout. */
81
+ blur?: boolean;
82
+ }
59
83
 
60
84
  export declare interface MoonbaseCustomFont {
61
85
  /**
@@ -429,6 +453,13 @@ export declare interface MoonbaseIntentArgs {
429
453
  quantity?: number;
430
454
  offer_id?: string;
431
455
  show_cart?: boolean;
456
+ /**
457
+ * The customer's license this purchase upgrades or renews, for a product whose licenses cover
458
+ * only some releases. Buying it extends that license instead of issuing another, at the price
459
+ * the storefront quotes for that license. Each license is a cart line of its own, always one
460
+ * unit. Products only. Left out, the purchase issues a new license.
461
+ */
462
+ license_id?: string;
432
463
  };
433
464
  [MoonbaseIntent.Purchase]: {
434
465
  product_id?: string;
@@ -436,12 +467,16 @@ export declare interface MoonbaseIntentArgs {
436
467
  variation_id?: string;
437
468
  quantity?: number;
438
469
  coupon_code?: string;
470
+ /** The customer's license this purchase upgrades or renews, always one unit. Products only. */
471
+ license_id?: string;
439
472
  } | {
440
473
  product_id?: string;
441
474
  bundle_id?: string;
442
475
  variation_id?: string;
443
476
  quantity?: number;
444
477
  coupon_code?: string;
478
+ /** The customer's license this purchase upgrades or renews, always one unit. Products only. */
479
+ license_id?: string;
445
480
  }[];
446
481
  [MoonbaseIntent.Checkout]: {
447
482
  complete?: boolean;
@@ -497,6 +532,12 @@ export declare interface MoonbaseOptions {
497
532
  * - `'never'` / `false`: always the overlay, which can't offer Apple Pay or Google Pay.
498
533
  */
499
534
  redirect: boolean | CheckoutRedirectMode;
535
+ /**
536
+ * What the popup checkout draws behind it, e.g. `{ color: 'brand', opacity: 'strong', blur: true }`.
537
+ * Left out, and for any part left out, the account's theme in Moonbase decides. Parts merge one at
538
+ * a time across `configure()` calls; pass `null` to hand all of it back to the theme.
539
+ */
540
+ backdrop?: MoonbaseCheckoutBackdrop | null;
500
541
  };
501
542
  cart: {
502
543
  quantity: 'selectable' | 'single';
@@ -559,6 +600,12 @@ export declare interface MoonbaseOptions {
559
600
  colors: {
560
601
  primary: Record<number, string> | string;
561
602
  background: 'white' | 'gray';
603
+ /**
604
+ * The fill, label and hover of primary buttons, e.g. `{ background: '#E5A000', text: '#000000' }`.
605
+ * Left out, primary buttons are drawn from `primary` as before. Replaced as a whole by each
606
+ * `configure()` that names it; pass `null` to go back to `primary`.
607
+ */
608
+ button?: MoonbaseButtonColors | null;
562
609
  };
563
610
  fonts: {
564
611
  /**
@@ -572,6 +619,27 @@ export declare interface MoonbaseOptions {
572
619
  corners: 'sharp' | 'soft' | 'round';
573
620
  buttons: 'outlined' | 'light';
574
621
  cards: 'outlined' | 'shadow' | 'white';
622
+ /**
623
+ * `'uppercase'` sets button labels in capitals: a size smaller, bold and spaced out, at the same
624
+ * button height. Subtle, link-like buttons keep their case. `'normal'` (default) leaves them as
625
+ * written.
626
+ */
627
+ buttonLabels: 'normal' | 'uppercase';
628
+ /**
629
+ * One weight for every heading: 300, 400, 500, 600, 700 or 800. `'standard'` (default) keeps each
630
+ * heading's own, which differ by level.
631
+ */
632
+ headingWeight: 'standard' | 'light' | 'regular' | 'medium' | 'semibold' | 'bold' | 'extrabold';
633
+ /** `'light'` sets running text at 300 rather than the default `'regular'` 400. Bold text stays bold. */
634
+ bodyWeight: 'regular' | 'light';
635
+ /** Letter spacing for headings: `'tight'` `-0.02em`, `'wide'` `0.04em`. `'standard'` (default) keeps each heading's own. */
636
+ headingLetterSpacing: 'standard' | 'tight' | 'wide';
637
+ /**
638
+ * The room around and between blocks in the drawer: `'compact'` is three quarters of the
639
+ * default, `'relaxed'` a quarter more from 640px wide (and the default below, so a phone keeps its
640
+ * width). Buttons, fields, icons and text keep their size either way.
641
+ */
642
+ spacing: 'standard' | 'compact' | 'relaxed';
575
643
  };
576
644
  pricing: {
577
645
  /** Whole prices: `'auto'` (default) shows `$10`, `'always'` shows `$10.00`. */