@coincircuit/checkout 0.2.0 → 0.2.2

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.
@@ -44,6 +44,19 @@ function createMessageListener(allowedOrigin, handlers) {
44
44
 
45
45
  // src/utils.ts
46
46
  var DEFAULT_BASE_URL = "https://checkout.coincircuit.io";
47
+ var ALLOWED_BASE_URLS = [
48
+ "https://checkout.coincircuit.io",
49
+ "https://sandbox-checkout.coincircuit.io"
50
+ ];
51
+ function validateBaseUrl(url) {
52
+ const normalized = url.replace(/\/+$/, "");
53
+ if (!ALLOWED_BASE_URLS.includes(normalized)) {
54
+ throw new Error(
55
+ `CoinCircuitCheckout: invalid baseUrl "${url}". Must be one of: ${ALLOWED_BASE_URLS.join(", ")}`
56
+ );
57
+ }
58
+ return normalized;
59
+ }
47
60
  function buildCheckoutUrl(baseUrl, reference, theme) {
48
61
  const url = new URL(`/pay/${encodeURIComponent(reference)}`, baseUrl);
49
62
  url.searchParams.set("embed", "true");
@@ -83,36 +96,36 @@ function injectStyles() {
83
96
  }
84
97
  #${OVERLAY_ID} .cc-modal {
85
98
  position: relative;
86
- width: 100%;
87
- max-width: 450px;
88
- height: 90vh;
89
- max-height: 700px;
99
+ width: min(600px, 96vw);
100
+ max-width: 600px;
101
+ height: min(88vh, 800px);
90
102
  border-radius: 16px;
91
- overflow: hidden;
92
103
  background: #fff;
93
104
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
94
105
  }
95
106
  #${OVERLAY_ID} .cc-close {
96
- position: absolute;
97
- top: 12px;
98
- right: 12px;
99
- z-index: 10;
100
- width: 32px;
101
- height: 32px;
107
+ position: fixed;
108
+ top: 16px;
109
+ right: 16px;
110
+ z-index: 1000000;
111
+ width: 36px;
112
+ height: 36px;
102
113
  border: none;
103
114
  border-radius: 50%;
104
- background: rgba(0, 0, 0, 0.5);
115
+ background: rgba(255, 255, 255, 0.15);
116
+ backdrop-filter: blur(8px);
105
117
  color: #fff;
106
- font-size: 18px;
118
+ font-size: 20px;
107
119
  line-height: 1;
108
120
  cursor: pointer;
109
121
  display: flex;
110
122
  align-items: center;
111
123
  justify-content: center;
112
- transition: background 0.15s;
124
+ transition: background 0.15s, transform 0.15s;
113
125
  }
114
126
  #${OVERLAY_ID} .cc-close:hover {
115
- background: rgba(0, 0, 0, 0.7);
127
+ background: rgba(255, 255, 255, 0.25);
128
+ transform: scale(1.1);
116
129
  }
117
130
  #${OVERLAY_ID} iframe {
118
131
  width: 100%;
@@ -138,11 +151,11 @@ function injectStyles() {
138
151
  animation: cc-spin 0.8s linear infinite;
139
152
  }
140
153
  @keyframes cc-spin { to { transform: rotate(360deg); } }
141
- @media (max-width: 480px) {
154
+ @media (max-width: 720px) {
142
155
  #${OVERLAY_ID} .cc-modal {
156
+ width: 100%;
143
157
  max-width: 100%;
144
- height: 100vh;
145
- max-height: 100vh;
158
+ height: 100dvh;
146
159
  border-radius: 0;
147
160
  }
148
161
  }
@@ -173,9 +186,15 @@ function createOverlay(checkoutUrl, onCloseClick) {
173
186
  iframe.setAttribute("referrerpolicy", "strict-origin-when-cross-origin");
174
187
  iframe.setAttribute("title", "CoinCircuit Checkout");
175
188
  iframe.setAttribute("allow", "payment");
189
+ const closeBtn = document.createElement("button");
190
+ closeBtn.className = "cc-close";
191
+ closeBtn.setAttribute("aria-label", "Close checkout");
192
+ closeBtn.textContent = "\u2715";
193
+ closeBtn.addEventListener("click", onCloseClick);
176
194
  modal.appendChild(spinner);
177
195
  modal.appendChild(iframe);
178
196
  overlay.appendChild(modal);
197
+ overlay.appendChild(closeBtn);
179
198
  return { overlay, iframe };
180
199
  }
