@moonbase.sh/storefront 3.5.0 → 3.6.1

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
@@ -169,6 +169,8 @@ five groups per request are applied, and IDs are matched lowercase.
169
169
 
170
170
  The two are unioned rather than overridden: `configure` names the lists everyone
171
171
  signing up through your site joins, the link adds whichever the campaign is for.
172
+ A [sign-up form on your own page](#newsletter-sign-up-forms) adds to `subscribe` the
173
+ same way, with a field named `groups`.
172
174
  `checkout` is configuration-only, because the cart outlives any one link.
173
175
 
174
176
  For somebody who already has an account, `join_group` does it as a request of its
@@ -341,6 +343,106 @@ To render sales entirely yourself, turn the built-in surfaces off and listen for
341
343
  `promotion-shown`, or read them from the `usePromotions()` composable in
342
344
  `@moonbase.sh/vue`.
343
345
 
346
+ ## Newsletter sign-up forms
347
+
348
+ A sign-up form on your own page, in your own design, can go straight to Moonbase. Mark it
349
+ with `data-moonbase-form="subscribe"` and the widget sends it in the background instead of
350
+ letting the browser load a new page:
351
+
352
+ ```html
353
+ <form data-moonbase-form="subscribe">
354
+ <input name="name" placeholder="Name" maxlength="200">
355
+ <input name="email" type="email" placeholder="you@example.com" required>
356
+ <button>Subscribe</button>
357
+ </form>
358
+ ```
359
+
360
+ The widget reads the fields by name:
361
+
362
+ | Field | |
363
+ | --- | --- |
364
+ | `email` | Required. |
365
+ | `name` | Optional, up to 200 characters. |
366
+ | `groups` | Optional group IDs, comma-separated in one field or repeated (checkboxes, say). Added to `groups.subscribe`, as `mb_groups` is on a link. |
367
+
368
+ The emails signed up for are the ones `communicationPreferences.show` names, as for the
369
+ drawer's own subscribe form, and whether the visitor has to confirm by email first is your
370
+ account's double opt-in setting. The form is yours, so the consent wording is too: the drawer's
371
+ form says "By subscribing you agree to receive newsletter and product update emails", and
372
+ yours should say as much.
373
+
374
+ ### Showing the result
375
+
376
+ By default the drawer opens on the outcome: "You're subscribed!", or "Check your email to
377
+ finish" under double opt-in. If the server turns the email down, the drawer opens its own form,
378
+ filled in from yours, with the reason under the button, so the visitor can correct it there.
379
+
380
+ To keep everything on your page, add `data-moonbase-feedback="inline"`. The drawer then stays
381
+ closed, and the widget reports progress on the form itself for you to style:
382
+
383
+ ```html
384
+ <form class="newsletter" data-moonbase-form="subscribe" data-moonbase-feedback="inline">
385
+ <div class="fields">
386
+ <input name="email" type="email" required>
387
+ <button>Subscribe</button>
388
+ </div>
389
+ <p data-moonbase-message></p>
390
+ </form>
391
+ ```
392
+
393
+ | `data-moonbase-state` | When |
394
+ | --- | --- |
395
+ | `submitting` | The request is out. The form's submit buttons are disabled until it returns. |
396
+ | `subscribed` | The visitor is on the list. |
397
+ | `confirmation_sent` | Double opt-in: a confirmation email went out, and the visitor is on the list once they click it. |
398
+ | `error` | The server turned the email down, or the request failed. |
399
+
400
+ A `[data-moonbase-message]` element inside the form gets the outcome as text, worded as the
401
+ drawer words it, and is made a live region so screen readers announce it. Leave it out to show
402
+ your own wording instead:
403
+
404
+ ```css
405
+ .newsletter:is([data-moonbase-state="subscribed"], [data-moonbase-state="confirmation_sent"]) .fields {
406
+ display: none;
407
+ }
408
+ .newsletter[data-moonbase-state="error"] [data-moonbase-message] {
409
+ color: #c00;
410
+ }
411
+ ```
412
+
413
+ Style both success states. For a visitor who is not signed in, the status follows your double
414
+ opt-in setting rather than whether the address was new, so the form cannot be used to find out
415
+ who is subscribed already. With double opt-in on, nearly every sign-up ends in
416
+ `confirmation_sent`.
417
+
418
+ `data-moonbase-state` is set in the default mode as well, so a spinner can cover the moment
419
+ before the drawer opens.
420
+
421
+ ### Reacting in code
422
+
423
+ Every successful sign-up emits `subscribed`, from these forms and from the drawer's own:
424
+
425
+ ```ts
426
+ Moonbase.on(MoonbaseEvent.Subscribed, ({ email, status, source }) => {
427
+ // source is 'form' for a data-moonbase-form form, 'drawer' for the drawer's own
428
+ })
429
+ ```
430
+
431
+ ### Good to know
432
+
433
+ - The attribute hands the form to Moonbase: the widget claims the submit before any other
434
+ script on the page sees it, so a site builder's own form handling does not post it somewhere
435
+ else as well. Your own submit listeners on that form do not run either; use the `subscribed`
436
+ event instead.
437
+ - Loaded from the CDN, the widget holds a form submitted before it is ready and sends it once
438
+ `setup()` has run. Installed from npm, call `setup()` early: until then the browser submits
439
+ the form as a plain form.
440
+ - A signed-in customer subscribes the address they type in, which is usually their own.
441
+ - Forms inside a shadow root are not picked up.
442
+ - An unknown `data-moonbase-form` value is not submitted, and logs a warning to the console.
443
+ - To open the drawer's own form instead, filled in, call `Moonbase.subscribe({ email, name })`
444
+ or link to `?mb_intent=subscribe&mb_email=...&mb_name=...`.
445
+
344
446
  ## Events
345
447
 
346
448
  Subscribe to widget lifecycle events with `Moonbase.on(...)`.
@@ -350,6 +452,7 @@ Available events include:
350
452
  - `signed-in`
351
453
  - `signed-up`
352
454
  - `signed-out`
455
+ - `subscribed`
353
456
  - `storefront-updated`
354
457
  - `promotion-shown`
355
458
  - `promotion-clicked`
@@ -12,6 +12,7 @@ import { OwnedProduct } from '@moonbase.sh/vue';
12
12
  import { Storefront } from '@moonbase.sh/vue';
13
13
  import { StorefrontProduct } from '@moonbase.sh/vue';
14
14
  import { StorefrontPromotion } from '@moonbase.sh/vue';
15
+ import { SubscribeResponse } from '@moonbase.sh/vue';
15
16
  import { TrailingZeros } from '@moonbase.sh/vue';
16
17
  import { User } from '@moonbase.sh/vue';
17
18
  import { Voucher } from '@moonbase.sh/vue';
@@ -75,6 +76,7 @@ export declare enum MoonbaseEvent {
75
76
  SignedIn = "signed-in",
76
77
  SignedUp = "signed-up",
77
78
  SignedOut = "signed-out",
79
+ Subscribed = "subscribed",
78
80
  RedeemedVoucher = "redeemed-voucher",
79
81
  JoinedGroup = "joined-group",
80
82
  StorefrontUpdated = "storefront-updated",
@@ -100,6 +102,23 @@ export declare interface MoonbaseEventArgs {
100
102
  [MoonbaseEvent.SignedOut]: {
101
103
  user: User;
102
104
  };
105
+ [MoonbaseEvent.Subscribed]: {
106
+ email: string;
107
+ name: string | null;
108
+ /**
109
+ * `confirmation_sent` when the account requires double opt-in: the visitor
110
+ * is only on the list once they click the link in the email that went out.
111
+ */
112
+ status: SubscribeResponse['status'];
113
+ /**
114
+ * The group IDs requested, normalized. Not necessarily the ones applied: the
115
+ * API skips unknown groups and groups closed to sign-ups without a word.
116
+ */
117
+ groupIds?: string[];
118
+ /** The drawer's own form, or a `data-moonbase-form` form on the host page. */
119
+ source: 'drawer' | 'form';
120
+ user?: User | null;
121
+ };
103
122
  [MoonbaseEvent.RedeemedVoucher]: {
104
123
  voucher: Voucher;
105
124
  user: User;
@@ -284,6 +303,8 @@ export declare interface MoonbaseIntentArgs {
284
303
  };
285
304
  [MoonbaseIntent.Subscribe]: {
286
305
  email?: string;
306
+ /** Prefills the name field. */
307
+ name?: string;
287
308
  /**
288
309
  * Comma-separated merchant-owned group IDs to join on subscribe, added to
289
310
  * whatever `options.groups.subscribe` already names.
@@ -393,7 +414,8 @@ export declare interface MoonbaseOptions {
393
414
  * `signUp` and `subscribe` can be added to per link with `mb_groups`, e.g.
394
415
  * `?mb_intent=sign_up&mb_groups=beta,vip`. The two are unioned: the options
395
416
  * say which lists everyone signing up through this site joins, the link adds
396
- * whichever the campaign is for.
417
+ * whichever the campaign is for. A host-page `data-moonbase-form="subscribe"`
418
+ * form adds to `subscribe` the same way, with a field named `groups`.
397
419
  *
398
420
  * `checkout` is options-only. The cart outlives any one intent, and a buyer
399
421
  * pressing the drawer's own checkout button never went through a link, so a