@maytes/checkout-button 1.1.1 → 1.2.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/CHANGELOG.md +49 -0
- package/README.md +97 -53
- package/dist/checkout-button.c640180e.js +156 -0
- package/dist/checkout-button.c640180e.js.map +1 -0
- package/dist/checkout-button.cjs +271 -145
- package/dist/checkout-button.cjs.map +1 -1
- package/dist/checkout-button.d.cts +40 -4
- package/dist/checkout-button.d.ts +40 -4
- package/dist/{checkout-button.aed57a66.mjs → checkout-button.d6e444ee.mjs} +271 -145
- package/dist/checkout-button.d6e444ee.mjs.map +1 -0
- package/dist/{checkout-button.2aad12c3.cjs → checkout-button.d7bc9aea.cjs} +271 -145
- package/dist/checkout-button.d7bc9aea.cjs.map +1 -0
- package/dist/checkout-button.element.6c530c24.js +155 -0
- package/dist/checkout-button.element.6c530c24.js.map +1 -0
- package/dist/checkout-button.element.js +155 -0
- package/dist/checkout-button.element.js.map +1 -0
- package/dist/checkout-button.js +19 -14
- package/dist/checkout-button.js.map +1 -1
- package/dist/checkout-button.mjs +271 -145
- package/dist/checkout-button.mjs.map +1 -1
- package/dist/element.cjs +201 -0
- package/dist/element.cjs.map +1 -0
- package/dist/element.d.cts +44 -0
- package/dist/element.d.ts +44 -0
- package/dist/element.mjs +180 -0
- package/dist/element.mjs.map +1 -0
- package/dist/integrity.json +37 -26
- package/dist/react.cjs +139 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +30 -0
- package/dist/react.d.ts +30 -0
- package/dist/react.mjs +117 -0
- package/dist/react.mjs.map +1 -0
- package/docs/guides/angular.md +56 -0
- package/docs/guides/api.md +108 -0
- package/docs/guides/events.md +48 -0
- package/docs/guides/launch-behaviour.md +41 -0
- package/docs/guides/nextjs.md +49 -0
- package/docs/guides/own-button.md +41 -0
- package/docs/guides/quickstart-html.md +31 -0
- package/docs/guides/quickstart-npm.md +34 -0
- package/docs/guides/react.md +88 -0
- package/docs/guides/security-csp.md +32 -0
- package/docs/guides/server.md +76 -0
- package/docs/guides/solid.md +44 -0
- package/docs/guides/stripe-payment-element.md +14 -0
- package/docs/guides/svelte.md +46 -0
- package/docs/guides/troubleshooting.md +17 -0
- package/docs/guides/vue-nuxt.md +64 -0
- package/docs/guides/web-component.md +109 -0
- package/package.json +40 -3
- package/dist/checkout-button.2aad12c3.cjs.map +0 -1
- package/dist/checkout-button.4b780d52.js +0 -151
- package/dist/checkout-button.4b780d52.js.map +0 -1
- package/dist/checkout-button.aed57a66.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#28](https://github.com/kttipay/maytes-checkout-button/pull/28) [`a5c64cd`](https://github.com/kttipay/maytes-checkout-button/commit/a5c64cd13d095296c4c49eb3d9478f437802f9e3) Thanks [@kos-maytes](https://github.com/kos-maytes)! - `renderButton()` accepts `radius` and `height` so the Split with Maytes button can match an express-checkout row (for example 6px corners at 48px next to Apple Pay and Google Pay); a button with a `height` keeps its label on one line. Every `maytes:checkout-*` event now carries `detail.instanceId` and `detail.source` (`'button'` or `'api'`), and each instance exposes `maytes.instanceId`, so pages with several instances can tell their events apart. Existing event fields and the default button are unchanged: without `radius`/`height` the button renders exactly as in 1.1. Events that had no `detail` (`opened`, `closed`) now carry `{ instanceId, source }`. TypeScript code that hand-builds a `MaytesSDK` object needs the new `instanceId` member.
|
|
8
|
+
|
|
9
|
+
- [#30](https://github.com/kttipay/maytes-checkout-button/pull/30) [`ac332b7`](https://github.com/kttipay/maytes-checkout-button/commit/ac332b7bf5d361166484e1b657a1a303e22192ef) Thanks [@kos-maytes](https://github.com/kos-maytes)! - Add `<maytes-checkout-button>`, a standard custom element for any front-end stack (plain HTML, Vue/Nuxt, Angular, Svelte/SvelteKit, Solid, React 19). Import `@maytes/checkout-button/element` or load `https://js.maytes.co/v1/checkout-button.element.js`; set `environment` and the other options as attributes and `createCheckout` as a property, and listen for `maytes-opened`, `maytes-closed`, `maytes-redirected` and `maytes-failed` on the element. `open()` starts the checkout from your own button. Configuration mistakes arrive as `maytes-failed` with `reason: 'config'` instead of throwing. `checkout-button.js`, `.mjs` and `.cjs` are unchanged.
|
|
10
|
+
|
|
11
|
+
- [#26](https://github.com/kttipay/maytes-checkout-button/pull/26) [`92ef8c0`](https://github.com/kttipay/maytes-checkout-button/commit/92ef8c009fb74f7639be7e9cb1b2cd8d90a1c2ee) Thanks [@kos-maytes](https://github.com/kos-maytes)! - Add `openCheckout({ mode })` to start the Maytes checkout from the merchant's own button, with the same popup, loader, overlay, events and fallbacks as the rendered button. It resolves with the launch result (`popup`, `redirected`, `failed`, `closed` or `ignored`) and never rejects.
|
|
12
|
+
|
|
13
|
+
No change for existing integrations: the rendered button looks and behaves exactly as before. TypeScript code that builds its own `MaytesSDK` object (for example a test fake) needs the new `openCheckout` member.
|
|
14
|
+
|
|
15
|
+
- [#29](https://github.com/kttipay/maytes-checkout-button/pull/29) [`c62fa53`](https://github.com/kttipay/maytes-checkout-button/commit/c62fa53eec701d71a84e67240ea86a6167aac4c0) Thanks [@kos-maytes](https://github.com/kos-maytes)! - Add React bindings at `@maytes/checkout-button/react` (`MaytesProvider`, `MaytesButton`, `useMaytes`) and `maytes.onBusyChange()`. React is an optional peer dependency (18 or 19); the CDN bundle is unchanged.
|
|
16
|
+
|
|
17
|
+
- [#36](https://github.com/kttipay/maytes-checkout-button/pull/36) [`59adae5`](https://github.com/kttipay/maytes-checkout-button/commit/59adae5dfdb72eb15f6ab4ad0174b9ac693e593f) Thanks [@kos-maytes](https://github.com/kos-maytes)! - `<MaytesButton>` accepts `redirectOverlay`, like `renderButton()`: with it, a same-tab launch shows the Maytes loading overlay while the checkout is created. Off by default.
|
|
18
|
+
|
|
19
|
+
- [#32](https://github.com/kttipay/maytes-checkout-button/pull/32) [`7634c62`](https://github.com/kttipay/maytes-checkout-button/commit/7634c62e007b56db63502322cd77fa553f7a14b5) Thanks [@kos-maytes](https://github.com/kos-maytes)! - Add an opt-in `redirectOverlay` option to `renderButton()` and `openCheckout()`: when the checkout opens in the same tab (redirect mode, phones, blocked popups), the Maytes loading overlay shows while the checkout is created and clears itself after a back-button return. Off by default, so existing integrations are unchanged.
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- [#21](https://github.com/kttipay/maytes-checkout-button/pull/21) [`e87a44b`](https://github.com/kttipay/maytes-checkout-button/commit/e87a44b9649686048fa1e622831d601b8eeed71c) Thanks [@kos-maytes](https://github.com/kos-maytes)! - Fix the checkout button's busy-state spinner not reappearing after a customer's first checkout attempt on a given rendered button. The button now tracks its current icon (logo or spinner) by direct reference instead of re-querying the DOM by class name, so the spinner swap works correctly on every checkout attempt, not just the first.
|
|
24
|
+
|
|
25
|
+
<!-- @hash-sri-start -->
|
|
26
|
+
|
|
27
|
+
**SRI hashes** (use these in `<script integrity="..." crossorigin="anonymous">`):
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
checkout-button.js sha384-gIQUOEPPO0H+Stb2Ffa40dFxBxGnB40p1+AHttEYor5oZiVKoM+aKagIL3GuNkG1
|
|
31
|
+
checkout-button.mjs sha384-sKFZzp1oSiijC45OFR04FOjFQfgvxawtUp+u/qXvRu5s5ZF8iMSTHaQo5g+VLJ79
|
|
32
|
+
checkout-button.cjs sha384-fkm1nIhsGYEjDw3uc4cjdxui4K8H4HuPnIQ379GP1Y7vtwFC/Dw3M85KopqvjRl1
|
|
33
|
+
checkout-button.element.js sha384-Y3aDrAucY25r7DzSkYJpsjoazd67oBy4WSxbTXBgpaWaT6TOuEOW3PidCw0PeVb9
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**SemVer CDN links** (readable production pins; use with the SRI hashes above):
|
|
37
|
+
|
|
38
|
+
- [checkout-button.js](https://js.maytes.co/v1.2.0/checkout-button.js)
|
|
39
|
+
- [checkout-button.mjs](https://js.maytes.co/v1.2.0/checkout-button.mjs)
|
|
40
|
+
- [checkout-button.cjs](https://js.maytes.co/v1.2.0/checkout-button.cjs)
|
|
41
|
+
- [checkout-button.element.js](https://js.maytes.co/v1.2.0/checkout-button.element.js)
|
|
42
|
+
|
|
43
|
+
**Hashed CDN links** (byte-level production pins; use with the SRI hashes above):
|
|
44
|
+
|
|
45
|
+
- [checkout-button.c640180e.js](https://js.maytes.co/checkout-button.c640180e.js)
|
|
46
|
+
- [checkout-button.d6e444ee.mjs](https://js.maytes.co/checkout-button.d6e444ee.mjs)
|
|
47
|
+
- [checkout-button.d7bc9aea.cjs](https://js.maytes.co/checkout-button.d7bc9aea.cjs)
|
|
48
|
+
- [checkout-button.element.6c530c24.js](https://js.maytes.co/checkout-button.element.6c530c24.js)
|
|
49
|
+
|
|
50
|
+
<!-- @hash-sri-end -->
|
|
3
51
|
## 1.1.1
|
|
4
52
|
|
|
5
53
|
### Patch Changes
|
|
@@ -29,6 +77,7 @@ checkout-button.cjs sha384-oSekYX0Re0jdMsBU6uzxUedTM+Cnl8uF5y0wmZmjUHngtzr8Sdze
|
|
|
29
77
|
- [checkout-button.2aad12c3.cjs](https://js.maytes.co/checkout-button.2aad12c3.cjs)
|
|
30
78
|
|
|
31
79
|
<!-- @hash-sri-end -->
|
|
80
|
+
|
|
32
81
|
## 1.1.0
|
|
33
82
|
|
|
34
83
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -5,54 +5,80 @@
|
|
|
5
5
|
<h1 align="center">@maytes/checkout-button</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
|
|
8
|
+
The <strong>Split with Maytes</strong> button for your checkout page.<br>
|
|
9
|
+
Shoppers pay their share of the order and invite friends to pay theirs.
|
|
9
10
|
</p>
|
|
10
11
|
|
|
11
12
|
<p align="center">
|
|
12
13
|
<a href="https://www.npmjs.com/package/@maytes/checkout-button"><img alt="npm version" src="https://img.shields.io/npm/v/@maytes/checkout-button?color=4A0324&label=npm"></a>
|
|
13
|
-
<a href="https://bundlephobia.com/package/@maytes/checkout-button"><img alt="bundle size" src="https://img.shields.io/bundlephobia/minzip/@maytes/checkout-button?color=FE572A&label=gzip"></a>
|
|
14
14
|
<a href="./CHANGELOG.md"><img alt="provenance" src="https://img.shields.io/badge/npm-provenance-4A0324"></a>
|
|
15
15
|
<a href="./LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-4A0324"></a>
|
|
16
16
|
<a href="https://developers.maytes.co/checkout-button"><img alt="docs" src="https://img.shields.io/badge/docs-developers.maytes.co-FE572A"></a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="#quickstart">Quickstart</a> ·
|
|
21
|
+
<a href="#choose-your-setup">Guides</a> ·
|
|
22
|
+
<a href="#install">Install</a> ·
|
|
23
|
+
<a href="#api">API</a> ·
|
|
24
|
+
<a href="https://developers.maytes.co/checkout-button">Integration guide</a>
|
|
25
|
+
</p>
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
When a shopper clicks the button, it asks your server to create a Maytes checkout and opens it in a popup, or in the same tab on phones. Your server captures the payment when Maytes sends the `checkout.authorized` webhook.
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
## Features
|
|
24
30
|
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
- **CSP-safe
|
|
28
|
-
- **Evergreen CDN
|
|
29
|
-
- **Signed
|
|
31
|
+
- **Any stack.** A `<script>` tag or `import { Maytes }`, with [a guide per stack](#choose-your-setup), React components and a web component.
|
|
32
|
+
- **No dependencies.** ESM and CommonJS builds ship unminified, so your bundler tree-shakes them.
|
|
33
|
+
- **CSP-safe.** No `eval`, `Function` or string timers; every release is scanned.
|
|
34
|
+
- **Evergreen CDN.** `/v1/` always serves the newest `1.x`; [pin a version](#install) with SRI to freeze it.
|
|
35
|
+
- **Signed releases.** Every npm release carries [SLSA](https://slsa.dev) provenance.
|
|
30
36
|
|
|
31
|
-
##
|
|
37
|
+
## Quickstart
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
|
|
39
|
+
```html
|
|
40
|
+
<div id="maytes-button"></div>
|
|
41
|
+
|
|
42
|
+
<script src="https://js.maytes.co/v1/checkout-button.js" crossorigin="anonymous"></script>
|
|
43
|
+
<script>
|
|
44
|
+
const maytes = window.Maytes({
|
|
45
|
+
environment: 'sandbox',
|
|
46
|
+
createCheckout: async () => {
|
|
47
|
+
const res = await fetch('/api/maytes/checkout', { method: 'POST' });
|
|
48
|
+
if (!res.ok) throw new Error('Could not create the Maytes checkout');
|
|
49
|
+
return res.json(); // { checkoutId, checkoutUrl }
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
maytes.renderButton(document.getElementById('maytes-button'), { block: true });
|
|
54
|
+
</script>
|
|
55
|
+
```
|
|
38
56
|
|
|
39
|
-
|
|
57
|
+
Your server creates the checkout behind `POST /api/maytes/checkout`; [Your server](docs/guides/server.md) shows how. Using a framework? Pick it below.
|
|
58
|
+
|
|
59
|
+
<a id="usage"></a>
|
|
60
|
+
|
|
61
|
+
## Choose your setup
|
|
40
62
|
|
|
41
|
-
|
|
63
|
+
- **Frontend:** [HTML](docs/guides/quickstart-html.md) · [npm](docs/guides/quickstart-npm.md) · [React](docs/guides/react.md) · [Next.js](docs/guides/nextjs.md) · [Vue and Nuxt](docs/guides/vue-nuxt.md) · [Angular](docs/guides/angular.md) · [Svelte](docs/guides/svelte.md) · [Solid](docs/guides/solid.md) · [Web component](docs/guides/web-component.md)
|
|
64
|
+
- **Integration:** [Your server](docs/guides/server.md) · [Stripe Payment Element](docs/guides/stripe-payment-element.md) · [Your own button](docs/guides/own-button.md)
|
|
42
65
|
|
|
43
|
-
|
|
66
|
+
## Install
|
|
67
|
+
|
|
68
|
+
| | Evergreen (recommended) | Pinned |
|
|
44
69
|
|---|---|---|
|
|
45
70
|
| **Use when** | Default — always get the newest `1.x` release | You'd rather freeze on a tested build |
|
|
46
71
|
| **Guarantee** | Always current; a bad release reaches you immediately | The bytes you tested are the bytes shipped, forever |
|
|
47
72
|
| **SRI** | Not possible | Yes |
|
|
48
73
|
|
|
49
|
-
### Evergreen (recommended)
|
|
50
|
-
|
|
51
74
|
```html
|
|
52
75
|
<script src="https://js.maytes.co/v1/checkout-button.js"
|
|
53
76
|
crossorigin="anonymous"></script>
|
|
54
77
|
```
|
|
55
78
|
|
|
79
|
+
<details>
|
|
80
|
+
<summary><b>Evergreen: CSP and versions</b></summary>
|
|
81
|
+
|
|
56
82
|
No `integrity` attribute is possible here — the bytes change without notice as new `1.x` releases ship. Trust the origin via CSP instead:
|
|
57
83
|
|
|
58
84
|
```
|
|
@@ -61,19 +87,22 @@ Content-Security-Policy: script-src 'self' https://js.maytes.co;
|
|
|
61
87
|
|
|
62
88
|
`/v1/` tracks the newest `1.x` release only; it won't jump to a future `2.x` (move to `/v2/checkout-button.js` explicitly once that ships). Poll `https://js.maytes.co/integrity.json` if you want to detect changes yourself.
|
|
63
89
|
|
|
64
|
-
|
|
90
|
+
</details>
|
|
91
|
+
|
|
92
|
+
<details>
|
|
93
|
+
<summary><b>Pinned: SemVer or content hash, with SRI</b></summary>
|
|
65
94
|
|
|
66
95
|
For a guarantee instead of convenience — freeze on a tested build, update on your own schedule:
|
|
67
96
|
|
|
68
97
|
<!-- @cdn-example-start -->
|
|
69
98
|
```html
|
|
70
|
-
<script src="https://js.maytes.co/v1.
|
|
99
|
+
<script src="https://js.maytes.co/v1.2.0/checkout-button.js"
|
|
71
100
|
integrity="sha384-…"
|
|
72
101
|
crossorigin="anonymous"></script>
|
|
73
102
|
```
|
|
74
103
|
|
|
75
104
|
```html
|
|
76
|
-
<script src="https://js.maytes.co/checkout-button.
|
|
105
|
+
<script src="https://js.maytes.co/checkout-button.c640180e.js"
|
|
77
106
|
integrity="sha384-…"
|
|
78
107
|
crossorigin="anonymous"></script>
|
|
79
108
|
```
|
|
@@ -81,60 +110,75 @@ For a guarantee instead of convenience — freeze on a tested build, update on y
|
|
|
81
110
|
|
|
82
111
|
Both URLs are the same release bytes with the same SRI value — pick either. Full version/hash/SRI history: [`CHANGELOG.md`](./CHANGELOG.md), [releases](https://github.com/kttipay/maytes-checkout-button/releases), `https://js.maytes.co/integrity.json`. Pinned URLs never change once published.
|
|
83
112
|
|
|
84
|
-
|
|
113
|
+
</details>
|
|
114
|
+
|
|
115
|
+
**npm**
|
|
85
116
|
|
|
86
117
|
```bash
|
|
87
118
|
npm install @maytes/checkout-button
|
|
88
119
|
```
|
|
89
120
|
|
|
90
|
-
|
|
121
|
+
ESM (`import`) and CommonJS (`require`) builds ship unminified with type declarations; your bundler minifies them. The reasoning behind the CDN channels is in [`docs/cdn-versioning.md`](./docs/cdn-versioning.md).
|
|
91
122
|
|
|
92
|
-
|
|
123
|
+
## API
|
|
124
|
+
|
|
125
|
+
`Maytes` is a callable factory, like `Stripe()`. Each call returns an isolated instance.
|
|
93
126
|
|
|
94
127
|
```ts
|
|
95
128
|
import { Maytes } from '@maytes/checkout-button';
|
|
96
129
|
|
|
97
130
|
const maytes = Maytes({
|
|
131
|
+
environment: 'sandbox',
|
|
98
132
|
createCheckout: async () => {
|
|
99
|
-
const res = await fetch('/api/maytes/
|
|
100
|
-
|
|
133
|
+
const res = await fetch('/api/maytes/checkout', { method: 'POST' });
|
|
134
|
+
if (!res.ok) throw new Error('Could not create the Maytes checkout');
|
|
135
|
+
return res.json(); // { checkoutId, checkoutUrl }
|
|
101
136
|
},
|
|
102
|
-
environment: 'sandbox',
|
|
103
137
|
});
|
|
104
138
|
|
|
105
|
-
|
|
139
|
+
maytes.renderButton(document.getElementById('maytes-button')!, { block: true });
|
|
140
|
+
```
|
|
106
141
|
|
|
107
|
-
|
|
108
|
-
|
|
142
|
+
| Member | Purpose |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `Maytes({ createCheckout, environment })` | Creates an instance. `createCheckout` asks your server for `{ checkoutId, checkoutUrl? }`; `environment` is `'sandbox'` or `'production'`. |
|
|
145
|
+
| `renderButton(container, { label, block, mode, radius, height })` | Renders the button and returns a function that removes it. `mode` is `'popup'` (default) or `'redirect'`; `radius` and `height` fit it next to wallet buttons. |
|
|
146
|
+
| `openCheckout({ mode })` | Starts the checkout from your own button, as a click on the rendered button does. See [Using your own button](docs/guides/own-button.md). |
|
|
147
|
+
| `instanceId` | Read-only id of the instance; every `maytes:checkout-*` event carries it in `event.detail`. |
|
|
148
|
+
| `onBusyChange(listener)` | Calls `listener(true)` when a launch starts and `listener(false)` when it ends; returns a function that stops listening. |
|
|
149
|
+
| `redirectToCheckout({ checkoutId, replace })` | Sends the current tab to a checkout you already created. |
|
|
150
|
+
| `checkoutUrl({ checkoutId })` | Builds the hosted checkout URL. |
|
|
151
|
+
| `destroy()` | Tears down the instance, its buttons, listeners and overlay. Call it on unmount. |
|
|
152
|
+
| `maytes:checkout-opened` / `-closed` / `-redirected` / `-failed` | `CustomEvent`s on `document` describing what the button did. |
|
|
109
153
|
|
|
110
|
-
|
|
111
|
-
maytes.redirectToCheckout({ checkoutId });
|
|
112
|
-
const url = maytes.checkoutUrl({ checkoutId });
|
|
154
|
+
Style the button from CSS with `--maytes-button-height`, `--maytes-button-radius` and `--maytes-button-font-size`; see the [API reference](docs/guides/api.md#styling-with-css-custom-properties).
|
|
113
155
|
|
|
114
|
-
|
|
115
|
-
cleanup();
|
|
116
|
-
maytes.destroy();
|
|
117
|
-
```
|
|
156
|
+
Full reference: [API](docs/guides/api.md) · [Events](docs/guides/events.md).
|
|
118
157
|
|
|
119
|
-
|
|
158
|
+
## More guides
|
|
120
159
|
|
|
121
|
-
|
|
160
|
+
- **Reference:** [API](docs/guides/api.md) · [Events](docs/guides/events.md) · [Popup, redirect and iframes](docs/guides/launch-behaviour.md) · [Security and CSP](docs/guides/security-csp.md)
|
|
161
|
+
- **Help:** [Troubleshooting](docs/guides/troubleshooting.md)
|
|
162
|
+
- **Internals:** [Technical overview](docs/overview.md) · [CDN versioning decision record](docs/cdn-versioning.md)
|
|
122
163
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
| `checkoutUrl(options)` | Build the hosted checkout URL. |
|
|
129
|
-
| `destroy()` | Tear down the instance and its listeners — call this on unmount or when the instance's config/environment changes, not as a reaction to detecting payment success from your own polling (that can tear down a checkout that's still in progress). To remove a single button, use the cleanup function returned by `renderButton()` or hide/disable the button element instead. |
|
|
164
|
+
The same guides ship in the npm package under `docs/guides/` and are published on [developers.maytes.co](https://developers.maytes.co/checkout-button).
|
|
165
|
+
|
|
166
|
+
## Using an AI coding assistant
|
|
167
|
+
|
|
168
|
+
This repository ships an [Agent Skill](https://github.com/kttipay/maytes-checkout-button/tree/main/skills/maytes-checkout-button) that teaches coding assistants to add Split with Maytes correctly on any stack: credentials stay on your server, `createCheckout` returns `{ checkoutId, checkoutUrl }`, the button is created in browser-only code and destroyed on unmount, and the webhook captures the payment.
|
|
130
169
|
|
|
131
|
-
|
|
170
|
+
In Claude Code:
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
/plugin marketplace add kttipay/maytes-checkout-button
|
|
174
|
+
/plugin install maytes-checkout-button@maytes
|
|
175
|
+
```
|
|
132
176
|
|
|
133
|
-
|
|
177
|
+
Then ask, for example, "add Split with Maytes to my checkout". Other assistants that support Agent Skills can use the [`skills/maytes-checkout-button`](https://github.com/kttipay/maytes-checkout-button/tree/main/skills/maytes-checkout-button) folder directly. The skill covers only the released API.
|
|
134
178
|
|
|
135
179
|
## Mobile app
|
|
136
180
|
|
|
137
|
-
After checkout, shoppers split the cost with friends using Maytes payment links (`app.maytes.co/…`).
|
|
181
|
+
After checkout, shoppers split the cost with friends using Maytes payment links (`app.maytes.co/…`). With the Maytes app installed, those links open in the app (iOS Universal Links / Android App Links); otherwise in the browser. Maytes handles this end to end — you integrate only the button and configure nothing for the app.
|
|
138
182
|
|
|
139
183
|
## Development
|
|
140
184
|
|
|
@@ -146,7 +190,7 @@ npm run test:run
|
|
|
146
190
|
npm run build # bundles + SRI hashes + CSP scan
|
|
147
191
|
```
|
|
148
192
|
|
|
149
|
-
Versioning and changelog are managed with [Changesets](./.changeset/README.md). Run `npm run changeset` with your PR. Brand colours are vendored, not hand-written — see [`RELEASING.md`](./RELEASING.md#brand-colours-come-from-the-design-foundation) for how that works.
|
|
193
|
+
Versioning and changelog are managed with [Changesets](./.changeset/README.md). Run `npm run changeset` with your PR. Brand colours are vendored, not hand-written — see [`RELEASING.md`](./RELEASING.md#brand-colours-come-from-the-design-foundation) for how that works. Internals, the end-to-end sequence and behaviour contracts are in [`docs/overview.md`](./docs/overview.md).
|
|
150
194
|
|
|
151
195
|
## License
|
|
152
196
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";var MaytesCheckoutButton=(()=>{var R=Object.defineProperty;var ve=Object.getOwnPropertyDescriptor;var ke=Object.getOwnPropertyNames;var Ce=Object.prototype.hasOwnProperty;var Ee=(e,t)=>{for(var o in t)R(e,o,{get:t[o],enumerable:!0})},xe=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ke(t))!Ce.call(e,r)&&r!==o&&R(e,r,{get:()=>t[r],enumerable:!(n=ve(t,r))||n.enumerable});return e};var Me=e=>xe(R({},"__esModule",{value:!0}),e);var at={};Ee(at,{Maytes:()=>F,MaytesError:()=>c,MaytesErrorCode:()=>s,SDK_VERSION:()=>y});var s={Config:"CONFIG"},c=class extends Error{constructor(t,o){super(o),this.code=t,this.name="MaytesError"}};var G=40,z=55,Se=999;function K(e){return typeof e=="number"&&Number.isInteger(e)}function q(e){let{radius:t,height:o}=e,n={};if(o!==void 0){if(!K(o)||o<G||o>z)throw new c(s.Config,`renderButton({ height }) must be a whole number of pixels from ${G} to ${z}`);n.height=o}if(t!==void 0){let r=o===void 0?Se:Math.floor(o/2);if(!K(t)||t<0||t>r)throw new c(s.Config,`renderButton({ radius }) must be a whole number of pixels from 0 to ${r}`);n.radius=t}return n}function Y(e,t){t.radius!==void 0&&e.style.setProperty("--maytes-button-radius",`${t.radius}px`),t.height!==void 0&&(e.style.setProperty("--maytes-button-height",`${t.height}px`),e.classList.add("maytes-checkout-button--sized"))}var l={brand:{primary:"#4A0324",secondary:"#FE572A"},palette:{burgundy:{700:"#3B021D"},base:{white:"#FFFFFF"}},text:{primaryInverse:"#FFFFFF"}};var mt=l.brand.primary,Z=l.brand.secondary,A="http://www.w3.org/2000/svg",_e=["M392,6.11c-.3-1.61-1.72-2.79-3.38-2.79h-99.97c-1.66,0-3.09,1.19-3.38,2.79l-51.14,275.49c-.36,2.07,1.24,4.03,3.38,4.03h71.07c1.72,0,3.15-1.24,3.38-2.97l5.57-42.24c.23-1.72,1.66-2.97,3.38-2.97h32.45c1.72,0,3.15,1.24,3.38,2.97l5.57,42.24c.23,1.72,1.66,2.97,3.38,2.97h74.46c2.14,0,3.8-1.96,3.38-4.03L392,6.11ZM344.42,174.89h-14.59c-2.07,0-3.62-1.84-3.38-3.86l9.55-74.33c.06-.48.48-.83.95-.83s.89.35.95.83l9.91,74.33c.3,2.02-1.31,3.86-3.38,3.86h0Z","M218.86,3.32h-77.72c-1.48,0-2.85,1.01-3.27,2.44l-25.63,83.65c-.12.35-.41.6-.83.6s-.71-.23-.83-.6L84.9,5.76c-.41-1.42-1.78-2.44-3.27-2.44H3.44c-1.9,0-3.44,1.54-3.44,3.44v275.43c0,1.9,1.54,3.45,3.44,3.45h71.26c1.9,0,3.44-1.54,3.44-3.45v-77.3l-.83-51.44c0-.53.41-.95.95-.95.41,0,.77.3.89.71l14.42,59.62c.35,1.54,1.72,2.61,3.32,2.61h28.42c1.61,0,2.97-1.06,3.32-2.61l14.47-59.79c.12-.3.35-.53.71-.53.41,0,.71.3.71.71l-.42,51.67-.06.06v77.3c0,1.9,1.54,3.44,3.44,3.44h71.37c1.9,0,3.44-1.54,3.44-3.44V6.77c0-1.9-1.54-3.44-3.44-3.44h0Z","M1179.6,147c-9.73-11.8-20.71-21.12-47.76-38.44-27.06-16.91-31.69-23.26-31.69-31.68,0-6.76,3.8-11.39,10.56-11.39,8.19,0,14.18,10.44,15.43,26.28.18,2.14,2.13,3.74,4.27,3.26l63.66-14.12c1.6-.36,2.73-1.9,2.61-3.56-3.97-49.3-35-77.36-86.44-77.36-27.47,0-50.25,8.07-67.63,24.09-17.39,16.01-25.82,36.72-25.82,62.53,0,16.91,4.22,32.09,13.12,45.62,8.9,13.53,25.75,28.3,51.56,44.38,14.77,9.32,24.09,16.49,27.88,21.12,4.21,4.63,6.35,9.31,6.35,14.36,0,6.35-4.63,10.56-11.81,10.56-10.5,0-18.15-11.87-19.28-29.66-.12-2.25-2.31-3.91-4.51-3.26l-63.6,18.68c-1.55.42-2.55,1.84-2.43,3.44,1.78,22.84,11.03,41.41,26.88,55.65,16.49,14.36,36.77,21.53,64.24,21.53s50.32-7.59,67.64-23.26c17.74-15.66,26.64-36.37,26.64-61.28,0-22.01-6.35-40.58-19.87-57.49v-.02Z","M1002.33,3.32h-146.18c-1.9,0-3.44,1.54-3.44,3.44v275.49c0,1.9,1.54,3.44,3.44,3.44h146.18c1.9,0,3.44-1.54,3.44-3.44v-62.05c0-1.9-1.54-3.44-3.44-3.44h-63.3c-1.9,0-3.45-1.54-3.45-3.45v-34.58c0-1.9,1.54-3.44,3.45-3.44v.18h53.63c1.9,0,3.45-1.54,3.45-3.44v-57.84c0-1.9-1.55-3.44-3.45-3.44h-53.63c-1.9,0-3.45-1.54-3.45-3.44v-31.61c0-1.9,1.54-3.44,3.45-3.44h63.3c1.9,0,3.44-1.54,3.44-3.44V6.77c0-1.9-1.54-3.44-3.44-3.44Z","M840.22,6.77c0-1.9-1.54-3.44-3.44-3.44h-175.31c-1.9,0-3.45,1.54-3.45,3.44v62c0,1.9,1.54,3.44,3.45,3.44h41.77c1.9,0,3.44,1.54,3.44,3.44v206.62c0,1.9,1.54,3.45,3.44,3.45h78.14c1.9,0,3.45-1.54,3.45-3.45V75.7c0-1.9,1.54-3.44,3.45-3.44h41.77c1.9,0,3.44-1.54,3.44-3.44h-.12V6.77h-.02Z","M607.71,3.38l-.06-.06c-23.23,0-32.59,48.08-40.22,80.25-1.38,5.82-4.74,18.31-7.75,27.31-4.44,13.26-10.68,30.43-22.21,31.93-18.85,2.47-7.14-39.43-7.14-39.43l21.67-92.98c.84-3.6-1.92-7.02-5.58-7.02h-85.49c-3.12,0-5.64,2.46-5.71,5.64l-1.68,75.09c-.48,21.25,5.64,42.31,18.37,59.37,12.72,17.05,38.81,28,63.12,25.9,52.48-7.08,65.46-70.49,68.4-71.1,3.06-.64,2.56,9.3.84,22.15-2.2,16.42-8.46,32.1-18.52,45.27-5.3,6.95-11.13,12.9-16.55,16.37-32.96,22.51-95.69,9.48-122.4-2.7-3.66-1.68-7.75,1.02-7.75,5.04l16.39,83.98c0,.84.18,1.68.54,2.4,9.48,17.83,53.31,19.33,74.43,17.77,32.18-2.04,100.37-29.35,115.32-122.33,12.17-103.08-1.14-162.91-38.06-162.84l.02-.02Z"];function f(e,t){let o=document.createElementNS(A,"svg");o.setAttribute("xmlns",A),o.setAttribute("viewBox","0 0 1199.47 289.04"),o.style.height=e,o.style.width="auto",o.style.color=t;for(let n of _e){let r=document.createElementNS(A,"path");r.setAttribute("fill","currentColor"),r.setAttribute("d",n),o.appendChild(r)}return o}function p(e){return typeof e=="object"&&e!==null&&e.name==="SecurityError"}function T(){return window.top!==null&&window.top!==window}function L(){if(!T())return null;let e=window.top;try{return e.document,e}catch(t){if(!p(t))throw t;return null}}function J(){if(!T())return window.innerWidth;let e=L();if(e!==null)return e.innerWidth;let t=window.screen?.width;return typeof t=="number"&&t>0?t:window.innerWidth}function X(e,t,o){o?e.location.replace(t):e.location.href=t}function Ie(e){try{e.opener=null}catch(t){if(!p(t))throw t}}function k(e,t){if(!T())return X(window,e,t),{target:"self"};let o;try{return X(window.top,e,t),{target:"top"}}catch(n){if(!p(n))throw n;o=n}try{let n=window.open(e,"_blank");return n!==null?(Ie(n),{target:"tab"}):{target:null,cause:o}}catch(n){return{target:null,cause:n}}}var Q="maytes-overlay-title",D="data-maytes-checkout-button-overlay-styles",Oe="rgba(0, 0, 0, 0.6)";function Re(){let e=L();if(e===null)return null;let t=e.document;return t.body!==null?t:null}function Ae(){return Re()??document}function Te(e){if(e===document||e.querySelector(`style[${D}]`)!==null)return;let t=document.head.querySelector("style[data-maytes-checkout-button]");if(t===null)return;let o=e.createElement("style");o.setAttribute(D,"");let n=t.getAttribute("nonce");n!==null&&o.setAttribute("nonce",n),o.textContent=t.textContent??"",e.head.appendChild(o)}function Le(e,t,o){let n=e.createElement("dialog");n.className="maytes-checkout-overlay",n.setAttribute("aria-labelledby",Q),n.setAttribute("data-maytes-overlay","");let r=e.createElement("div");r.className="maytes-checkout-overlay__content";let d=e.createElement("div");d.setAttribute("aria-hidden","true"),d.appendChild(f("2.5rem",Z)),r.appendChild(d);let i=e.createElement("div");i.className="maytes-checkout-overlay__spinner",i.setAttribute("role","status"),i.setAttribute("aria-live","polite"),i.setAttribute("aria-label","Checkout in progress"),r.appendChild(i);let u=e.createElement("p");if(u.id=Q,u.className="maytes-checkout-overlay__text",u.textContent=o==="popup"?"Completing checkout with Maytes\u2026":"Taking you to Maytes\u2026",r.appendChild(u),o==="popup"){let a=e.createElement("button");a.className="maytes-checkout-overlay__link",a.type="button",a.textContent="Return to Maytes",a.addEventListener("click",()=>{if(t.popupWindow!==null&&!t.popupWindow.closed)try{t.popupWindow.focus()}catch(m){if(!p(m))throw m}}),r.appendChild(a)}return n.appendChild(r),n.addEventListener("cancel",a=>{a.preventDefault(),t.popupWindow!==null&&!t.popupWindow.closed&&t.popupWindow.close(),h(t)}),n}function ee(e){e.style.background=Oe}function U(e,t="popup"){if(e.overlayEl!==null)return;let o=Ae();Te(o);let n=Le(o,e,t);if(e.overlayEl=n,o.body.appendChild(n),o!==document&&De(e),typeof n.showModal=="function")try{n.showModal()}catch(r){console.warn("[maytes/checkout-button] dialog.showModal failed; falling back to inline backdrop",r),n.setAttribute("open",""),ee(n)}else n.setAttribute("open",""),ee(n)}function De(e){let t=()=>h(e);window.addEventListener("pagehide",t),e.overlayDetach=()=>window.removeEventListener("pagehide",t)}function h(e){if(e.overlayEl===null)return;e.overlayDetach?.(),e.overlayDetach=null;let t=e.overlayEl,o=t.ownerDocument;typeof t.close=="function"&&t.open&&t.close(),t.remove(),o!==document&&o.head.querySelector(`style[${D}]`)?.remove(),e.overlayEl=null}var Ue={staging:"https://staging-checkout.maytes.co",sandbox:"https://sandbox-checkout.maytes.co",production:"https://checkout.maytes.co"};function te(e){return e==="sandbox"||e==="production"||e==="staging"}function oe(e,t){if(t!==void 0)return t;let o=Ue[e];if(o===void 0)throw new c(s.Config,`Unknown environment: ${String(e)}`);return o}function ne(e){let t;try{t=new URL(e)}catch{return!1}return t.protocol==="https:"||t.protocol==="http:"}function W(e){let t=e.trim().replace(/\/+$/,""),o;try{o=new URL(t)}catch{throw new c(s.Config,`baseUrl is not a valid URL: ${t}`)}if(o.protocol!=="https:"&&o.protocol!=="http:")throw new c(s.Config,`baseUrl must use http or https; got ${o.protocol}`);return t}function We(e){if(typeof e!="string"||e.trim().length===0)throw new c(s.Config,"checkoutId is required (non-empty string)");return e.trim()}function C(e,t,o){let n=We(o);return`${W(oe(e,t))}/?id=${encodeURIComponent(n)}`}function Ne(e,t){if(typeof window>"u")throw new c(s.Config,"redirectToCheckout requires a browser context (window is undefined)");if(k(e,t).target===null)throw new c(s.Config,"redirectToCheckout could not leave the embedding iframe; call it from a user gesture or from the top-level page")}function re(e,t){return{checkoutUrl(o){return C(e,t,o.checkoutId)},redirectToCheckout(o){let n=C(e,t,o.checkoutId);Ne(n,o.replace===!0)}}}var y="1.2.0";var ie="data-maytes-checkout-button",ae=`style[${ie}="${y}"]`,ce=`__maytes_checkout_button_styles_refs_${y}__`,Pe="#6b8aff",Be=`
|
|
2
|
+
.maytes-checkout-button {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
gap: 0.57em;
|
|
7
|
+
min-height: var(--maytes-button-height, auto);
|
|
8
|
+
padding: 0.71em 1.29em;
|
|
9
|
+
border: none;
|
|
10
|
+
border-radius: var(--maytes-button-radius, 999px);
|
|
11
|
+
background: ${l.brand.primary};
|
|
12
|
+
color: ${l.text.primaryInverse};
|
|
13
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
14
|
+
font-size: var(--maytes-button-font-size, 14px);
|
|
15
|
+
font-weight: 600;
|
|
16
|
+
line-height: 1;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
user-select: none;
|
|
19
|
+
transition: background-color 120ms ease, opacity 120ms ease;
|
|
20
|
+
}
|
|
21
|
+
.maytes-checkout-button:hover { background: ${l.palette.burgundy[700]}; }
|
|
22
|
+
.maytes-checkout-button:focus-visible {
|
|
23
|
+
outline: 2px solid ${Pe};
|
|
24
|
+
outline-offset: 2px;
|
|
25
|
+
}
|
|
26
|
+
.maytes-checkout-button[aria-disabled='true'] {
|
|
27
|
+
cursor: progress;
|
|
28
|
+
opacity: 0.7;
|
|
29
|
+
}
|
|
30
|
+
.maytes-checkout-button--sized {
|
|
31
|
+
box-sizing: border-box;
|
|
32
|
+
white-space: nowrap;
|
|
33
|
+
}
|
|
34
|
+
.maytes-checkout-button--block {
|
|
35
|
+
display: flex;
|
|
36
|
+
width: 100%;
|
|
37
|
+
}
|
|
38
|
+
.maytes-checkout-button__logo { height: 1em; width: auto; flex: none; }
|
|
39
|
+
.maytes-checkout-button__spinner {
|
|
40
|
+
height: 1em;
|
|
41
|
+
width: 1em;
|
|
42
|
+
border-radius: 50%;
|
|
43
|
+
border: 0.14em solid currentColor;
|
|
44
|
+
border-right-color: transparent;
|
|
45
|
+
animation: maytes-checkout-button-spin 0.7s linear infinite;
|
|
46
|
+
}
|
|
47
|
+
@keyframes maytes-checkout-button-spin {
|
|
48
|
+
to { transform: rotate(360deg); }
|
|
49
|
+
}
|
|
50
|
+
.maytes-checkout-overlay {
|
|
51
|
+
position: fixed;
|
|
52
|
+
inset: 0;
|
|
53
|
+
width: 100vw;
|
|
54
|
+
height: 100vh;
|
|
55
|
+
max-width: 100vw;
|
|
56
|
+
max-height: 100vh;
|
|
57
|
+
margin: 0;
|
|
58
|
+
padding: 0;
|
|
59
|
+
border: none;
|
|
60
|
+
background: transparent;
|
|
61
|
+
z-index: 2147483646;
|
|
62
|
+
font: 500 15px/1.4 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
63
|
+
}
|
|
64
|
+
.maytes-checkout-overlay[open] {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
}
|
|
69
|
+
.maytes-checkout-overlay::backdrop {
|
|
70
|
+
background: rgba(0, 0, 0, 0.6);
|
|
71
|
+
backdrop-filter: blur(4px);
|
|
72
|
+
-webkit-backdrop-filter: blur(4px);
|
|
73
|
+
}
|
|
74
|
+
.maytes-checkout-overlay__content {
|
|
75
|
+
display: flex;
|
|
76
|
+
flex-direction: column;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: 1.5rem;
|
|
79
|
+
}
|
|
80
|
+
.maytes-checkout-overlay__spinner {
|
|
81
|
+
width: 2.5rem;
|
|
82
|
+
height: 2.5rem;
|
|
83
|
+
border: 4px solid rgba(255, 255, 255, 0.3);
|
|
84
|
+
border-top-color: ${l.brand.secondary};
|
|
85
|
+
border-radius: 50%;
|
|
86
|
+
animation: maytes-checkout-button-spin 0.8s linear infinite;
|
|
87
|
+
}
|
|
88
|
+
.maytes-checkout-overlay__text {
|
|
89
|
+
color: ${l.text.primaryInverse};
|
|
90
|
+
font-size: 1.125rem;
|
|
91
|
+
font-weight: 500;
|
|
92
|
+
margin: 0;
|
|
93
|
+
}
|
|
94
|
+
.maytes-checkout-overlay__link {
|
|
95
|
+
color: rgba(255, 255, 255, 0.7);
|
|
96
|
+
font-size: 0.875rem;
|
|
97
|
+
text-decoration: underline;
|
|
98
|
+
text-underline-offset: 4px;
|
|
99
|
+
background: none;
|
|
100
|
+
border: none;
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
font-family: inherit;
|
|
103
|
+
transition: color 0.15s;
|
|
104
|
+
}
|
|
105
|
+
.maytes-checkout-overlay__link:hover { color: ${l.text.primaryInverse}; }
|
|
106
|
+
@media (prefers-reduced-motion: reduce) {
|
|
107
|
+
.maytes-checkout-overlay__spinner,
|
|
108
|
+
.maytes-checkout-button__spinner { animation: none; }
|
|
109
|
+
}
|
|
110
|
+
`,se=`
|
|
111
|
+
:root { color-scheme: light; }
|
|
112
|
+
html, body { margin: 0; height: 100%; }
|
|
113
|
+
body.maytes-popup-loading {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
justify-content: center;
|
|
117
|
+
min-height: 100vh;
|
|
118
|
+
background: ${l.brand.primary};
|
|
119
|
+
color: ${l.text.primaryInverse};
|
|
120
|
+
font: 500 16px/1.45 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
121
|
+
}
|
|
122
|
+
.maytes-popup-loading__content {
|
|
123
|
+
display: flex;
|
|
124
|
+
flex-direction: column;
|
|
125
|
+
align-items: center;
|
|
126
|
+
gap: 1.5rem;
|
|
127
|
+
padding: 2rem;
|
|
128
|
+
text-align: center;
|
|
129
|
+
}
|
|
130
|
+
.maytes-popup-loading__logo { height: 2.75rem; width: auto; }
|
|
131
|
+
.maytes-popup-loading__spinner {
|
|
132
|
+
width: 2.5rem;
|
|
133
|
+
height: 2.5rem;
|
|
134
|
+
border: 4px solid rgba(255, 255, 255, 0.25);
|
|
135
|
+
border-top-color: ${l.brand.secondary};
|
|
136
|
+
border-radius: 50%;
|
|
137
|
+
animation: maytes-checkout-button-spin 0.8s linear infinite;
|
|
138
|
+
}
|
|
139
|
+
@keyframes maytes-checkout-button-spin {
|
|
140
|
+
to { transform: rotate(360deg); }
|
|
141
|
+
}
|
|
142
|
+
.maytes-popup-loading__text { margin: 0; font-size: 1.05rem; font-weight: 500; }
|
|
143
|
+
.maytes-popup-loading__slow {
|
|
144
|
+
margin: 0;
|
|
145
|
+
font-size: 0.9rem;
|
|
146
|
+
font-weight: 400;
|
|
147
|
+
color: rgba(255, 255, 255, 0.75);
|
|
148
|
+
max-width: 22rem;
|
|
149
|
+
}
|
|
150
|
+
.maytes-popup-loading__slow[hidden] { display: none; }
|
|
151
|
+
@media (prefers-reduced-motion: reduce) {
|
|
152
|
+
.maytes-popup-loading__spinner { animation: none; }
|
|
153
|
+
}
|
|
154
|
+
`;function ue(){return window[ce]??0}function le(e){let t=window;t[ce]=e}function de(e){let t=ue()+1;if(le(t),document.head.querySelector(ae)!==null)return;let o=document.createElement("style");o.setAttribute(ie,y),e!==void 0&&e!==""&&o.setAttribute("nonce",e),o.textContent=Be,document.head.appendChild(o)}function pe(){let e=Math.max(0,ue()-1);if(le(e),e>0)return;let t=document.head.querySelector(ae);t!==null&&t.remove()}var N=500,P=800,$e=500,Fe=600,He=8e3;function Ve(e){if(typeof e!="object"||e===null)return!1;let t=e;return!(typeof t.checkoutId!="string"||t.checkoutId.trim().length===0||t.checkoutUrl!==void 0&&(typeof t.checkoutUrl!="string"||t.checkoutUrl.trim().length===0||!ne(t.checkoutUrl)))}function je(e){try{e.focus()}catch(t){if(!p(t))throw t}}function E(e){if(e!==null)try{e.closed||e.close()}catch(t){if(!p(t))throw t}}function Ge(){let e=window.screen?.width??N,t=window.screen?.height??P,o=Math.max(0,Math.round((e-N)/2)),n=Math.max(0,Math.round((t-P)/2));return`popup=yes,width=${N},height=${P},left=${o},top=${n},resizable=yes,scrollbars=yes`}function w(e){e.popupPollHandle!==null&&(clearInterval(e.popupPollHandle),e.popupPollHandle=null)}function ze(e,t){w(e),e.popupPollHandle=setInterval(()=>{let o=e.popupWindow;(o===null||o.closed)&&(w(e),e.popupWindow=null,t())},$e)}function Ke(){return J()<=Fe}function qe(e){return window.open("about:blank",e.popupName,Ge())}function Ye(e,t){e.location.replace(t)}function Ze(e){for(;e.body.firstChild!==null;)e.body.removeChild(e.body.firstChild)}function Xe(e,t){let o=e.document;if(o===null||o.head===null||o.body===null)return;o.title="Maytes checkout",o.documentElement.lang="en";let n=o.createElement("style");t!==void 0&&t!==""&&n.setAttribute("nonce",t),n.textContent=se,o.head.appendChild(n),o.body.classList.add("maytes-popup-loading"),Ze(o);let r=o.createElement("main");r.className="maytes-popup-loading__content",r.setAttribute("role","status"),r.setAttribute("aria-live","polite");let d=f("2.75rem",l.text.primaryInverse);d.setAttribute("class","maytes-popup-loading__logo"),d.setAttribute("aria-hidden","true"),r.appendChild(d);let i=o.createElement("div");i.className="maytes-popup-loading__spinner",i.setAttribute("aria-hidden","true"),r.appendChild(i);let u=o.createElement("p");u.className="maytes-popup-loading__text",u.textContent="Completing checkout with Maytes\u2026",r.appendChild(u);let a=o.createElement("p");a.className="maytes-popup-loading__slow",a.hidden=!0,a.textContent="Still connecting. This can take a moment on slow networks.",r.appendChild(a),o.body.appendChild(r),setTimeout(()=>{a.hidden=!1},He)}function Je(e,t){return{instanceId:e.instanceId,source:t}}function B(e,t,o){let n=o===void 0?{...e,reason:t}:{...e,reason:t,cause:o};document.dispatchEvent(new CustomEvent("maytes:checkout-failed",{detail:n}))}function Qe(e,t,o){let n={...e,url:t,target:o};document.dispatchEvent(new CustomEvent("maytes:checkout-redirected",{detail:n}))}function x(e,t="renderButton"){if(e!=="redirect"&&e!=="popup")throw new c(s.Config,`${t}({ mode }) must be 'redirect' or 'popup'`);return e}function M(e,t="renderButton"){if(e===void 0)return!1;if(typeof e!="boolean")throw new c(s.Config,`${t}({ redirectOverlay }) must be true or false`);return e}function $(e,t){e.busy=t;for(let o of[...e.busyViews])o(t)}function S(e){h(e),$(e,!1)}function me(e,t){E(t),w(e),e.popupWindow===t&&(e.popupWindow=null),S(e)}function et(e){if(e.restoreDetach!==null)return;let t=n=>{n.persisted&&(o(),S(e))},o=()=>{window.removeEventListener("pageshow",t),e.restoreDetach=null};window.addEventListener("pageshow",t),e.restoreDetach=o}function tt(e,t,o,n){let r=k(o,!1);return n&&(r.target==="self"||r.target==="top")?($(e,!1),et(e)):S(e),r.target===null?(console.error("[maytes/checkout-button] could not leave the embedding frame:",r.cause),B(t,"navigation-blocked",r.cause),{outcome:"failed",reason:"navigation-blocked"}):(Qe(t,o,r.target),{outcome:"redirected",target:r.target})}function ot(e,t){let o=qe(e);return o===null?null:(e.popupWindow=o,e.popupNavigated=!1,je(o),Xe(o,e.config.cspNonce),U(e),document.dispatchEvent(new CustomEvent("maytes:checkout-opened",{detail:t})),ze(e,()=>{S(e),document.dispatchEvent(new CustomEvent("maytes:checkout-closed",{detail:t}))}),o)}async function _(e,t,o,n=!1){if(e.busy||e.destroyed)return{outcome:"ignored"};$(e,!0);let r=Je(e,o),d=t==="popup"&&!Ke(),i=d?ot(e,r):null;i===null&&n&&U(e,"redirect");try{let u=await e.config.createCheckout();if(e.destroyed||i!==null&&i.closed)return E(i),{outcome:"closed"};if(!Ve(u)){me(e,i);let m=new c(s.Config,"createCheckout must resolve to { checkoutId: string, checkoutUrl?: http(s) URL }");return console.error(m),B(r,"invalid-shape",m),{outcome:"failed",reason:"invalid-shape"}}let a=u.checkoutUrl??C(e.config.environment,e.config.baseUrl,u.checkoutId);return i!==null?(e.popupNavigated=!0,Ye(i,a),{outcome:"popup"}):(d&&console.warn("[maytes/checkout-button] popup was blocked; redirecting instead"),tt(e,r,a,n))}catch(u){return i!==null&&i.closed?{outcome:"closed"}:(me(e,i),console.error("[maytes/checkout-button] createCheckout failed:",u),B(r,"create-checkout-rejected",u),{outcome:"failed",reason:"create-checkout-rejected"})}}function fe(){let e=f("1em","currentColor");return e.setAttribute("class","maytes-checkout-button__logo"),e.setAttribute("aria-hidden","true"),e}function nt(){let e=document.createElement("span");return e.className="maytes-checkout-button__spinner",e.setAttribute("aria-hidden","true"),e}function he(e,t,o={}){if(e.destroyed)throw new c(s.Config,"renderButton() called on a destroyed Maytes instance");if(!(t instanceof HTMLElement))throw new c(s.Config,"renderButton(container) requires an HTMLElement");let n=q(o),r=M(o.redirectOverlay);de(e.config.cspNonce);let d=o.label??"Split with",i=o.block===!0,u=x(o.mode??"popup"),a=document.createElement("button");a.type="button",a.className=i?"maytes-checkout-button maytes-checkout-button--block":"maytes-checkout-button",Y(a,n),a.setAttribute("aria-label",`${d} Maytes`);let m=document.createTextNode(`${d} `),g=fe();a.appendChild(m),a.appendChild(g);let we=v=>{if(v){a.setAttribute("aria-disabled","true"),a.setAttribute("aria-busy","true");let b=nt();g.replaceWith(b),g=b}else{a.removeAttribute("aria-disabled"),a.removeAttribute("aria-busy");let b=fe();g.replaceWith(b),g=b}},I=!1,H=v=>{I&&(we(v),v||(I=!1))};e.busyViews.add(H);let V=()=>{e.busy||e.destroyed||(I=!0,_(e,u,"button",r))};a.addEventListener("click",V),t.appendChild(a);let j=!1,O=()=>{j||(j=!0,a.removeEventListener("click",V),a.remove(),e.busyViews.delete(H),e.teardowns.delete(O),pe())};return e.teardowns.add(O),O}function ye(){return`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}function ge(){if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")try{return crypto.randomUUID()}catch{return ye()}return ye()}function be(e,t){let o={createCheckout:e.createCheckout,environment:e.environment};return t?.baseUrl!==void 0&&(o.baseUrl=t.baseUrl),t?.cspNonce!==void 0&&(o.cspNonce=t.cspNonce),{config:o,busy:!1,busyViews:new Set,instanceId:ge(),overlayEl:null,overlayDetach:null,restoreDetach:null,popupWindow:null,popupNavigated:!1,popupName:`maytes-checkout-${ge()}`,popupPollHandle:null,destroyed:!1,teardowns:new Set}}function rt(e){if(typeof e!="object"||e===null)throw new c(s.Config,"Maytes() requires an options object");if(typeof e.createCheckout!="function")throw new c(s.Config,"Maytes({ createCheckout }) must be an async function returning { checkoutId }");if(!te(e.environment))throw new c(s.Config,"Maytes({ environment }) must be 'sandbox' or 'production'")}function it(e){e!==void 0&&e.baseUrl!==void 0&&W(e.baseUrl)}var F=(e,t)=>{rt(e),it(t);let o=be(e,t),{checkoutUrl:n,redirectToCheckout:r}=re(o.config.environment,o.config.baseUrl);return{instanceId:o.instanceId,renderButton(i,u){return he(o,i,u)},openCheckout(i){if(o.destroyed)throw new c(s.Config,"openCheckout() called on a destroyed Maytes instance");let u=x(i?.mode??"popup","openCheckout"),a=M(i?.redirectOverlay,"openCheckout");return _(o,u,"api",a)},onBusyChange(i){if(o.destroyed)throw new c(s.Config,"onBusyChange() called on a destroyed Maytes instance");return o.busyViews.add(i),()=>{o.busyViews.delete(i)}},redirectToCheckout(i){r(i)},checkoutUrl(i){return n(i)},destroy(){if(!o.destroyed){o.destroyed=!0,w(o),o.restoreDetach?.(),h(o),o.popupNavigated||E(o.popupWindow),o.popupWindow=null,o.busy=!1;for(let i of[...o.teardowns])i();o.teardowns.clear()}}}};typeof window<"u"&&(window.Maytes=F);return Me(at);})();
|
|
155
|
+
window.Maytes = MaytesCheckoutButton.Maytes;
|
|
156
|
+
//# sourceMappingURL=checkout-button.js.map
|