181
200
  function showOverlay(overlay) {
@@ -240,7 +259,7 @@ var CoinCircuitCheckout = class {
240
259
  removeMessageListener = null;
241
260
  loadTimeout = null;
242
261
  constructor(config = {}) {
243
- this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
262
+ this.baseUrl = config.baseUrl ? validateBaseUrl(config.baseUrl) : DEFAULT_BASE_URL;
244
263
  this.origin = extractOrigin(this.baseUrl);
245
264
  this.publicKey = config.publicKey;
246
265
  }
@@ -267,7 +286,7 @@ var CoinCircuitCheckout = class {
267
286
  this.overlay = overlay;
268
287
  this.loadTimeout = setTimeout(() => {
269
288
  showErrorToast(
270
- "Checkout failed to load. The checkout service may be unavailable or blocked by security policy."
289
+ "Checkout failed to load."
271
290
  );
272
291
  this.close();
273
292
  }, 15e3);
package/dist/index.cjs CHANGED
@@ -75,6 +75,19 @@ function createMessageListener(allowedOrigin, handlers) {
75
75
 
76
76
  // src/utils.ts
77
77
  var DEFAULT_BASE_URL = "https://checkout.coincircuit.io";
78
+ var ALLOWED_BASE_URLS = [
79
+ "https://checkout.coincircuit.io",
80
+ "https://sandbox-checkout.coincircuit.io"
81
+ ];
82
+ function validateBaseUrl(url) {
83
+ const normalized = url.replace(/\/+$/, "");
84
+ if (!ALLOWED_BASE_URLS.includes(normalized)) {
85
+ throw new Error(
86
+ `CoinCircuitCheckout: invalid baseUrl "${url}". Must be one of: ${ALLOWED_BASE_URLS.join(", ")}`
87
+ );
88
+ }
89
+ return normalized;
90
+ }
78
91
  function buildCheckoutUrl(baseUrl, reference, theme) {
79
92
  const url = new URL(`/pay/${encodeURIComponent(reference)}`, baseUrl);
80
93
  url.searchParams.set("embed", "true");
@@ -114,36 +127,36 @@ function injectStyles() {
114
127
  }
115
128
  #${OVERLAY_ID} .cc-modal {
116
129
  position: relative;
117
- width: 100%;
118
- max-width: 450px;
119
- height: 90vh;
120
- max-height: 700px;
130
+ width: min(600px, 96vw);
131
+ max-width: 600px;
132
+ height: min(88vh, 800px);
121
133
  border-radius: 16px;
122
- overflow: hidden;
123
134
  background: #fff;
124
135
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
125
136
  }
126
137
  #${OVERLAY_ID} .cc-close {
127
- position: absolute;
128
- top: 12px;
129
- right: 12px;
130
- z-index: 10;
131
- width: 32px;
132
- height: 32px;
138
+ position: fixed;
139
+ top: 16px;
140
+ right: 16px;
141
+ z-index: 1000000;
142
+ width: 36px;
143
+ height: 36px;
133
144
  border: none;
134
145
  border-radius: 50%;
135
- background: rgba(0, 0, 0, 0.5);
146
+ background: rgba(255, 255, 255, 0.15);
147
+ backdrop-filter: blur(8px);
136
148
  color: #fff;
137
- font-size: 18px;
149
+ font-size: 20px;
138
150
  line-height: 1;
139
151
  cursor: pointer;
140
152
  display: flex;
141
153
  align-items: center;
142
154
  justify-content: center;
143
- transition: background 0.15s;
155
+ transition: background 0.15s, transform 0.15s;
144
156
  }
145
157
  #${OVERLAY_ID} .cc-close:hover {
146
- background: rgba(0, 0, 0, 0.7);
158
+ background: rgba(255, 255, 255, 0.25);
159
+ transform: scale(1.1);
147
160
  }
148
161
  #${OVERLAY_ID} iframe {
149
162
  width: 100%;
@@ -169,11 +182,11 @@ function injectStyles() {
169
182
  animation: cc-spin 0.8s linear infinite;
170
183
  }
171
184
  @keyframes cc-spin { to { transform: rotate(360deg); } }
172
- @media (max-width: 480px) {
185
+ @media (max-width: 720px) {
173
186
  #${OVERLAY_ID} .cc-modal {
187
+ width: 100%;
174
188
  max-width: 100%;
175
- height: 100vh;
176
- max-height: 100vh;
189
+ height: 100dvh;
177
190
  border-radius: 0;
178
191
  }
179
192
  }
@@ -204,9 +217,15 @@ function createOverlay(checkoutUrl, onCloseClick) {
204
217
  iframe.setAttribute("referrerpolicy", "strict-origin-when-cross-origin");
205
218
  iframe.setAttribute("title", "CoinCircuit Checkout");
206
219
  iframe.setAttribute("allow", "payment");
220
+ const closeBtn = document.createElement("button");
221
+ closeBtn.className = "cc-close";
222
+ closeBtn.setAttribute("aria-label", "Close checkout");
223
+ closeBtn.textContent = "\u2715";
224
+ closeBtn.addEventListener("click", onCloseClick);
207
225
  modal.appendChild(spinner);
208
226
  modal.appendChild(iframe);
209
227
  overlay.appendChild(modal);
228
+ overlay.appendChild(closeBtn);
210
229
  return { overlay, iframe };
211
230
  }
212
231
  function showOverlay(overlay) {
@@ -271,7 +290,7 @@ var CoinCircuitCheckout = class {
271
290
  removeMessageListener = null;
272
291
  loadTimeout = null;
273
292
  constructor(config = {}) {
274
- this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
293
+ this.baseUrl = config.baseUrl ? validateBaseUrl(config.baseUrl) : DEFAULT_BASE_URL;
275
294
  this.origin = extractOrigin(this.baseUrl);
276
295
  this.publicKey = config.publicKey;
277
296
  }
@@ -298,7 +317,7 @@ var CoinCircuitCheckout = class {
298
317
  this.overlay = overlay;
299
318
  this.loadTimeout = setTimeout(() => {
300
319
  showErrorToast(
301
- "Checkout failed to load. The checkout service may be unavailable or blocked by security policy."
320
+ "Checkout failed to load."
302
321
  );
303
322
  this.close();
304
323
  }, 15e3);
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  buildCheckoutUrl,
6
6
  createMessageListener,
7
7
  extractOrigin
8
- } from "./chunk-VYS76EOY.js";
8
+ } from "./chunk-DG6Y255K.js";
9
9
  export {
10
10
  CHECKOUT_MESSAGE_TYPES,
11
11
  CoinCircuitCheckout,
package/dist/react.cjs CHANGED
@@ -71,6 +71,19 @@ function createMessageListener(allowedOrigin, handlers) {
71
71
 
72
72
  // src/utils.ts
73
73
  var DEFAULT_BASE_URL = "https://checkout.coincircuit.io";
74
+ var ALLOWED_BASE_URLS = [
75
+ "https://checkout.coincircuit.io",
76
+ "https://sandbox-checkout.coincircuit.io"
77
+ ];
78
+ function validateBaseUrl(url) {
79
+ const normalized = url.replace(/\/+$/, "");
80
+ if (!ALLOWED_BASE_URLS.includes(normalized)) {
81
+ throw new Error(
82
+ `CoinCircuitCheckout: invalid baseUrl "${url}". Must be one of: ${ALLOWED_BASE_URLS.join(", ")}`
83
+ );
84
+ }
85
+ return normalized;
86
+ }
74
87
  function buildCheckoutUrl(baseUrl, reference, theme) {
75
88
  const url = new URL(`/pay/${encodeURIComponent(reference)}`, baseUrl);
76
89
  url.searchParams.set("embed", "true");
@@ -110,36 +123,36 @@ function injectStyles() {
110
123
  }
111
124
  #${OVERLAY_ID} .cc-modal {
112
125
  position: relative;
113
- width: 100%;
114
- max-width: 450px;
115
- height: 90vh;
116
- max-height: 700px;
126
+ width: min(600px, 96vw);
127
+ max-width: 600px;
128
+ height: min(88vh, 800px);
117
129
  border-radius: 16px;
118
- overflow: hidden;
119
130
  background: #fff;
120
131
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
121
132
  }
122
133
  #${OVERLAY_ID} .cc-close {
123
- position: absolute;
124
- top: 12px;
125
- right: 12px;
126
- z-index: 10;
127
- width: 32px;
128
- height: 32px;
134
+ position: fixed;
135
+ top: 16px;
136
+ right: 16px;
137
+ z-index: 1000000;
138
+ width: 36px;
139
+ height: 36px;
129
140
  border: none;
130
141
  border-radius: 50%;
131
- background: rgba(0, 0, 0, 0.5);
142
+ background: rgba(255, 255, 255, 0.15);
143
+ backdrop-filter: blur(8px);
132
144
  color: #fff;
133
- font-size: 18px;
145
+ font-size: 20px;
134
146
  line-height: 1;
135
147
  cursor: pointer;
136
148
  display: flex;
137
149
  align-items: center;
138
150
  justify-content: center;
139
- transition: background 0.15s;
151
+ transition: background 0.15s, transform 0.15s;
140
152
  }
141
153
  #${OVERLAY_ID} .cc-close:hover {
142
- background: rgba(0, 0, 0, 0.7);
154
+ background: rgba(255, 255, 255, 0.25);
155
+ transform: scale(1.1);
143
156
  }
144
157
  #${OVERLAY_ID} iframe {
145
158
  width: 100%;
@@ -165,11 +178,11 @@ function injectStyles() {
165
178
  animation: cc-spin 0.8s linear infinite;
166
179
  }
167
180
  @keyframes cc-spin { to { transform: rotate(360deg); } }
168
- @media (max-width: 480px) {
181
+ @media (max-width: 720px) {
169
182
  #${OVERLAY_ID} .cc-modal {
183
+ width: 100%;
170
184
  max-width: 100%;
171
- height: 100vh;
172
- max-height: 100vh;
185
+ height: 100dvh;
173
186
  border-radius: 0;
174
187
  }
175
188
  }
@@ -200,9 +213,15 @@ function createOverlay(checkoutUrl, onCloseClick) {
200
213
  iframe.setAttribute("referrerpolicy", "strict-origin-when-cross-origin");
201
214
  iframe.setAttribute("title", "CoinCircuit Checkout");
202
215
  iframe.setAttribute("allow", "payment");
216
+ const closeBtn = document.createElement("button");
217
+ closeBtn.className = "cc-close";
218
+ closeBtn.setAttribute("aria-label", "Close checkout");
219
+ closeBtn.textContent = "\u2715";
220
+ closeBtn.addEventListener("click", onCloseClick);
203
221
  modal.appendChild(spinner);
204
222
  modal.appendChild(iframe);
205
223
  overlay.appendChild(modal);
224
+ overlay.appendChild(closeBtn);
206
225
  return { overlay, iframe };
207
226
  }
208
227
  function showOverlay(overlay) {
@@ -267,7 +286,7 @@ var CoinCircuitCheckout = class {
267
286
  removeMessageListener = null;
268
287
  loadTimeout = null;
269
288
  constructor(config = {}) {
270
- this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
289
+ this.baseUrl = config.baseUrl ? validateBaseUrl(config.baseUrl) : DEFAULT_BASE_URL;
271
290
  this.origin = extractOrigin(this.baseUrl);
272
291
  this.publicKey = config.publicKey;
273
292
  }
@@ -294,7 +313,7 @@ var CoinCircuitCheckout = class {
294
313
  this.overlay = overlay;
295
314
  this.loadTimeout = setTimeout(() => {
296
315
  showErrorToast(
297
- "Checkout failed to load. The checkout service may be unavailable or blocked by security policy."
316
+ "Checkout failed to load."
298
317
  );
299
318
  this.close();
300
319
  }, 15e3);
package/dist/react.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CoinCircuitCheckout
3
- } from "./chunk-VYS76EOY.js";
3
+ } from "./chunk-DG6Y255K.js";
4
4
 
5
5
  // src/react.ts
6
6
  import { useRef, useCallback, useEffect, createElement } from "react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coincircuit/checkout",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Embed CoinCircuit checkout in your site via iframe, with vanilla JS and React support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",