@maytes/checkout-button 1.1.1 → 1.2.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/CHANGELOG.md +82 -0
- package/README.md +93 -74
- package/dist/checkout-button.299a037b.js +188 -0
- package/dist/checkout-button.299a037b.js.map +1 -0
- package/dist/{checkout-button.2aad12c3.cjs → checkout-button.332d26cc.cjs} +314 -156
- package/dist/checkout-button.332d26cc.cjs.map +1 -0
- package/dist/{checkout-button.aed57a66.mjs → checkout-button.67fdb2e1.mjs} +314 -156
- package/dist/checkout-button.67fdb2e1.mjs.map +1 -0
- package/dist/checkout-button.cjs +314 -156
- 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.element.afe71cd5.js +187 -0
- package/dist/checkout-button.element.afe71cd5.js.map +1 -0
- package/dist/checkout-button.element.js +187 -0
- package/dist/checkout-button.element.js.map +1 -0
- package/dist/checkout-button.js +58 -21
- package/dist/checkout-button.js.map +1 -1
- package/dist/checkout-button.mjs +314 -156
- 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,86 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#39](https://github.com/kttipay/maytes-checkout-button/pull/39) [`73d1f0c`](https://github.com/kttipay/maytes-checkout-button/commit/73d1f0ccb84ec22473e8a0b1ba17e923c254e2ee) Thanks [@kos-maytes](https://github.com/kos-maytes)! - The Split with Maytes button keeps its white label and logo, burgundy background and Maytes focus ring when hovered, focused or pressed on sites whose theme styles every button (for example WooCommerce's Storefront theme, which turned the label dark grey on hover). Host-page transitions no longer fade the logo, and the overlay's "Return to Maytes" link no longer picks up the theme's button background. A mouse click no longer shows the theme's focus outline on the button or the link; keyboard focus shows the Maytes focus ring on both.
|
|
8
|
+
|
|
9
|
+
<!-- @hash-sri-start -->
|
|
10
|
+
|
|
11
|
+
**SRI hashes** (use these in `<script integrity="..." crossorigin="anonymous">`):
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
checkout-button.js sha384-0n2iIhZMofbJkzlb2mgQmm714yMFWW0079cxvVxCxZKPjjRHTrEBddxLRygUFUA/
|
|
15
|
+
checkout-button.mjs sha384-DvlD7lErx6rl9lPfEtS9tu9Hp+sb+LC8ZXkzCnfRxP2ruuHuE/toGraDj7Hp9KjU
|
|
16
|
+
checkout-button.cjs sha384-2h9J+cURwjqOA8QYBgt1LeulM0IgD6w1hCxdLdieKvuhDb1/ejuXT3rLEy5SXsb9
|
|
17
|
+
checkout-button.element.js sha384-NHwIzALKGM4v3zbs5kbpDmWb52EGQ6+NMh7ARB5UPTCbjwn3orJV1bDnXzgZrwck
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**SemVer CDN links** (readable production pins; use with the SRI hashes above):
|
|
21
|
+
|
|
22
|
+
- [checkout-button.js](https://js.maytes.co/v1.2.1/checkout-button.js)
|
|
23
|
+
- [checkout-button.mjs](https://js.maytes.co/v1.2.1/checkout-button.mjs)
|
|
24
|
+
- [checkout-button.cjs](https://js.maytes.co/v1.2.1/checkout-button.cjs)
|
|
25
|
+
- [checkout-button.element.js](https://js.maytes.co/v1.2.1/checkout-button.element.js)
|
|
26
|
+
|
|
27
|
+
**Hashed CDN links** (byte-level production pins; use with the SRI hashes above):
|
|
28
|
+
|
|
29
|
+
- [checkout-button.299a037b.js](https://js.maytes.co/checkout-button.299a037b.js)
|
|
30
|
+
- [checkout-button.67fdb2e1.mjs](https://js.maytes.co/checkout-button.67fdb2e1.mjs)
|
|
31
|
+
- [checkout-button.332d26cc.cjs](https://js.maytes.co/checkout-button.332d26cc.cjs)
|
|
32
|
+
- [checkout-button.element.afe71cd5.js](https://js.maytes.co/checkout-button.element.afe71cd5.js)
|
|
33
|
+
|
|
34
|
+
<!-- @hash-sri-end -->
|
|
35
|
+
## 1.2.0
|
|
36
|
+
|
|
37
|
+
### Minor Changes
|
|
38
|
+
|
|
39
|
+
- [#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.
|
|
40
|
+
|
|
41
|
+
- [#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.
|
|
42
|
+
|
|
43
|
+
- [#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.
|
|
44
|
+
|
|
45
|
+
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.
|
|
46
|
+
|
|
47
|
+
- [#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.
|
|
48
|
+
|
|
49
|
+
- [#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.
|
|
50
|
+
|
|
51
|
+
- [#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.
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- [#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.
|
|
56
|
+
|
|
57
|
+
<!-- @hash-sri-start -->
|
|
58
|
+
|
|
59
|
+
**SRI hashes** (use these in `<script integrity="..." crossorigin="anonymous">`):
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
checkout-button.js sha384-gIQUOEPPO0H+Stb2Ffa40dFxBxGnB40p1+AHttEYor5oZiVKoM+aKagIL3GuNkG1
|
|
63
|
+
checkout-button.mjs sha384-sKFZzp1oSiijC45OFR04FOjFQfgvxawtUp+u/qXvRu5s5ZF8iMSTHaQo5g+VLJ79
|
|
64
|
+
checkout-button.cjs sha384-fkm1nIhsGYEjDw3uc4cjdxui4K8H4HuPnIQ379GP1Y7vtwFC/Dw3M85KopqvjRl1
|
|
65
|
+
checkout-button.element.js sha384-Y3aDrAucY25r7DzSkYJpsjoazd67oBy4WSxbTXBgpaWaT6TOuEOW3PidCw0PeVb9
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**SemVer CDN links** (readable production pins; use with the SRI hashes above):
|
|
69
|
+
|
|
70
|
+
- [checkout-button.js](https://js.maytes.co/v1.2.0/checkout-button.js)
|
|
71
|
+
- [checkout-button.mjs](https://js.maytes.co/v1.2.0/checkout-button.mjs)
|
|
72
|
+
- [checkout-button.cjs](https://js.maytes.co/v1.2.0/checkout-button.cjs)
|
|
73
|
+
- [checkout-button.element.js](https://js.maytes.co/v1.2.0/checkout-button.element.js)
|
|
74
|
+
|
|
75
|
+
**Hashed CDN links** (byte-level production pins; use with the SRI hashes above):
|
|
76
|
+
|
|
77
|
+
- [checkout-button.c640180e.js](https://js.maytes.co/checkout-button.c640180e.js)
|
|
78
|
+
- [checkout-button.d6e444ee.mjs](https://js.maytes.co/checkout-button.d6e444ee.mjs)
|
|
79
|
+
- [checkout-button.d7bc9aea.cjs](https://js.maytes.co/checkout-button.d7bc9aea.cjs)
|
|
80
|
+
- [checkout-button.element.6c530c24.js](https://js.maytes.co/checkout-button.element.6c530c24.js)
|
|
81
|
+
|
|
82
|
+
<!-- @hash-sri-end -->
|
|
83
|
+
|
|
3
84
|
## 1.1.1
|
|
4
85
|
|
|
5
86
|
### Patch Changes
|
|
@@ -29,6 +110,7 @@ checkout-button.cjs sha384-oSekYX0Re0jdMsBU6uzxUedTM+Cnl8uF5y0wmZmjUHngtzr8Sdze
|
|
|
29
110
|
- [checkout-button.2aad12c3.cjs](https://js.maytes.co/checkout-button.2aad12c3.cjs)
|
|
30
111
|
|
|
31
112
|
<!-- @hash-sri-end -->
|
|
113
|
+
|
|
32
114
|
## 1.1.0
|
|
33
115
|
|
|
34
116
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -5,136 +5,155 @@
|
|
|
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`, so you get fixes without redeploying.
|
|
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.
|
|
40
58
|
|
|
41
|
-
|
|
59
|
+
<a id="usage"></a>
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
|---|---|---|
|
|
45
|
-
| **Use when** | Default — always get the newest `1.x` release | You'd rather freeze on a tested build |
|
|
46
|
-
| **Guarantee** | Always current; a bad release reaches you immediately | The bytes you tested are the bytes shipped, forever |
|
|
47
|
-
| **SRI** | Not possible | Yes |
|
|
61
|
+
## Choose your setup
|
|
48
62
|
|
|
49
|
-
|
|
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)
|
|
65
|
+
|
|
66
|
+
## Install
|
|
67
|
+
|
|
68
|
+
**Script tag**
|
|
50
69
|
|
|
51
70
|
```html
|
|
52
71
|
<script src="https://js.maytes.co/v1/checkout-button.js"
|
|
53
72
|
crossorigin="anonymous"></script>
|
|
54
73
|
```
|
|
55
74
|
|
|
56
|
-
|
|
75
|
+
Always serves the newest `1.x` release, so you get fixes without redeploying. It won't jump to a future `2.x`: move to `/v2/checkout-button.js` yourself once that ships.
|
|
57
76
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
`/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
|
-
|
|
64
|
-
### Pinned (SemVer or content hash)
|
|
77
|
+
<details>
|
|
78
|
+
<summary><b>CSP</b></summary>
|
|
65
79
|
|
|
66
|
-
|
|
80
|
+
Allow the CDN origin in your Content Security Policy:
|
|
67
81
|
|
|
68
|
-
<!-- @cdn-example-start -->
|
|
69
|
-
```html
|
|
70
|
-
<script src="https://js.maytes.co/v1.1.1/checkout-button.js"
|
|
71
|
-
integrity="sha384-…"
|
|
72
|
-
crossorigin="anonymous"></script>
|
|
73
82
|
```
|
|
74
|
-
|
|
75
|
-
```html
|
|
76
|
-
<script src="https://js.maytes.co/checkout-button.4b780d52.js"
|
|
77
|
-
integrity="sha384-…"
|
|
78
|
-
crossorigin="anonymous"></script>
|
|
83
|
+
Content-Security-Policy: script-src 'self' https://js.maytes.co;
|
|
79
84
|
```
|
|
80
|
-
<!-- @cdn-example-end -->
|
|
81
85
|
|
|
82
|
-
|
|
86
|
+
No `integrity` attribute is possible on this URL, because its bytes change as new `1.x` releases ship. Poll `https://js.maytes.co/integrity.json` if you want to detect changes yourself.
|
|
87
|
+
|
|
88
|
+
</details>
|
|
83
89
|
|
|
84
|
-
|
|
90
|
+
**npm**
|
|
85
91
|
|
|
86
92
|
```bash
|
|
87
93
|
npm install @maytes/checkout-button
|
|
88
94
|
```
|
|
89
95
|
|
|
90
|
-
|
|
96
|
+
ESM (`import`) and CommonJS (`require`) builds ship unminified with type declarations; your bundler minifies them.
|
|
97
|
+
|
|
98
|
+
## API
|
|
91
99
|
|
|
92
|
-
`Maytes` is a callable factory (
|
|
100
|
+
`Maytes` is a callable factory, like `Stripe()`. Each call returns an isolated instance.
|
|
93
101
|
|
|
94
102
|
```ts
|
|
95
103
|
import { Maytes } from '@maytes/checkout-button';
|
|
96
104
|
|
|
97
105
|
const maytes = Maytes({
|
|
106
|
+
environment: 'sandbox',
|
|
98
107
|
createCheckout: async () => {
|
|
99
|
-
const res = await fetch('/api/maytes/
|
|
100
|
-
|
|
108
|
+
const res = await fetch('/api/maytes/checkout', { method: 'POST' });
|
|
109
|
+
if (!res.ok) throw new Error('Could not create the Maytes checkout');
|
|
110
|
+
return res.json(); // { checkoutId, checkoutUrl }
|
|
101
111
|
},
|
|
102
|
-
environment: 'sandbox',
|
|
103
112
|
});
|
|
104
113
|
|
|
105
|
-
|
|
114
|
+
maytes.renderButton(document.getElementById('maytes-button')!, { block: true });
|
|
115
|
+
```
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
|
|
117
|
+
| Member | Purpose |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `Maytes({ createCheckout, environment })` | Creates an instance. `createCheckout` asks your server for `{ checkoutId, checkoutUrl? }`; `environment` is `'sandbox'` or `'production'`. |
|
|
120
|
+
| `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. |
|
|
121
|
+
| `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). |
|
|
122
|
+
| `instanceId` | Read-only id of the instance; every `maytes:checkout-*` event carries it in `event.detail`. |
|
|
123
|
+
| `onBusyChange(listener)` | Calls `listener(true)` when a launch starts and `listener(false)` when it ends; returns a function that stops listening. |
|
|
124
|
+
| `redirectToCheckout({ checkoutId, replace })` | Sends the current tab to a checkout you already created. |
|
|
125
|
+
| `checkoutUrl({ checkoutId })` | Builds the hosted checkout URL. |
|
|
126
|
+
| `destroy()` | Tears down the instance, its buttons, listeners and overlay. Call it on unmount. |
|
|
127
|
+
| `maytes:checkout-opened` / `-closed` / `-redirected` / `-failed` | `CustomEvent`s on `document` describing what the button did. |
|
|
109
128
|
|
|
110
|
-
|
|
111
|
-
maytes.redirectToCheckout({ checkoutId });
|
|
112
|
-
const url = maytes.checkoutUrl({ checkoutId });
|
|
129
|
+
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
130
|
|
|
114
|
-
|
|
115
|
-
cleanup();
|
|
116
|
-
maytes.destroy();
|
|
117
|
-
```
|
|
131
|
+
Full reference: [API](docs/guides/api.md) · [Events](docs/guides/events.md).
|
|
118
132
|
|
|
119
|
-
|
|
133
|
+
## More guides
|
|
120
134
|
|
|
121
|
-
|
|
135
|
+
- **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)
|
|
136
|
+
- **Help:** [Troubleshooting](docs/guides/troubleshooting.md)
|
|
137
|
+
- **Internals:** [Technical overview](docs/overview.md) · [CDN versioning decision record](docs/cdn-versioning.md)
|
|
122
138
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
| `renderButton(container, options?)` | Render the button into `container`; returns a cleanup function. Options include `label`, `block`, and `mode: 'redirect' \| 'popup'` (default `'popup'`). |
|
|
127
|
-
| `redirectToCheckout(options)` | Launch checkout directly (no button). |
|
|
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. |
|
|
139
|
+
The same guides ship in the npm package under `docs/guides/` and are published on [developers.maytes.co](https://developers.maytes.co/checkout-button).
|
|
140
|
+
|
|
141
|
+
## Using an AI coding assistant
|
|
130
142
|
|
|
131
|
-
|
|
143
|
+
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.
|
|
144
|
+
|
|
145
|
+
In Claude Code:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
/plugin marketplace add kttipay/maytes-checkout-button
|
|
149
|
+
/plugin install maytes-checkout-button@maytes
|
|
150
|
+
```
|
|
132
151
|
|
|
133
|
-
|
|
152
|
+
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
153
|
|
|
135
154
|
## Mobile app
|
|
136
155
|
|
|
137
|
-
After checkout, shoppers split the cost with friends using Maytes payment links (`app.maytes.co/…`).
|
|
156
|
+
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
157
|
|
|
139
158
|
## Development
|
|
140
159
|
|
|
@@ -146,7 +165,7 @@ npm run test:run
|
|
|
146
165
|
npm run build # bundles + SRI hashes + CSP scan
|
|
147
166
|
```
|
|
148
167
|
|
|
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.
|
|
168
|
+
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
169
|
|
|
151
170
|
## License
|
|
152
171
|
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";var MaytesCheckoutButton=(()=>{var R=Object.defineProperty;var we=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var _e=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 Ce(t))!_e.call(e,r)&&r!==o&&R(e,r,{get:()=>t[r],enumerable:!(n=we(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:()=>f});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",Ie=["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 h(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 Ie){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 Oe(e){try{e.opener=null}catch(t){if(!p(t))throw t}}function w(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?(Oe(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",Re="rgba(0, 0, 0, 0.6)";function Ae(){let e=L();if(e===null)return null;let t=e.document;return t.body!==null?t:null}function Te(){return Ae()??document}function Le(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 De(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(h("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(),y(t)}),n}function ee(e){e.style.background=Re}function U(e,t="popup"){if(e.overlayEl!==null)return;let o=Te();Le(o);let n=De(o,e,t);if(e.overlayEl=n,o.body.appendChild(n),o!==document&&Ue(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 Ue(e){let t=()=>y(e);window.addEventListener("pagehide",t),e.overlayDetach=()=>window.removeEventListener("pagehide",t)}function y(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 We={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=We[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 Ne(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=Ne(o);return`${W(oe(e,t))}/?id=${encodeURIComponent(n)}`}function Pe(e,t){if(typeof window>"u")throw new c(s.Config,"redirectToCheckout requires a browser context (window is undefined)");if(w(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);Pe(n,o.replace===!0)}}}var f="1.2.1";var ae="data-maytes-checkout-button",ce=`style[${ae}="${f}"]`,se=`__maytes_checkout_button_styles_refs_${f}__`,ie="#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-radius: var(--maytes-button-radius, 999px);
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
11
|
+
font-size: var(--maytes-button-font-size, 14px);
|
|
12
|
+
font-weight: 600;
|
|
13
|
+
line-height: 1;
|
|
14
|
+
user-select: none;
|
|
15
|
+
}
|
|
16
|
+
.maytes-checkout-button.maytes-checkout-button,
|
|
17
|
+
.maytes-checkout-button.maytes-checkout-button:hover,
|
|
18
|
+
.maytes-checkout-button.maytes-checkout-button:focus,
|
|
19
|
+
.maytes-checkout-button.maytes-checkout-button:active {
|
|
20
|
+
background: ${l.brand.primary};
|
|
21
|
+
border: none;
|
|
22
|
+
color: ${l.text.primaryInverse};
|
|
23
|
+
box-shadow: none;
|
|
24
|
+
text-decoration: none;
|
|
25
|
+
text-shadow: none;
|
|
26
|
+
filter: none;
|
|
27
|
+
transform: none;
|
|
28
|
+
opacity: 1;
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
transition: background-color 120ms ease, opacity 120ms ease;
|
|
31
|
+
}
|
|
32
|
+
.maytes-checkout-button.maytes-checkout-button:hover { background: ${l.palette.burgundy[700]}; }
|
|
33
|
+
.maytes-checkout-button.maytes-checkout-button:focus:not(:focus-visible) { outline: none; }
|
|
34
|
+
.maytes-checkout-button.maytes-checkout-button:focus-visible {
|
|
35
|
+
outline: 2px solid ${ie};
|
|
36
|
+
outline-offset: 2px;
|
|
37
|
+
}
|
|
38
|
+
.maytes-checkout-button.maytes-checkout-button[aria-disabled='true'] {
|
|
39
|
+
cursor: progress;
|
|
40
|
+
opacity: 0.7;
|
|
41
|
+
}
|
|
42
|
+
.maytes-checkout-button.maytes-checkout-button * { transition: none; }
|
|
43
|
+
.maytes-checkout-button.maytes-checkout-button .maytes-checkout-button__logo,
|
|
44
|
+
.maytes-checkout-button.maytes-checkout-button .maytes-checkout-button__logo * {
|
|
45
|
+
animation: none;
|
|
46
|
+
fill: currentColor;
|
|
47
|
+
}
|
|
48
|
+
.maytes-checkout-button--sized {
|
|
49
|
+
box-sizing: border-box;
|
|
50
|
+
white-space: nowrap;
|
|
51
|
+
}
|
|
52
|
+
.maytes-checkout-button--block {
|
|
53
|
+
display: flex;
|
|
54
|
+
width: 100%;
|
|
55
|
+
}
|
|
56
|
+
.maytes-checkout-button__logo { height: 1em; width: auto; flex: none; }
|
|
57
|
+
.maytes-checkout-button__spinner {
|
|
58
|
+
height: 1em;
|
|
59
|
+
width: 1em;
|
|
60
|
+
border-radius: 50%;
|
|
61
|
+
border: 0.14em solid currentColor;
|
|
62
|
+
border-right-color: transparent;
|
|
63
|
+
animation: maytes-checkout-button-spin 0.7s linear infinite;
|
|
64
|
+
}
|
|
65
|
+
@keyframes maytes-checkout-button-spin {
|
|
66
|
+
to { transform: rotate(360deg); }
|
|
67
|
+
}
|
|
68
|
+
.maytes-checkout-overlay {
|
|
69
|
+
position: fixed;
|
|
70
|
+
inset: 0;
|
|
71
|
+
width: 100vw;
|
|
72
|
+
height: 100vh;
|
|
73
|
+
max-width: 100vw;
|
|
74
|
+
max-height: 100vh;
|
|
75
|
+
margin: 0;
|
|
76
|
+
padding: 0;
|
|
77
|
+
border: none;
|
|
78
|
+
background: transparent;
|
|
79
|
+
z-index: 2147483646;
|
|
80
|
+
font: 500 15px/1.4 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
81
|
+
}
|
|
82
|
+
.maytes-checkout-overlay[open] {
|
|
83
|
+
display: flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
justify-content: center;
|
|
86
|
+
}
|
|
87
|
+
.maytes-checkout-overlay::backdrop {
|
|
88
|
+
background: rgba(0, 0, 0, 0.6);
|
|
89
|
+
backdrop-filter: blur(4px);
|
|
90
|
+
-webkit-backdrop-filter: blur(4px);
|
|
91
|
+
}
|
|
92
|
+
.maytes-checkout-overlay__content {
|
|
93
|
+
display: flex;
|
|
94
|
+
flex-direction: column;
|
|
95
|
+
align-items: center;
|
|
96
|
+
gap: 1.5rem;
|
|
97
|
+
}
|
|
98
|
+
.maytes-checkout-overlay__spinner {
|
|
99
|
+
width: 2.5rem;
|
|
100
|
+
height: 2.5rem;
|
|
101
|
+
border: 4px solid rgba(255, 255, 255, 0.3);
|
|
102
|
+
border-top-color: ${l.brand.secondary};
|
|
103
|
+
border-radius: 50%;
|
|
104
|
+
animation: maytes-checkout-button-spin 0.8s linear infinite;
|
|
105
|
+
}
|
|
106
|
+
.maytes-checkout-overlay__text {
|
|
107
|
+
color: ${l.text.primaryInverse};
|
|
108
|
+
font-size: 1.125rem;
|
|
109
|
+
font-weight: 500;
|
|
110
|
+
margin: 0;
|
|
111
|
+
}
|
|
112
|
+
.maytes-checkout-overlay__link {
|
|
113
|
+
font-size: 0.875rem;
|
|
114
|
+
text-underline-offset: 4px;
|
|
115
|
+
font-family: inherit;
|
|
116
|
+
}
|
|
117
|
+
.maytes-checkout-overlay__link.maytes-checkout-overlay__link,
|
|
118
|
+
.maytes-checkout-overlay__link.maytes-checkout-overlay__link:hover,
|
|
119
|
+
.maytes-checkout-overlay__link.maytes-checkout-overlay__link:focus,
|
|
120
|
+
.maytes-checkout-overlay__link.maytes-checkout-overlay__link:active {
|
|
121
|
+
background: none;
|
|
122
|
+
border: none;
|
|
123
|
+
color: rgba(255, 255, 255, 0.7);
|
|
124
|
+
box-shadow: none;
|
|
125
|
+
text-decoration: underline;
|
|
126
|
+
text-shadow: none;
|
|
127
|
+
transform: none;
|
|
128
|
+
opacity: 1;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
transition: color 0.15s;
|
|
131
|
+
}
|
|
132
|
+
.maytes-checkout-overlay__link.maytes-checkout-overlay__link:hover { color: ${l.text.primaryInverse}; }
|
|
133
|
+
.maytes-checkout-overlay__link.maytes-checkout-overlay__link:focus:not(:focus-visible) { outline: none; }
|
|
134
|
+
.maytes-checkout-overlay__link.maytes-checkout-overlay__link:focus-visible {
|
|
135
|
+
outline: 2px solid ${ie};
|
|
136
|
+
outline-offset: 2px;
|
|
137
|
+
}
|
|
138
|
+
@media (prefers-reduced-motion: reduce) {
|
|
139
|
+
.maytes-checkout-overlay__spinner,
|
|
140
|
+
.maytes-checkout-button__spinner { animation: none; }
|
|
141
|
+
}
|
|
142
|
+
`,ue=`
|
|
143
|
+
:root { color-scheme: light; }
|
|
144
|
+
html, body { margin: 0; height: 100%; }
|
|
145
|
+
body.maytes-popup-loading {
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
justify-content: center;
|
|
149
|
+
min-height: 100vh;
|
|
150
|
+
background: ${l.brand.primary};
|
|
151
|
+
color: ${l.text.primaryInverse};
|
|
152
|
+
font: 500 16px/1.45 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
153
|
+
}
|
|
154
|
+
.maytes-popup-loading__content {
|
|
155
|
+
display: flex;
|
|
156
|
+
flex-direction: column;
|
|
157
|
+
align-items: center;
|
|
158
|
+
gap: 1.5rem;
|
|
159
|
+
padding: 2rem;
|
|
160
|
+
text-align: center;
|
|
161
|
+
}
|
|
162
|
+
.maytes-popup-loading__logo { height: 2.75rem; width: auto; }
|
|
163
|
+
.maytes-popup-loading__spinner {
|
|
164
|
+
width: 2.5rem;
|
|
165
|
+
height: 2.5rem;
|
|
166
|
+
border: 4px solid rgba(255, 255, 255, 0.25);
|
|
167
|
+
border-top-color: ${l.brand.secondary};
|
|
168
|
+
border-radius: 50%;
|
|
169
|
+
animation: maytes-checkout-button-spin 0.8s linear infinite;
|
|
170
|
+
}
|
|
171
|
+
@keyframes maytes-checkout-button-spin {
|
|
172
|
+
to { transform: rotate(360deg); }
|
|
173
|
+
}
|
|
174
|
+
.maytes-popup-loading__text { margin: 0; font-size: 1.05rem; font-weight: 500; }
|
|
175
|
+
.maytes-popup-loading__slow {
|
|
176
|
+
margin: 0;
|
|
177
|
+
font-size: 0.9rem;
|
|
178
|
+
font-weight: 400;
|
|
179
|
+
color: rgba(255, 255, 255, 0.75);
|
|
180
|
+
max-width: 22rem;
|
|
181
|
+
}
|
|
182
|
+
.maytes-popup-loading__slow[hidden] { display: none; }
|
|
183
|
+
@media (prefers-reduced-motion: reduce) {
|
|
184
|
+
.maytes-popup-loading__spinner { animation: none; }
|
|
185
|
+
}
|
|
186
|
+
`;function le(){return window[se]??0}function de(e){let t=window;t[se]=e}function pe(e){let t=le()+1;if(de(t),document.head.querySelector(ce)!==null)return;let o=document.createElement("style");o.setAttribute(ae,f),e!==void 0&&e!==""&&o.setAttribute("nonce",e),o.textContent=Be,document.head.appendChild(o)}function me(){let e=Math.max(0,le()-1);if(de(e),e>0)return;let t=document.head.querySelector(ce);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){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 v(e){e.popupPollHandle!==null&&(clearInterval(e.popupPollHandle),e.popupPollHandle=null)}function ze(e,t){v(e),e.popupPollHandle=setInterval(()=>{let o=e.popupWindow;(o===null||o.closed)&&(v(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=ue,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=h("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 E(e,t="renderButton"){if(e!=="redirect"&&e!=="popup")throw new c(s.Config,`${t}({ mode }) must be 'redirect' or 'popup'`);return e}function x(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 M(e){y(e),$(e,!1)}function he(e,t){_(t),v(e),e.popupWindow===t&&(e.popupWindow=null),M(e)}function et(e){if(e.restoreDetach!==null)return;let t=n=>{n.persisted&&(o(),M(e))},o=()=>{window.removeEventListener("pageshow",t),e.restoreDetach=null};window.addEventListener("pageshow",t),e.restoreDetach=o}function tt(e,t,o,n){let r=w(o,!1);return n&&(r.target==="self"||r.target==="top")?($(e,!1),et(e)):M(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,()=>{M(e),document.dispatchEvent(new CustomEvent("maytes:checkout-closed",{detail:t}))}),o)}async function S(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 _(i),{outcome:"closed"};if(!Ve(u)){he(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"}:(he(e,i),console.error("[maytes/checkout-button] createCheckout failed:",u),B(r,"create-checkout-rejected",u),{outcome:"failed",reason:"create-checkout-rejected"})}}function ye(){let e=h("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 fe(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=x(o.redirectOverlay);pe(e.config.cspNonce);let d=o.label??"Split with",i=o.block===!0,u=E(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} `),b=ye();a.appendChild(m),a.appendChild(b);let ke=k=>{if(k){a.setAttribute("aria-disabled","true"),a.setAttribute("aria-busy","true");let g=nt();b.replaceWith(g),b=g}else{a.removeAttribute("aria-disabled"),a.removeAttribute("aria-busy");let g=ye();b.replaceWith(g),b=g}},I=!1,H=k=>{I&&(ke(k),k||(I=!1))};e.busyViews.add(H);let V=()=>{e.busy||e.destroyed||(I=!0,S(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),me())};return e.teardowns.add(O),O}function be(){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 be()}return be()}function ve(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=ve(e,t),{checkoutUrl:n,redirectToCheckout:r}=re(o.config.environment,o.config.baseUrl);return{instanceId:o.instanceId,renderButton(i,u){return fe(o,i,u)},openCheckout(i){if(o.destroyed)throw new c(s.Config,"openCheckout() called on a destroyed Maytes instance");let u=E(i?.mode??"popup","openCheckout"),a=x(i?.redirectOverlay,"openCheckout");return S(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,v(o),o.restoreDetach?.(),y(o),o.popupNavigated||_(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);})();
|
|
187
|
+
window.Maytes = MaytesCheckoutButton.Maytes;
|
|
188
|
+
//# sourceMappingURL=checkout-button.js.map
|