@ton-pay/ui-react 0.2.0-beta.4 → 0.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/README.md +40 -41
- package/dist/index.d.mts +6 -176
- package/dist/index.d.ts +6 -176
- package/dist/index.js +208 -1839
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +184 -1815
- package/dist/index.mjs.map +1 -1
- package/dist/style-inject.d.mts +7 -0
- package/dist/style-inject.d.ts +7 -0
- package/dist/style-inject.js +30 -0
- package/dist/style-inject.js.map +1 -0
- package/dist/style-inject.mjs +30 -0
- package/dist/style-inject.mjs.map +1 -0
- package/package.json +11 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/components/ton-pay-button/TonPayButton.tsx
|
|
2
|
-
var _react = require('react'); var React6 = _interopRequireWildcard(_react); var React8 = _interopRequireWildcard(_react);
|
|
2
|
+
var _react = require('react'); var React6 = _interopRequireWildcard(_react); var React8 = _interopRequireWildcard(_react);
|
|
3
3
|
|
|
4
4
|
var _uireact = require('@tonconnect/ui-react');
|
|
5
5
|
|
|
@@ -25,7 +25,12 @@ async function getUserIp() {
|
|
|
25
25
|
// src/components/icons/index.tsx
|
|
26
26
|
|
|
27
27
|
var _jsxruntime = require('react/jsx-runtime');
|
|
28
|
-
var TonIcon = ({
|
|
28
|
+
var TonIcon = ({
|
|
29
|
+
size = 24,
|
|
30
|
+
bgColor = "#0098EA",
|
|
31
|
+
textColor = "white",
|
|
32
|
+
className
|
|
33
|
+
}) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
29
34
|
"svg",
|
|
30
35
|
{
|
|
31
36
|
width: size,
|
|
@@ -41,21 +46,14 @@ var TonIcon = ({ size = 24, className }) => /* @__PURE__ */ _jsxruntime.jsxs.cal
|
|
|
41
46
|
"path",
|
|
42
47
|
{
|
|
43
48
|
d: "M12 24C18.6274 24 24 18.6274 24 12C24 5.37257 18.6274 0 12 0C5.37257 0 0 5.37257 0 12C0 18.6274 5.37257 24 12 24Z",
|
|
44
|
-
fill:
|
|
45
|
-
}
|
|
46
|
-
),
|
|
47
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
48
|
-
"path",
|
|
49
|
-
{
|
|
50
|
-
d: "M12 24C18.6274 24 24 18.6274 24 12C24 5.37257 18.6274 0 12 0C5.37257 0 0 5.37257 0 12C0 18.6274 5.37257 24 12 24Z",
|
|
51
|
-
fill: "white"
|
|
49
|
+
fill: bgColor
|
|
52
50
|
}
|
|
53
51
|
),
|
|
54
52
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
55
53
|
"path",
|
|
56
54
|
{
|
|
57
55
|
d: "M16.0972 6.69763H7.9022C6.39543 6.69763 5.4404 8.32299 6.19846 9.63695L11.2561 18.4033C11.5862 18.9757 12.4133 18.9757 12.7433 18.4033L17.802 9.63695C18.559 8.32509 17.604 6.69763 16.0982 6.69763H16.0972ZM11.252 15.7744L10.1505 13.6426L7.49278 8.88922C7.31746 8.58497 7.53401 8.1951 7.90117 8.1951H11.251V15.7754L11.252 15.7744ZM16.5046 8.88819L13.8479 13.6437L12.7464 15.7744V8.19407H16.0962C16.4633 8.19407 16.6799 8.58395 16.5046 8.88819Z",
|
|
58
|
-
fill:
|
|
56
|
+
fill: textColor
|
|
59
57
|
}
|
|
60
58
|
)
|
|
61
59
|
] }),
|
|
@@ -139,8 +137,24 @@ var CloseIcon = ({
|
|
|
139
137
|
"aria-hidden": true,
|
|
140
138
|
children: [
|
|
141
139
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { width: "32", height: "32", rx: "8", fill: "#F4F4F4" }),
|
|
142
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
143
|
-
|
|
140
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
141
|
+
"path",
|
|
142
|
+
{
|
|
143
|
+
d: "M8.99933 22.251L22.2501 9.00026",
|
|
144
|
+
stroke: "#7A7A7A",
|
|
145
|
+
strokeWidth: "1.5",
|
|
146
|
+
strokeLinecap: "round"
|
|
147
|
+
}
|
|
148
|
+
),
|
|
149
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
150
|
+
"path",
|
|
151
|
+
{
|
|
152
|
+
d: "M8.99933 9.08296L22.2501 22.3337",
|
|
153
|
+
stroke: "#7A7A7A",
|
|
154
|
+
strokeWidth: "1.5",
|
|
155
|
+
strokeLinecap: "round"
|
|
156
|
+
}
|
|
157
|
+
)
|
|
144
158
|
]
|
|
145
159
|
}
|
|
146
160
|
);
|
|
@@ -273,10 +287,7 @@ var ErrorDotIcon = ({
|
|
|
273
287
|
]
|
|
274
288
|
}
|
|
275
289
|
);
|
|
276
|
-
var CardIcon = ({
|
|
277
|
-
size = 20,
|
|
278
|
-
className
|
|
279
|
-
}) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
290
|
+
var CardIcon = ({ size = 20, className }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
280
291
|
"svg",
|
|
281
292
|
{
|
|
282
293
|
width: size,
|
|
@@ -287,15 +298,24 @@ var CardIcon = ({
|
|
|
287
298
|
className,
|
|
288
299
|
"aria-hidden": true,
|
|
289
300
|
children: [
|
|
290
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
291
|
-
|
|
301
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
302
|
+
"path",
|
|
303
|
+
{
|
|
304
|
+
d: "M15.4688 5H4.53125C3.68693 5 3 5.71369 3 6.59091V13.4091C3 14.2863 3.68693 15 4.53125 15H15.4688C16.3131 15 17 14.2863 17 13.4091V6.59091C17 5.71369 16.3131 5 15.4688 5ZM4.53125 5.90909H15.4688C15.8306 5.90909 16.125 6.21497 16.125 6.59091V7.5H3.875V6.59091C3.875 6.21497 4.16941 5.90909 4.53125 5.90909ZM15.4688 14.0909H4.53125C4.16941 14.0909 3.875 13.785 3.875 13.4091V8.40909H16.125V13.4091C16.125 13.785 15.8306 14.0909 15.4688 14.0909Z",
|
|
305
|
+
fill: "white"
|
|
306
|
+
}
|
|
307
|
+
),
|
|
308
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
309
|
+
"path",
|
|
310
|
+
{
|
|
311
|
+
d: "M6.33333 13H5.66667C5.2985 13 5 12.7015 5 12.3333V11.6667C5 11.2985 5.2985 11 5.66667 11H6.33333C6.7015 11 7 11.2985 7 11.6667V12.3333C7 12.7015 6.7015 13 6.33333 13Z",
|
|
312
|
+
fill: "white"
|
|
313
|
+
}
|
|
314
|
+
)
|
|
292
315
|
]
|
|
293
316
|
}
|
|
294
317
|
);
|
|
295
|
-
var CryptoIcon = ({
|
|
296
|
-
size = 20,
|
|
297
|
-
className
|
|
298
|
-
}) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
318
|
+
var CryptoIcon = ({ size = 20, className }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
299
319
|
"svg",
|
|
300
320
|
{
|
|
301
321
|
width: size,
|
|
@@ -305,19 +325,38 @@ var CryptoIcon = ({
|
|
|
305
325
|
xmlns: "http://www.w3.org/2000/svg",
|
|
306
326
|
className,
|
|
307
327
|
"aria-hidden": true,
|
|
308
|
-
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
328
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
329
|
+
"path",
|
|
330
|
+
{
|
|
331
|
+
d: "M14.3896 3.5H5.61006C3.99582 3.5 2.97267 5.24122 3.7848 6.64885L9.20318 16.0401C9.55683 16.6533 10.4429 16.6533 10.7965 16.0401L16.216 6.64885C17.027 5.24347 16.0028 3.5 14.3896 3.5ZM9.19879 13.2238L8.01872 10.9401L5.17144 5.84782C4.98361 5.52189 5.21561 5.10422 5.60896 5.10422H9.19772V13.225L9.19879 13.2238ZM14.826 5.84671L11.9798 10.9412L10.7998 13.2238V5.10312H14.3885C14.7818 5.10312 15.0138 5.52078 14.826 5.84671Z",
|
|
332
|
+
fill: "white"
|
|
333
|
+
}
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
var TonPayLogo = ({ className }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
338
|
+
"div",
|
|
339
|
+
{
|
|
340
|
+
className,
|
|
341
|
+
style: { display: "flex", alignItems: "center", gap: "4px" },
|
|
342
|
+
children: [
|
|
343
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TonIconBlue, { size: 26 }),
|
|
344
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
345
|
+
"span",
|
|
346
|
+
{
|
|
347
|
+
style: {
|
|
348
|
+
fontWeight: 600,
|
|
349
|
+
fontSize: "18px",
|
|
350
|
+
lineHeight: "24px",
|
|
351
|
+
color: "#000000",
|
|
352
|
+
letterSpacing: "-0.5px"
|
|
353
|
+
},
|
|
354
|
+
children: "Pay"
|
|
355
|
+
}
|
|
356
|
+
)
|
|
357
|
+
]
|
|
309
358
|
}
|
|
310
359
|
);
|
|
311
|
-
var TonPayLogo = ({ className }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className, style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
|
|
312
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TonIconBlue, { size: 26 }),
|
|
313
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: {
|
|
314
|
-
fontWeight: 600,
|
|
315
|
-
fontSize: "18px",
|
|
316
|
-
lineHeight: "24px",
|
|
317
|
-
color: "#000000",
|
|
318
|
-
letterSpacing: "-0.5px"
|
|
319
|
-
}, children: "Pay" })
|
|
320
|
-
] });
|
|
321
360
|
|
|
322
361
|
// src/components/notification/Notification.tsx
|
|
323
362
|
|
|
@@ -394,7 +433,7 @@ var ErrorTransactionNotification = ({ text, className, style }) => {
|
|
|
394
433
|
|
|
395
434
|
// src/components/bottom-sheet/BottomSheet.css
|
|
396
435
|
var _styleinject = require('#style-inject'); var _styleinject2 = _interopRequireDefault(_styleinject);
|
|
397
|
-
_styleinject2.default.call(void 0, ".bottom-sheet-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n z-index: 1000;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n animation: fadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.bottom-sheet-backdrop.closing {\n animation: fadeOut 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n@keyframes fadeIn {\n from {\n opacity: 0;\n backdrop-filter: blur(0px);\n -webkit-backdrop-filter: blur(0px);\n }\n to {\n opacity: 1;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n }\n}\n@keyframes fadeOut {\n from {\n opacity: 1;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n }\n to {\n opacity: 0;\n backdrop-filter: blur(0px);\n -webkit-backdrop-filter: blur(0px);\n }\n}\n.bottom-sheet {\n position: relative;\n width: 100%;\n max-width: 100%;\n background-color: #ffffff;\n border-radius: 20px 20px 0 0;\n box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n touch-action: none;\n transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n will-change: height, transform;\n transform: translateY(0);\n}\n.bottom-sheet.dragging {\n transition: none;\n}\n.bottom-sheet.closing {\n animation: slideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n@keyframes slideDown {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(100%);\n }\n}\n.bottom-sheet-handle-container {\n width: 100%;\n padding: 12px 0 8px;\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n cursor: grab;\n}\n.bottom-sheet-handle-container:active {\n cursor: grabbing;\n}\n.bottom-sheet-handle {\n width: 80px;\n height: 4px;\n background-color: #d1d5db;\n border-radius: 2px;\n cursor: pointer;\n}\n.bottom-sheet-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overscroll-behavior: contain;\n padding: 0;\n min-height: 0;\n}\n.bottom-sheet-content.scrolling {\n touch-action: pan-y;\n}\n@media (prefers-color-scheme: dark) {\n .bottom-sheet {\n background-color: #
|
|
436
|
+
_styleinject2.default.call(void 0, ".bottom-sheet-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n z-index: 1000;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n animation: fadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.bottom-sheet-backdrop.closing {\n animation: fadeOut 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n@keyframes fadeIn {\n from {\n opacity: 0;\n backdrop-filter: blur(0px);\n -webkit-backdrop-filter: blur(0px);\n }\n to {\n opacity: 1;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n }\n}\n@keyframes fadeOut {\n from {\n opacity: 1;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n }\n to {\n opacity: 0;\n backdrop-filter: blur(0px);\n -webkit-backdrop-filter: blur(0px);\n }\n}\n.bottom-sheet {\n position: relative;\n width: 100%;\n max-width: 100%;\n background-color: #ffffff;\n border-radius: 20px 20px 0 0;\n box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n touch-action: none;\n transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n will-change: height, transform;\n transform: translateY(0);\n}\n.bottom-sheet.dragging {\n transition: none;\n}\n.bottom-sheet.closing {\n animation: slideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n@keyframes slideDown {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(100%);\n }\n}\n.bottom-sheet-handle-container {\n width: 100%;\n padding: 12px 0 8px;\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n cursor: grab;\n}\n.bottom-sheet-handle-container:active {\n cursor: grabbing;\n}\n.bottom-sheet-handle {\n width: 80px;\n height: 4px;\n background-color: #d1d5db;\n border-radius: 2px;\n cursor: pointer;\n}\n.bottom-sheet-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overscroll-behavior: contain;\n padding: 0;\n min-height: 0;\n}\n.bottom-sheet-content.scrolling {\n touch-action: pan-y;\n}\n@media (prefers-color-scheme: dark) {\n .bottom-sheet {\n background-color: #1c2633;\n box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.4);\n }\n .bottom-sheet-handle {\n background-color: #4b5563;\n }\n}\n");
|
|
398
437
|
|
|
399
438
|
// src/components/bottom-sheet/BottomSheet.tsx
|
|
400
439
|
|
|
@@ -513,7 +552,10 @@ var BottomSheet = ({
|
|
|
513
552
|
);
|
|
514
553
|
const snapToDetent = _react.useCallback.call(void 0,
|
|
515
554
|
(detentIndex) => {
|
|
516
|
-
const clampedIndex = Math.max(
|
|
555
|
+
const clampedIndex = Math.max(
|
|
556
|
+
0,
|
|
557
|
+
Math.min(detentIndex, detents.length - 1)
|
|
558
|
+
);
|
|
517
559
|
isSnappingRef.current = true;
|
|
518
560
|
targetDetentRef.current = clampedIndex;
|
|
519
561
|
const viewportHeight = window.innerHeight;
|
|
@@ -562,10 +604,16 @@ var BottomSheet = ({
|
|
|
562
604
|
if (isDraggingDown && enableSwipeToClose) {
|
|
563
605
|
newHeight = Math.max(0, Math.min(maxDetentHeight, newHeight));
|
|
564
606
|
} else {
|
|
565
|
-
newHeight = Math.max(
|
|
607
|
+
newHeight = Math.max(
|
|
608
|
+
minDetentHeight,
|
|
609
|
+
Math.min(maxDetentHeight, newHeight)
|
|
610
|
+
);
|
|
566
611
|
}
|
|
567
612
|
} else {
|
|
568
|
-
newHeight = Math.max(
|
|
613
|
+
newHeight = Math.max(
|
|
614
|
+
minDetentHeight,
|
|
615
|
+
Math.min(maxDetentHeight, newHeight)
|
|
616
|
+
);
|
|
569
617
|
}
|
|
570
618
|
return newHeight;
|
|
571
619
|
},
|
|
@@ -577,7 +625,7 @@ var BottomSheet = ({
|
|
|
577
625
|
const touch = e.touches[0];
|
|
578
626
|
if (!touch) return;
|
|
579
627
|
const deltaY = touch.clientY - touchStartYRef.current;
|
|
580
|
-
const currentScrollTop = _nullishCoalesce(_optionalChain([contentRef, 'access',
|
|
628
|
+
const currentScrollTop = _nullishCoalesce(_optionalChain([contentRef, 'access', _ => _.current, 'optionalAccess', _2 => _2.scrollTop]), () => ( 0));
|
|
581
629
|
const isContentScrollable = contentRef.current ? contentRef.current.scrollHeight > contentRef.current.clientHeight : false;
|
|
582
630
|
if (!contentRef.current) return;
|
|
583
631
|
const touchTarget = e.target;
|
|
@@ -701,14 +749,28 @@ var BottomSheet = ({
|
|
|
701
749
|
if (isAtMaxDetent) {
|
|
702
750
|
newHeight = Math.max(0, Math.min(maxDetentHeight, newHeight));
|
|
703
751
|
} else if (isAtMinDetent) {
|
|
704
|
-
newHeight = Math.max(
|
|
752
|
+
newHeight = Math.max(
|
|
753
|
+
minDetentHeight,
|
|
754
|
+
Math.min(maxDetentHeight, newHeight)
|
|
755
|
+
);
|
|
705
756
|
} else {
|
|
706
|
-
newHeight = Math.max(
|
|
757
|
+
newHeight = Math.max(
|
|
758
|
+
minDetentHeight,
|
|
759
|
+
Math.min(maxDetentHeight, newHeight)
|
|
760
|
+
);
|
|
707
761
|
}
|
|
708
762
|
setSheetHeight(newHeight);
|
|
709
763
|
setCurrentY(e.clientY);
|
|
710
764
|
},
|
|
711
|
-
[
|
|
765
|
+
[
|
|
766
|
+
isOpen,
|
|
767
|
+
isDragging,
|
|
768
|
+
startY,
|
|
769
|
+
currentDetent,
|
|
770
|
+
detents,
|
|
771
|
+
getDetentValue,
|
|
772
|
+
isClosing
|
|
773
|
+
]
|
|
712
774
|
);
|
|
713
775
|
const handleMouseUp = _react.useCallback.call(void 0, () => {
|
|
714
776
|
if (!isOpen || !isDragging || isClosing) return;
|
|
@@ -891,7 +953,7 @@ var BottomSheet_default = BottomSheet;
|
|
|
891
953
|
|
|
892
954
|
// src/components/payment-modal/PaymentModal.css
|
|
893
955
|
|
|
894
|
-
_styleinject2.default.call(void 0, '.pm-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n font-family: "Inter", sans-serif;\n color: #000000;\n --pm-bg: #FFFFFF;\n --pm-text: #000000;\n --pm-text-secondary: #666666;\n --pm-text-muted: #8C8C8C;\n --pm-border: rgba(0, 0, 0, 0.1);\n --pm-order-bg: #E9F5FA;\n --pm-order-border: rgba(0, 100, 153, 0.03);\n --pm-order-text: #004062;\n --pm-hover-bg: #F9F9F9;\n --pm-iframe-bg: #f9f9f9;\n --pm-spinner-track: #E5E7EB;\n --pm-actions-border: hsl(0, 0%, 92%);\n}\n@media (prefers-color-scheme: dark) {\n .pm-content {\n color: #FFFFFF;\n --pm-bg: #1f2937;\n --pm-text: #FFFFFF;\n --pm-text-secondary: #9CA3AF;\n --pm-text-muted: #6B7280;\n --pm-border: rgba(255, 255, 255, 0.1);\n --pm-order-bg: rgba(255, 255, 255, 0.05);\n --pm-order-border: rgba(255, 255, 255, 0.1);\n --pm-order-text: #FFFFFF;\n --pm-hover-bg: rgba(255, 255, 255, 0.05);\n --pm-iframe-bg: #111827;\n --pm-spinner-track: #374151;\n --pm-actions-border: rgba(255, 255, 255, 0.1);\n }\n}\n.pm-header {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n padding: 16px;\n box-sizing: border-box;\n position: relative;\n}\n.bottom-sheet .pm-header {\n padding: 0 16px;\n}\n.pm-header-left,\n.pm-header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 40px;\n}\n.pm-header-right {\n justify-content: flex-end;\n}\n.pm-title {\n font-weight: 600;\n font-size: 18px;\n line-height: 22px;\n text-align: center;\n flex: 1;\n}\n.pm-close-btn,\n.pm-back-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--pm-text, #000000);\n opacity: 0.6;\n}\n.pm-close-btn:hover,\n.pm-back-btn:hover {\n opacity: 1;\n}\n.pm-body-main {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n padding: 0;\n gap: 0;\n box-sizing: border-box;\n}\n.pm-main-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n padding: 0 16px;\n}\n.pm-main-title {\n font-size: 18px;\n font-weight: 600;\n line-height: 20px;\n text-align: center;\n margin: 0 0 8px;\n color: var(--pm-text, #000000);\n}\n.pm-amount-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n margin-bottom: 16px;\n}\n.pm-amount-label {\n font-weight: 500;\n font-size: 12px;\n line-height: 15px;\n color: var(--pm-text-muted, #8C8C8C);\n}\n.pm-amount-value {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 24px;\n line-height: 29px;\n color: var(--pm-text, #000000);\n}\n.pm-order-info {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 36px;\n padding: 8px 16px;\n margin-bottom: 24px;\n gap: 4px;\n background: var(--pm-order-bg, #E9F5FA);\n border-radius: 9px;\n box-sizing: border-box;\n border: 1px solid var(--pm-order-border, rgba(0, 100, 153, 0.03));\n}\n.pm-order-text {\n font-family: "Inter", sans-serif;\n font-style: normal;\n font-weight: 400;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n color: var(--pm-order-text, #004062);\n flex: none;\n}\n.pm-actions-card {\n width: 100%;\n background: #F9F9F9;\n border-top: 1px solid var(--pm-actions-border, hsl(0, 0%, 92%));\n padding: 16px;\n box-sizing: border-box;\n}\n@media (prefers-color-scheme: dark) {\n .pm-actions-card {\n background: var(--pm-hover-bg, rgba(255, 255, 255, 0.05));\n }\n}\n.pm-actions {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n}\n.pm-btn {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n padding: 13px 10px 10px;\n gap: 4px;\n width: 100%;\n height: 44px;\n border-radius: 8px;\n border: none;\n cursor: pointer;\n font-weight: 500;\n font-size: 14px;\n line-height: 19px;\n transition: opacity 0.2s;\n}\n.pm-btn:hover {\n opacity: 0.9;\n}\n.pm-btn-primary {\n background: #0098EA;\n color: #FFFFFF;\n}\n.pm-btn-black {\n background: #000000;\n color: #FFFFFF;\n}\n.pm-btn.processing {\n background: #E6E6E6;\n color: #7A7A7A;\n cursor: default;\n}\n.pm-btn.processing:hover {\n opacity: 1;\n}\n.pm-footer {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n font-size: 12px;\n line-height: 15px;\n}\n.pm-footer-text {\n color: var(--pm-text-muted, #808080);\n}\n.pm-footer-link {\n color: #0098EA;\n cursor: pointer;\n text-decoration: none;\n}\n.pm-footer-link:hover {\n text-decoration: underline;\n}\n.pm-desktop-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.44);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease-out;\n}\n.pm-desktop-modal {\n width: 100%;\n max-width: 414px;\n margin: 16px;\n background: var(--pm-bg, #FFFFFF);\n border-radius: 32px;\n box-shadow: 0px 4px 24px rgba(0, 0, 0, 0.25);\n overflow: hidden;\n position: relative;\n animation: scaleIn 0.2s ease-out;\n}\n@media (prefers-color-scheme: dark) {\n .pm-desktop-modal {\n box-shadow: 0px 4px 32px rgba(0, 0, 0, 0.5);\n }\n}\n@keyframes scaleIn {\n from {\n transform: scale(0.95);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n}\n.pm-iframe-container {\n width: 100%;\n height: 100%;\n min-height: 400px;\n display: flex;\n flex-direction: column;\n background: var(--pm-iframe-bg, #f9f9f9);\n position: relative;\n}\n.pm-iframe-container iframe {\n flex: 1;\n width: 100%;\n height: 100%;\n border: none;\n display: block;\n}\n.pm-menu-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n background: var(--pm-bg, #FFFFFF);\n border: 1px solid var(--pm-border, rgba(0, 0, 0, 0.1));\n border-radius: 8px;\n box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);\n z-index: 1001;\n min-width: 150px;\n overflow: hidden;\n}\n@media (prefers-color-scheme: dark) {\n .pm-menu-dropdown {\n box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.4);\n }\n}\n.pm-menu-item {\n padding: 10px 16px;\n font-size: 14px;\n cursor: pointer;\n color: var(--pm-text, #000000);\n}\n.pm-menu-item:hover {\n background: var(--pm-hover-bg, #F9F9F9);\n}\n.pm-menu-item.danger {\n color: #E74C3C;\n}\n.pm-menu-item.disabled {\n cursor: default;\n color: var(--pm-text-muted, #8C8C8C);\n}\n.pm-menu-item.disabled:hover {\n background: transparent;\n}\n.icon-moonpay {\n background: #7D00FF;\n color: white;\n}\n.icon-onramper {\n background: #000000;\n color: white;\n}\n.icon-transak {\n background:\n linear-gradient(\n 120deg,\n #348BED 22.91%,\n #2B80E8 36.09%,\n #1461DB 60.25%,\n #0E57D7 66.11%);\n color: white;\n}\n.icon-mercurio {\n background: #000000;\n color: white;\n}\n.pm-success-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n.pm-success-icon {\n width: 64px;\n height: 64px;\n background: #0098EA;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 20px;\n color: white;\n}\n.pm-success-icon svg {\n width: 32px;\n height: 32px;\n}\n.pm-success-title {\n font-size: 24px;\n font-weight: 600;\n color: var(--pm-text, #000000);\n margin: 0 0 8px;\n}\n.pm-success-text {\n font-size: 16px;\n color: var(--pm-text-secondary, #666666);\n margin: 0;\n}\n.pm-error-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n.pm-error-icon {\n width: 64px;\n height: 64px;\n background: #E74C3C;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 20px;\n color: white;\n}\n.pm-error-icon svg {\n width: 32px;\n height: 32px;\n}\n.pm-error-title {\n font-size: 24px;\n font-weight: 600;\n color: var(--pm-text, #000000);\n margin: 0 0 8px;\n}\n.pm-error-text {\n font-size: 16px;\n color: var(--pm-text-secondary, #666666);\n margin: 0 0 24px;\n max-width: 300px;\n}\n.pm-error-actions {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n max-width: 280px;\n}\n.pm-error-inline {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 40px 20px;\n text-align: center;\n color: #E74C3C;\n}\n.pm-error-inline svg {\n width: 48px;\n height: 48px;\n margin-bottom: 16px;\n}\n.pm-error-inline p {\n margin: 0 0 20px;\n color: var(--pm-text-secondary, #666666);\n font-size: 14px;\n}\n.pm-btn-outline {\n background: transparent;\n color: #0098EA;\n border: 1px solid #0098EA;\n}\n.pm-btn-outline:hover {\n background: rgba(0, 152, 234, 0.08);\n}\n.pm-loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--pm-text-muted, #6b7280);\n}\n.pm-loading-container p {\n margin: 16px 0 0;\n font-size: 14px;\n}\n.pm-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--pm-iframe-bg, #f9f9f9);\n z-index: 1;\n}\n.pm-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--pm-spinner-track, #E5E7EB);\n border-top-color: #0098EA;\n border-radius: 50%;\n animation: pm-spin 0.8s linear infinite;\n}\n.pm-btn-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(122, 122, 122, 0.3);\n border-top-color: #7A7A7A;\n border-radius: 50%;\n animation: pm-spin 0.8s linear infinite;\n}\n@keyframes pm-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.pm-retry-link {\n font-family: "Inter", sans-serif;\n font-style: normal;\n font-weight: 400;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n color: #004062;\n margin-top: 0px;\n}\n.pm-retry-action {\n cursor: pointer;\n text-decoration: underline;\n color: #0098EA;\n}\n@media (prefers-color-scheme: dark) {\n .pm-header-left span {\n color: #ffffff !important;\n }\n .pm-close-btn svg rect {\n fill: rgba(255, 255, 255, 0.1) !important;\n }\n .pm-close-btn svg path {\n stroke: #ffffff !important;\n }\n .pm-retry-link {\n color: var(--pm-text-muted, #8C8C8C) !important;\n }\n .pm-btn.processing {\n background: rgba(255, 255, 255, 0.1) !important;\n color: var(--pm-text-muted, #8C8C8C) !important;\n }\n}\n');
|
|
956
|
+
_styleinject2.default.call(void 0, ':where(.pm-content, .pm-desktop-modal) {\n color: #000000;\n --pm-bg: #ffffff;\n --pm-text: #000000;\n --pm-text-secondary: #666666;\n --pm-text-muted: #8c8c8c;\n --pm-border: rgba(0, 0, 0, 0.1);\n --pm-order-bg: #e9f5fa;\n --pm-order-border: rgba(0, 100, 153, 0.03);\n --pm-order-text: #004062;\n --pm-hover-bg: #f9f9f9;\n --pm-iframe-bg: #f9f9f9;\n --pm-spinner-track: #e5e7eb;\n --pm-actions-border: hsl(0, 0%, 92%);\n}\n.pm-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n font-family: "Inter", sans-serif;\n}\n@media (prefers-color-scheme: dark) {\n :where(.pm-content, .pm-desktop-modal) {\n color: #ffffff;\n --pm-bg: #1f2937;\n --pm-text: #ffffff;\n --pm-text-secondary: #9ca3af;\n --pm-text-muted: #6b7280;\n --pm-border: rgba(255, 255, 255, 0.1);\n --pm-order-bg: rgba(255, 255, 255, 0.05);\n --pm-order-border: rgba(255, 255, 255, 0.1);\n --pm-order-text: #ffffff;\n --pm-hover-bg: rgba(255, 255, 255, 0.05);\n --pm-iframe-bg: #111827;\n --pm-spinner-track: #374151;\n --pm-actions-border: rgba(255, 255, 255, 0.1);\n }\n}\n.pm-header {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n padding: 16px;\n box-sizing: border-box;\n position: relative;\n}\n.bottom-sheet .pm-header {\n padding: 0 16px;\n}\n.pm-header-left,\n.pm-header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 40px;\n}\n.pm-header-right {\n justify-content: flex-end;\n}\n.pm-title {\n font-weight: 600;\n font-size: 18px;\n line-height: 22px;\n text-align: center;\n flex: 1;\n}\n.pm-close-btn,\n.pm-back-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--pm-text, #000000);\n opacity: 0.6;\n}\n.pm-close-btn:hover,\n.pm-back-btn:hover {\n opacity: 1;\n}\n.pm-body-main {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n padding: 0;\n gap: 0;\n box-sizing: border-box;\n}\n.pm-main-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n padding: 0 16px;\n}\n.pm-main-title {\n font-size: 18px;\n font-weight: 600;\n line-height: 20px;\n text-align: center;\n margin: 0 0 8px;\n color: var(--pm-text, #000000);\n}\n.pm-amount-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n margin-bottom: 16px;\n}\n.pm-amount-label {\n font-weight: 500;\n font-size: 12px;\n line-height: 15px;\n color: var(--pm-text-muted, #8c8c8c);\n}\n.pm-amount-value {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 24px;\n line-height: 29px;\n color: var(--pm-text, #000000);\n}\n.pm-order-info {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 36px;\n padding: 8px 16px;\n margin-bottom: 24px;\n gap: 4px;\n background: var(--pm-order-bg, #e9f5fa);\n border-radius: 9px;\n box-sizing: border-box;\n border: 1px solid var(--pm-order-border, rgba(0, 100, 153, 0.03));\n}\n.pm-order-text {\n font-family: "Inter", sans-serif;\n font-style: normal;\n font-weight: 400;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n color: var(--pm-order-text, #004062);\n flex: none;\n}\n.pm-actions-card {\n width: 100%;\n background: #f9f9f9;\n border-top: 1px solid var(--pm-actions-border, hsl(0, 0%, 92%));\n padding: 16px;\n box-sizing: border-box;\n}\n@media (prefers-color-scheme: dark) {\n .pm-actions-card {\n background: var(--pm-hover-bg, rgba(255, 255, 255, 0.05));\n }\n}\n.pm-actions {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n}\n.pm-btn {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n padding: 13px 10px 10px;\n gap: 4px;\n width: 100%;\n height: 47px;\n border-radius: 8px;\n border: none;\n cursor: pointer;\n font-weight: 500;\n font-size: 14px;\n line-height: 19px;\n transition: opacity 0.2s;\n}\n.pm-btn:hover {\n opacity: 0.9;\n}\n.pm-btn-primary {\n background: #0098ea;\n color: #ffffff;\n}\n.pm-btn-black {\n background: #000000;\n color: #ffffff;\n}\n.pm-btn.processing {\n background: #e6e6e6;\n color: #7a7a7a;\n cursor: default;\n}\n.pm-btn.processing:hover {\n opacity: 1;\n}\n.pm-footer {\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n font-size: 12px;\n line-height: 15px;\n}\n.pm-footer-text {\n color: var(--pm-text-muted, #808080);\n}\n.pm-footer-link {\n color: #0098ea;\n cursor: pointer;\n text-decoration: none;\n}\n.pm-footer-link:hover {\n text-decoration: underline;\n}\n.pm-desktop-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.44);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease-out;\n}\n.pm-desktop-modal {\n width: 100%;\n max-width: 414px;\n margin: 16px;\n background: var(--pm-bg, #ffffff);\n border-radius: 32px;\n box-shadow: 0px 4px 24px rgba(0, 0, 0, 0.25);\n overflow: hidden;\n position: relative;\n animation: scaleIn 0.2s ease-out;\n}\n@media (prefers-color-scheme: dark) {\n .pm-desktop-modal {\n box-shadow: 0px 4px 32px rgba(0, 0, 0, 0.5);\n }\n}\n@keyframes scaleIn {\n from {\n transform: scale(0.95);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n}\n.pm-iframe-container {\n width: 100%;\n height: 100%;\n min-height: 400px;\n display: flex;\n flex-direction: column;\n background: var(--pm-iframe-bg, #f9f9f9);\n position: relative;\n}\n.pm-iframe-container iframe {\n flex: 1;\n width: 100%;\n height: 100%;\n border: none;\n display: block;\n}\n.pm-menu-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n background: var(--pm-bg, #ffffff);\n border: 1px solid var(--pm-border, rgba(0, 0, 0, 0.1));\n border-radius: 8px;\n box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);\n z-index: 1001;\n min-width: 150px;\n overflow: hidden;\n}\n@media (prefers-color-scheme: dark) {\n .pm-menu-dropdown {\n box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.4);\n }\n}\n.pm-menu-item {\n padding: 10px 16px;\n font-size: 14px;\n cursor: pointer;\n color: var(--pm-text, #000000);\n}\n.pm-menu-item:hover {\n background: var(--pm-hover-bg, #f9f9f9);\n}\n.pm-menu-item.danger {\n color: #e74c3c;\n}\n.pm-menu-item.disabled {\n cursor: default;\n color: var(--pm-text-muted, #8c8c8c);\n}\n.pm-menu-item.disabled:hover {\n background: transparent;\n}\n.icon-moonpay {\n background: #7d00ff;\n color: white;\n}\n.icon-onramper {\n background: #000000;\n color: white;\n}\n.icon-transak {\n background:\n linear-gradient(\n 120deg,\n #348bed 22.91%,\n #2b80e8 36.09%,\n #1461db 60.25%,\n #0e57d7 66.11%);\n color: white;\n}\n.icon-mercurio {\n background: #000000;\n color: white;\n}\n.pm-success-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n.pm-success-icon {\n width: 64px;\n height: 64px;\n background: #0098ea;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 20px;\n color: white;\n}\n.pm-success-icon svg {\n width: 32px;\n height: 32px;\n}\n.pm-success-title {\n font-size: 24px;\n font-weight: 600;\n color: var(--pm-text, #000000);\n margin: 0 0 8px;\n}\n.pm-success-text {\n font-size: 16px;\n color: var(--pm-text-secondary, #666666);\n margin: 0;\n}\n.pm-error-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n.pm-error-icon {\n width: 64px;\n height: 64px;\n background: #e74c3c;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 20px;\n color: white;\n}\n.pm-error-icon svg {\n width: 32px;\n height: 32px;\n}\n.pm-error-title {\n font-size: 24px;\n font-weight: 600;\n color: var(--pm-text, #000000);\n margin: 0 0 8px;\n}\n.pm-error-text {\n font-size: 16px;\n color: var(--pm-text-secondary, #666666);\n margin: 0 0 24px;\n max-width: 300px;\n}\n.pm-error-actions {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n max-width: 280px;\n}\n.pm-error-inline {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 40px 20px;\n text-align: center;\n color: #e74c3c;\n}\n.pm-error-inline svg {\n width: 48px;\n height: 48px;\n margin-bottom: 16px;\n}\n.pm-error-inline p {\n margin: 0 0 20px;\n color: var(--pm-text-secondary, #666666);\n font-size: 14px;\n}\n.pm-btn-outline {\n background: transparent;\n color: #0098ea;\n border: 1px solid #0098ea;\n}\n.pm-btn-outline:hover {\n background: rgba(0, 152, 234, 0.08);\n}\n.pm-loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--pm-text-muted, #6b7280);\n}\n.pm-loading-container p {\n margin: 16px 0 0;\n font-size: 14px;\n}\n.pm-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--pm-iframe-bg, #f9f9f9);\n z-index: 1;\n}\n.pm-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--pm-spinner-track, #e5e7eb);\n border-top-color: #0098ea;\n border-radius: 50%;\n animation: pm-spin 0.8s linear infinite;\n}\n.pm-btn-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(122, 122, 122, 0.3);\n border-top-color: #7a7a7a;\n border-radius: 50%;\n animation: pm-spin 0.8s linear infinite;\n}\n@keyframes pm-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.pm-retry-link {\n font-family: "Inter", sans-serif;\n font-style: normal;\n font-weight: 400;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n color: #004062;\n margin-top: 0px;\n}\n.pm-retry-action {\n cursor: pointer;\n text-decoration: underline;\n color: #0098ea;\n}\n@media (prefers-color-scheme: dark) {\n .pm-header-left span {\n color: #ffffff !important;\n }\n .pm-close-btn svg rect {\n fill: rgba(255, 255, 255, 0.1) !important;\n }\n .pm-close-btn svg path {\n stroke: #ffffff !important;\n }\n .pm-retry-link {\n color: var(--pm-text-muted, #8c8c8c) !important;\n }\n .pm-btn.processing {\n background: rgba(255, 255, 255, 0.1) !important;\n color: var(--pm-text-muted, #8c8c8c) !important;\n }\n}\n');
|
|
895
957
|
|
|
896
958
|
// src/components/payment-modal/PaymentModal.tsx
|
|
897
959
|
|
|
@@ -928,7 +990,7 @@ var PaymentModal = ({
|
|
|
928
990
|
clearTimeout(iframeTimeoutRef.current);
|
|
929
991
|
}
|
|
930
992
|
setView("success");
|
|
931
|
-
_optionalChain([onPaymentSuccess, 'optionalCall',
|
|
993
|
+
_optionalChain([onPaymentSuccess, 'optionalCall', _3 => _3()]);
|
|
932
994
|
setTimeout(() => {
|
|
933
995
|
onClose();
|
|
934
996
|
}, 2e3);
|
|
@@ -950,26 +1012,26 @@ var PaymentModal = ({
|
|
|
950
1012
|
}, []);
|
|
951
1013
|
_react.useEffect.call(void 0, () => {
|
|
952
1014
|
const handleMessage = (event) => {
|
|
953
|
-
if (_optionalChain([event, 'access',
|
|
1015
|
+
if (_optionalChain([event, 'access', _4 => _4.data, 'optionalAccess', _5 => _5.type]) === "TONPAY_PAYMENT_SUCCESS") {
|
|
954
1016
|
handlePaymentSuccess();
|
|
955
1017
|
}
|
|
956
|
-
if (_optionalChain([event, 'access',
|
|
1018
|
+
if (_optionalChain([event, 'access', _6 => _6.data, 'optionalAccess', _7 => _7.type]) === "TONPAY_PAYMENT_ERROR") {
|
|
957
1019
|
const payload = event.data.payload;
|
|
958
|
-
handlePaymentError(_optionalChain([payload, 'optionalAccess',
|
|
1020
|
+
handlePaymentError(_optionalChain([payload, 'optionalAccess', _8 => _8.message]) || "Payment failed");
|
|
959
1021
|
}
|
|
960
|
-
if (_optionalChain([event, 'access',
|
|
1022
|
+
if (_optionalChain([event, 'access', _9 => _9.data, 'optionalAccess', _10 => _10.type]) === "TONPAY_IFRAME_LOADED") {
|
|
961
1023
|
setIframeLoaded(true);
|
|
962
1024
|
if (iframeTimeoutRef.current) {
|
|
963
1025
|
clearTimeout(iframeTimeoutRef.current);
|
|
964
1026
|
}
|
|
965
1027
|
}
|
|
966
|
-
if (_optionalChain([event, 'access',
|
|
1028
|
+
if (_optionalChain([event, 'access', _11 => _11.data, 'optionalAccess', _12 => _12.type]) === "TONPAY_MOONPAY_EVENT") {
|
|
967
1029
|
const payload = event.data.payload;
|
|
968
|
-
if (_optionalChain([payload, 'optionalAccess',
|
|
1030
|
+
if (_optionalChain([payload, 'optionalAccess', _13 => _13.type]) === "onTransactionCompleted" || _optionalChain([payload, 'optionalAccess', _14 => _14.eventName]) === "transactionCompleted") {
|
|
969
1031
|
handlePaymentSuccess();
|
|
970
1032
|
}
|
|
971
|
-
if (_optionalChain([payload, 'optionalAccess',
|
|
972
|
-
handlePaymentError(_optionalChain([payload, 'optionalAccess',
|
|
1033
|
+
if (_optionalChain([payload, 'optionalAccess', _15 => _15.type]) === "onTransactionFailed" || _optionalChain([payload, 'optionalAccess', _16 => _16.eventName]) === "transactionFailed") {
|
|
1034
|
+
handlePaymentError(_optionalChain([payload, 'optionalAccess', _17 => _17.message]) || "Transaction failed");
|
|
973
1035
|
}
|
|
974
1036
|
}
|
|
975
1037
|
};
|
|
@@ -998,7 +1060,7 @@ var PaymentModal = ({
|
|
|
998
1060
|
}
|
|
999
1061
|
}, IFRAME_LOAD_TIMEOUT);
|
|
1000
1062
|
}).catch((err) => {
|
|
1001
|
-
const errorMsg = _optionalChain([err, 'optionalAccess',
|
|
1063
|
+
const errorMsg = _optionalChain([err, 'optionalAccess', _18 => _18.message]) || "Failed to initialize payment";
|
|
1002
1064
|
setOnRampError(errorMsg);
|
|
1003
1065
|
fetchStartedRef.current = false;
|
|
1004
1066
|
}).finally(() => setIsOnRampLoading(false));
|
|
@@ -1008,7 +1070,14 @@ var PaymentModal = ({
|
|
|
1008
1070
|
clearTimeout(iframeTimeoutRef.current);
|
|
1009
1071
|
}
|
|
1010
1072
|
};
|
|
1011
|
-
}, [
|
|
1073
|
+
}, [
|
|
1074
|
+
view,
|
|
1075
|
+
onRampLink,
|
|
1076
|
+
onRampError,
|
|
1077
|
+
fetchOnRampLink,
|
|
1078
|
+
iframeLoaded,
|
|
1079
|
+
handlePaymentError
|
|
1080
|
+
]);
|
|
1012
1081
|
_react.useEffect.call(void 0, () => {
|
|
1013
1082
|
const checkMobile = () => {
|
|
1014
1083
|
setIsMobile(window.innerWidth < 768);
|
|
@@ -1041,7 +1110,9 @@ var PaymentModal = ({
|
|
|
1041
1110
|
const height = contentRef.current.scrollHeight;
|
|
1042
1111
|
const windowHeight = window.innerHeight;
|
|
1043
1112
|
const detent = Math.min((height + 40) / windowHeight, 0.95);
|
|
1044
|
-
setSheetDetent(
|
|
1113
|
+
setSheetDetent(
|
|
1114
|
+
(prev) => Math.abs(prev[0] - detent) < 0.01 ? prev : [detent]
|
|
1115
|
+
);
|
|
1045
1116
|
}
|
|
1046
1117
|
};
|
|
1047
1118
|
setTimeout(updateHeight, 50);
|
|
@@ -1066,7 +1137,14 @@ var PaymentModal = ({
|
|
|
1066
1137
|
view !== "main" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pm-title", children: "New Purchase" }),
|
|
1067
1138
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-header-right", children: [
|
|
1068
1139
|
walletAddress && view === "main" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { position: "relative" }, children: [
|
|
1069
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1140
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1141
|
+
"button",
|
|
1142
|
+
{
|
|
1143
|
+
className: "pm-close-btn",
|
|
1144
|
+
onClick: () => setShowMenu(!showMenu),
|
|
1145
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MenuIcon, {})
|
|
1146
|
+
}
|
|
1147
|
+
),
|
|
1070
1148
|
showMenu && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-menu-dropdown", children: [
|
|
1071
1149
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-menu-item disabled", children: [
|
|
1072
1150
|
walletAddress.slice(0, 4),
|
|
@@ -1078,7 +1156,7 @@ var PaymentModal = ({
|
|
|
1078
1156
|
{
|
|
1079
1157
|
className: "pm-menu-item danger",
|
|
1080
1158
|
onClick: () => {
|
|
1081
|
-
_optionalChain([onDisconnect, 'optionalCall',
|
|
1159
|
+
_optionalChain([onDisconnect, 'optionalCall', _19 => _19()]);
|
|
1082
1160
|
setShowMenu(false);
|
|
1083
1161
|
},
|
|
1084
1162
|
children: "Disconnect"
|
|
@@ -1104,39 +1182,52 @@ var PaymentModal = ({
|
|
|
1104
1182
|
] }),
|
|
1105
1183
|
itemTitle && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pm-order-info", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "pm-order-text", children: itemTitle }) })
|
|
1106
1184
|
] }),
|
|
1107
|
-
/* @__PURE__ */ _jsxruntime.
|
|
1108
|
-
/* @__PURE__ */ _jsxruntime.
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
{
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1185
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pm-actions-card", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-actions", children: [
|
|
1186
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1187
|
+
"button",
|
|
1188
|
+
{
|
|
1189
|
+
className: `pm-btn ${isLoading ? "processing" : "pm-btn-primary"}`,
|
|
1190
|
+
onClick: isLoading ? void 0 : onPayWithCrypto,
|
|
1191
|
+
disabled: isLoading,
|
|
1192
|
+
children: isLoading ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1193
|
+
"div",
|
|
1194
|
+
{
|
|
1195
|
+
style: { display: "flex", alignItems: "center", gap: "4px" },
|
|
1196
|
+
children: [
|
|
1197
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pm-btn-spinner" }),
|
|
1198
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Processing" })
|
|
1199
|
+
]
|
|
1200
|
+
}
|
|
1201
|
+
) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1202
|
+
"div",
|
|
1203
|
+
{
|
|
1204
|
+
style: { display: "flex", alignItems: "center", gap: "4px" },
|
|
1205
|
+
children: [
|
|
1206
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CryptoIcon, {}),
|
|
1207
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Pay with Crypto" })
|
|
1208
|
+
]
|
|
1209
|
+
}
|
|
1210
|
+
)
|
|
1211
|
+
}
|
|
1212
|
+
),
|
|
1213
|
+
isLoading && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-retry-link", children: [
|
|
1214
|
+
"Did the wallet fail to open?",
|
|
1215
|
+
" ",
|
|
1216
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "pm-retry-action", onClick: onPayWithCrypto, children: "Click here" }),
|
|
1217
|
+
"."
|
|
1134
1218
|
] }),
|
|
1135
|
-
onRampAvailable && !isLoading && /* @__PURE__ */ _jsxruntime.
|
|
1136
|
-
"
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1219
|
+
onRampAvailable && !isLoading && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1220
|
+
"button",
|
|
1221
|
+
{
|
|
1222
|
+
className: "pm-btn pm-btn-black",
|
|
1223
|
+
onClick: () => setView("card"),
|
|
1224
|
+
children: [
|
|
1225
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CardIcon, {}),
|
|
1226
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Pay with Card" })
|
|
1227
|
+
]
|
|
1228
|
+
}
|
|
1229
|
+
)
|
|
1230
|
+
] }) })
|
|
1140
1231
|
] });
|
|
1141
1232
|
const renderCardView = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-iframe-container", children: [
|
|
1142
1233
|
isOnRampLoading && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "pm-loading-container", children: [
|
|
@@ -1226,8 +1317,8 @@ var PaymentModal = ({
|
|
|
1226
1317
|
|
|
1227
1318
|
|
|
1228
1319
|
// ../api/src/common/const.ts
|
|
1229
|
-
var BASE_URL = "https://
|
|
1230
|
-
var TESTNET_BASE_URL = "https://
|
|
1320
|
+
var BASE_URL = "https://pay.ton.org";
|
|
1321
|
+
var TESTNET_BASE_URL = "https://dev.pay.ton.org";
|
|
1231
1322
|
|
|
1232
1323
|
// ../api/src/common/get-base-url.ts
|
|
1233
1324
|
var getBaseUrl = (chain) => {
|
|
@@ -1242,7 +1333,7 @@ var getBaseUrl = (chain) => {
|
|
|
1242
1333
|
|
|
1243
1334
|
// ../api/src/create-moonpay-transfer/create-moonpay-transfer.ts
|
|
1244
1335
|
var createMoonpayTransfer = async (params, options) => {
|
|
1245
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
1336
|
+
if (!_optionalChain([options, 'optionalAccess', _20 => _20.apiKey])) {
|
|
1246
1337
|
throw new Error("API key is required for MoonPay transfers");
|
|
1247
1338
|
}
|
|
1248
1339
|
const baseUrl = getBaseUrl(options.chain);
|
|
@@ -1271,44 +1362,21 @@ var createMoonpayTransfer = async (params, options) => {
|
|
|
1271
1362
|
return data;
|
|
1272
1363
|
};
|
|
1273
1364
|
|
|
1274
|
-
// ../api/src/check-moonpay-
|
|
1275
|
-
var
|
|
1276
|
-
const baseUrl = getBaseUrl(_optionalChain([options, 'optionalAccess',
|
|
1277
|
-
const headers = {
|
|
1278
|
-
"Content-Type": "application/json",
|
|
1279
|
-
..._optionalChain([options, 'optionalAccess', _23 => _23.apiKey]) ? { "x-api-key": options.apiKey } : {}
|
|
1280
|
-
};
|
|
1281
|
-
const response = await fetch(
|
|
1282
|
-
`${baseUrl}/api/external/moonpay/check-geo?ipAddress=${encodeURIComponent(params.ipAddress)}`,
|
|
1283
|
-
{
|
|
1284
|
-
method: "GET",
|
|
1285
|
-
headers
|
|
1286
|
-
}
|
|
1287
|
-
);
|
|
1288
|
-
if (!response.ok) {
|
|
1289
|
-
const errorText = await response.text();
|
|
1290
|
-
throw new Error(`Failed to check MoonPay geo: ${errorText}`, {
|
|
1291
|
-
cause: response.statusText
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
return response.json();
|
|
1295
|
-
};
|
|
1296
|
-
|
|
1297
|
-
// ../api/src/check-moonpay-limits/check-moonpay-limits.ts
|
|
1298
|
-
var checkMoonpayLimits = async (params, options) => {
|
|
1299
|
-
const baseUrl = getBaseUrl(_optionalChain([options, 'optionalAccess', _24 => _24.chain]));
|
|
1365
|
+
// ../api/src/check-moonpay-availability/check-moonpay-availability.ts
|
|
1366
|
+
var checkMoonpayAvailability = async (params, options) => {
|
|
1367
|
+
const baseUrl = getBaseUrl(_optionalChain([options, 'optionalAccess', _21 => _21.chain]));
|
|
1300
1368
|
const headers = {
|
|
1301
1369
|
"Content-Type": "application/json",
|
|
1302
|
-
..._optionalChain([options, 'optionalAccess',
|
|
1370
|
+
..._optionalChain([options, 'optionalAccess', _22 => _22.apiKey]) ? { "x-api-key": options.apiKey } : {}
|
|
1303
1371
|
};
|
|
1304
|
-
const response = await fetch(`${baseUrl}/api/external/moonpay/
|
|
1372
|
+
const response = await fetch(`${baseUrl}/api/external/moonpay/check`, {
|
|
1305
1373
|
method: "POST",
|
|
1306
1374
|
body: JSON.stringify(params),
|
|
1307
1375
|
headers
|
|
1308
1376
|
});
|
|
1309
1377
|
if (!response.ok) {
|
|
1310
1378
|
const errorText = await response.text();
|
|
1311
|
-
throw new Error(`Failed to check MoonPay
|
|
1379
|
+
throw new Error(`Failed to check MoonPay availability: ${errorText}`, {
|
|
1312
1380
|
cause: response.statusText
|
|
1313
1381
|
});
|
|
1314
1382
|
}
|
|
@@ -1336,18 +1404,17 @@ function useMoonPayIframe({
|
|
|
1336
1404
|
setLoading(true);
|
|
1337
1405
|
setError(null);
|
|
1338
1406
|
try {
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
if (!geo.isBuyAllowed) {
|
|
1342
|
-
return false;
|
|
1343
|
-
}
|
|
1344
|
-
const limitRes = await checkMoonpayLimits(
|
|
1345
|
-
{ asset },
|
|
1407
|
+
const availability = await checkMoonpayAvailability(
|
|
1408
|
+
{ asset, ipAddress },
|
|
1346
1409
|
{ apiKey, chain }
|
|
1347
1410
|
);
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
if (!
|
|
1411
|
+
setGeoResult(availability.geo);
|
|
1412
|
+
setLimits(availability.limits);
|
|
1413
|
+
if (!availability.geo.isBuyAllowed) {
|
|
1414
|
+
return false;
|
|
1415
|
+
}
|
|
1416
|
+
const limitsData = availability.limits;
|
|
1417
|
+
if (!_optionalChain([limitsData, 'optionalAccess', _23 => _23.quoteCurrency])) {
|
|
1351
1418
|
return false;
|
|
1352
1419
|
}
|
|
1353
1420
|
const { minBuyAmount, maxBuyAmount } = limitsData.quoteCurrency;
|
|
@@ -1551,7 +1618,7 @@ var TonPayButton = ({
|
|
|
1551
1618
|
setRedirectToWallet(null);
|
|
1552
1619
|
await handlePay((redirect) => setRedirectToWallet(() => redirect));
|
|
1553
1620
|
} catch (err) {
|
|
1554
|
-
_optionalChain([onError, 'optionalCall',
|
|
1621
|
+
_optionalChain([onError, 'optionalCall', _24 => _24(err)]);
|
|
1555
1622
|
if (showErrorNotification) {
|
|
1556
1623
|
const raw = typeof err === "object" && err && "message" in err ? String(err.message) : String(_nullishCoalesce(err, () => ( "")));
|
|
1557
1624
|
setErrorMessage(raw || "Wallet connection modal closed");
|
|
@@ -1581,8 +1648,8 @@ var TonPayButton = ({
|
|
|
1581
1648
|
[fetchOnRampLink, amount, currency, address, userIp]
|
|
1582
1649
|
);
|
|
1583
1650
|
const presetConfig = preset ? PRESETS[preset] : null;
|
|
1584
|
-
const finalBgColor = _nullishCoalesce(_nullishCoalesce(bgColor, () => ( _optionalChain([presetConfig, 'optionalAccess',
|
|
1585
|
-
const finalTextColor = _nullishCoalesce(_nullishCoalesce(textColor, () => ( _optionalChain([presetConfig, 'optionalAccess',
|
|
1651
|
+
const finalBgColor = _nullishCoalesce(_nullishCoalesce(bgColor, () => ( _optionalChain([presetConfig, 'optionalAccess', _25 => _25.bgColor]))), () => ( PRESETS.default.bgColor));
|
|
1652
|
+
const finalTextColor = _nullishCoalesce(_nullishCoalesce(textColor, () => ( _optionalChain([presetConfig, 'optionalAccess', _26 => _26.textColor]))), () => ( PRESETS.default.textColor));
|
|
1586
1653
|
const cssVars = {
|
|
1587
1654
|
"--tp-bg": finalBgColor,
|
|
1588
1655
|
"--tp-text": finalTextColor,
|
|
@@ -1597,13 +1664,13 @@ var TonPayButton = ({
|
|
|
1597
1664
|
if (text) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: text });
|
|
1598
1665
|
if (variant === "short") {
|
|
1599
1666
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tp-btn-content", children: [
|
|
1600
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TonIcon, {}),
|
|
1667
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TonIcon, { bgColor: finalBgColor, textColor: finalTextColor }),
|
|
1601
1668
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Pay" })
|
|
1602
1669
|
] });
|
|
1603
1670
|
}
|
|
1604
1671
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tp-btn-content", children: [
|
|
1605
1672
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Pay with" }),
|
|
1606
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TonIcon, {}),
|
|
1673
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TonIcon, { bgColor: finalBgColor, textColor: finalTextColor }),
|
|
1607
1674
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Pay" })
|
|
1608
1675
|
] });
|
|
1609
1676
|
};
|
|
@@ -1662,9 +1729,9 @@ var TonPayButton = ({
|
|
|
1662
1729
|
showMenu && showDropdown && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tp-menu", children: [
|
|
1663
1730
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tp-menu-arrow" }),
|
|
1664
1731
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tp-menu-address", children: [
|
|
1665
|
-
_optionalChain([address, 'optionalAccess',
|
|
1732
|
+
_optionalChain([address, 'optionalAccess', _27 => _27.slice, 'call', _28 => _28(0, 4)]),
|
|
1666
1733
|
"...",
|
|
1667
|
-
_optionalChain([address, 'optionalAccess',
|
|
1734
|
+
_optionalChain([address, 'optionalAccess', _29 => _29.slice, 'call', _30 => _30(-4)])
|
|
1668
1735
|
] }),
|
|
1669
1736
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1670
1737
|
"button",
|
|
@@ -1725,7 +1792,7 @@ function useTonPay() {
|
|
|
1725
1792
|
}
|
|
1726
1793
|
modal.open();
|
|
1727
1794
|
const unsubscribe = tonConnectUI.onStatusChange((wallet) => {
|
|
1728
|
-
if (_optionalChain([wallet, 'optionalAccess',
|
|
1795
|
+
if (_optionalChain([wallet, 'optionalAccess', _31 => _31.account])) {
|
|
1729
1796
|
unsubscribe();
|
|
1730
1797
|
unsubscribeModal();
|
|
1731
1798
|
resolve(wallet.account.address);
|
|
@@ -1757,7 +1824,7 @@ function useTonPay() {
|
|
|
1757
1824
|
from: walletAddress
|
|
1758
1825
|
},
|
|
1759
1826
|
{
|
|
1760
|
-
onRequestSent: _optionalChain([options, 'optionalAccess',
|
|
1827
|
+
onRequestSent: _optionalChain([options, 'optionalAccess', _32 => _32.onRequestSent])
|
|
1761
1828
|
}
|
|
1762
1829
|
);
|
|
1763
1830
|
return { ...messageResult, txResult };
|
|
@@ -1767,1704 +1834,6 @@ function useTonPay() {
|
|
|
1767
1834
|
return { pay, address };
|
|
1768
1835
|
}
|
|
1769
1836
|
|
|
1770
|
-
// src/signless/context.tsx
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
// src/signless/crypto/ed25519.ts
|
|
1775
|
-
var ALGORITHM = "Ed25519";
|
|
1776
|
-
function arrayBufferToUint8Array(buffer) {
|
|
1777
|
-
return new Uint8Array(buffer);
|
|
1778
|
-
}
|
|
1779
|
-
async function generateKeyPair() {
|
|
1780
|
-
const keyPair = await crypto.subtle.generateKey(ALGORITHM, true, [
|
|
1781
|
-
"sign",
|
|
1782
|
-
"verify"
|
|
1783
|
-
]);
|
|
1784
|
-
const privateKeyBuffer = await crypto.subtle.exportKey(
|
|
1785
|
-
"pkcs8",
|
|
1786
|
-
keyPair.privateKey
|
|
1787
|
-
);
|
|
1788
|
-
const publicKeyBuffer = await crypto.subtle.exportKey(
|
|
1789
|
-
"spki",
|
|
1790
|
-
keyPair.publicKey
|
|
1791
|
-
);
|
|
1792
|
-
return {
|
|
1793
|
-
publicKey: arrayBufferToUint8Array(publicKeyBuffer),
|
|
1794
|
-
privateKey: arrayBufferToUint8Array(privateKeyBuffer)
|
|
1795
|
-
};
|
|
1796
|
-
}
|
|
1797
|
-
async function signMessage(privateKey, message) {
|
|
1798
|
-
const importedKey = await crypto.subtle.importKey(
|
|
1799
|
-
"pkcs8",
|
|
1800
|
-
privateKey,
|
|
1801
|
-
ALGORITHM,
|
|
1802
|
-
false,
|
|
1803
|
-
["sign"]
|
|
1804
|
-
);
|
|
1805
|
-
const signature = await crypto.subtle.sign(ALGORITHM, importedKey, message);
|
|
1806
|
-
return arrayBufferToUint8Array(signature);
|
|
1807
|
-
}
|
|
1808
|
-
async function verifySignlessSignature(publicKey, message, signature) {
|
|
1809
|
-
const importedKey = await crypto.subtle.importKey(
|
|
1810
|
-
"spki",
|
|
1811
|
-
publicKey,
|
|
1812
|
-
ALGORITHM,
|
|
1813
|
-
false,
|
|
1814
|
-
["verify"]
|
|
1815
|
-
);
|
|
1816
|
-
return crypto.subtle.verify(ALGORITHM, importedKey, signature, message);
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
// src/signless/crypto/encryption.ts
|
|
1820
|
-
var PBKDF2_ITERATIONS = 1e5;
|
|
1821
|
-
var SALT_LENGTH = 16;
|
|
1822
|
-
var IV_LENGTH = 12;
|
|
1823
|
-
var KEY_LENGTH = 256;
|
|
1824
|
-
function arrayBufferToBase64(buffer) {
|
|
1825
|
-
const bytes = new Uint8Array(buffer);
|
|
1826
|
-
let binary = "";
|
|
1827
|
-
for (let i = 0; i < bytes.byteLength; i++) {
|
|
1828
|
-
binary += String.fromCharCode(bytes[i]);
|
|
1829
|
-
}
|
|
1830
|
-
return btoa(binary);
|
|
1831
|
-
}
|
|
1832
|
-
function base64ToArrayBuffer(base64) {
|
|
1833
|
-
const binary = atob(base64);
|
|
1834
|
-
const bytes = new Uint8Array(binary.length);
|
|
1835
|
-
for (let i = 0; i < binary.length; i++) {
|
|
1836
|
-
bytes[i] = binary.charCodeAt(i);
|
|
1837
|
-
}
|
|
1838
|
-
return bytes.buffer;
|
|
1839
|
-
}
|
|
1840
|
-
function generateSalt() {
|
|
1841
|
-
return crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
|
|
1842
|
-
}
|
|
1843
|
-
function generateIv() {
|
|
1844
|
-
return crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
1845
|
-
}
|
|
1846
|
-
async function deriveKeyFromPin(pin, salt) {
|
|
1847
|
-
const encoder = new TextEncoder();
|
|
1848
|
-
const pinData = encoder.encode(pin);
|
|
1849
|
-
const baseKey = await crypto.subtle.importKey(
|
|
1850
|
-
"raw",
|
|
1851
|
-
pinData,
|
|
1852
|
-
"PBKDF2",
|
|
1853
|
-
false,
|
|
1854
|
-
["deriveKey"]
|
|
1855
|
-
);
|
|
1856
|
-
return crypto.subtle.deriveKey(
|
|
1857
|
-
{
|
|
1858
|
-
name: "PBKDF2",
|
|
1859
|
-
salt,
|
|
1860
|
-
iterations: PBKDF2_ITERATIONS,
|
|
1861
|
-
hash: "SHA-256"
|
|
1862
|
-
},
|
|
1863
|
-
baseKey,
|
|
1864
|
-
{ name: "AES-GCM", length: KEY_LENGTH },
|
|
1865
|
-
false,
|
|
1866
|
-
["encrypt", "decrypt"]
|
|
1867
|
-
);
|
|
1868
|
-
}
|
|
1869
|
-
async function encryptPrivateKey(privateKey, publicKey, pin) {
|
|
1870
|
-
const salt = generateSalt();
|
|
1871
|
-
const iv = generateIv();
|
|
1872
|
-
const derivedKey = await deriveKeyFromPin(pin, salt);
|
|
1873
|
-
const encryptedBuffer = await crypto.subtle.encrypt(
|
|
1874
|
-
{ name: "AES-GCM", iv },
|
|
1875
|
-
derivedKey,
|
|
1876
|
-
privateKey
|
|
1877
|
-
);
|
|
1878
|
-
return {
|
|
1879
|
-
salt: arrayBufferToBase64(salt.buffer),
|
|
1880
|
-
iv: arrayBufferToBase64(iv.buffer),
|
|
1881
|
-
encryptedBlob: arrayBufferToBase64(encryptedBuffer),
|
|
1882
|
-
publicKey: arrayBufferToBase64(publicKey.buffer),
|
|
1883
|
-
version: 1
|
|
1884
|
-
};
|
|
1885
|
-
}
|
|
1886
|
-
async function decryptPrivateKey(vault, pin) {
|
|
1887
|
-
const salt = new Uint8Array(base64ToArrayBuffer(vault.salt));
|
|
1888
|
-
const iv = new Uint8Array(base64ToArrayBuffer(vault.iv));
|
|
1889
|
-
const encryptedBlob = base64ToArrayBuffer(vault.encryptedBlob);
|
|
1890
|
-
const derivedKey = await deriveKeyFromPin(pin, salt);
|
|
1891
|
-
try {
|
|
1892
|
-
const decryptedBuffer = await crypto.subtle.decrypt(
|
|
1893
|
-
{ name: "AES-GCM", iv },
|
|
1894
|
-
derivedKey,
|
|
1895
|
-
encryptedBlob
|
|
1896
|
-
);
|
|
1897
|
-
return new Uint8Array(decryptedBuffer);
|
|
1898
|
-
} catch (e4) {
|
|
1899
|
-
throw new Error("Invalid PIN or corrupted vault");
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
// src/signless/crypto/webauthn.ts
|
|
1904
|
-
var WEBAUTHN_RP_NAME = "TON Pay";
|
|
1905
|
-
var WEBAUTHN_RP_ID_FALLBACK = "tonpay.io";
|
|
1906
|
-
var STATIC_CHALLENGE = new Uint8Array([
|
|
1907
|
-
1,
|
|
1908
|
-
2,
|
|
1909
|
-
3,
|
|
1910
|
-
4,
|
|
1911
|
-
5,
|
|
1912
|
-
6,
|
|
1913
|
-
7,
|
|
1914
|
-
8,
|
|
1915
|
-
9,
|
|
1916
|
-
10,
|
|
1917
|
-
11,
|
|
1918
|
-
12,
|
|
1919
|
-
13,
|
|
1920
|
-
14,
|
|
1921
|
-
15,
|
|
1922
|
-
16
|
|
1923
|
-
]);
|
|
1924
|
-
function arrayBufferToBase64Url(buffer) {
|
|
1925
|
-
const bytes = new Uint8Array(buffer);
|
|
1926
|
-
let binary = "";
|
|
1927
|
-
for (let i = 0; i < bytes.byteLength; i++) {
|
|
1928
|
-
binary += String.fromCharCode(bytes[i]);
|
|
1929
|
-
}
|
|
1930
|
-
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1931
|
-
}
|
|
1932
|
-
function base64UrlToArrayBuffer(base64Url) {
|
|
1933
|
-
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
|
1934
|
-
const padding = "=".repeat((4 - base64.length % 4) % 4);
|
|
1935
|
-
const binary = atob(base64 + padding);
|
|
1936
|
-
const bytes = new Uint8Array(binary.length);
|
|
1937
|
-
for (let i = 0; i < binary.length; i++) {
|
|
1938
|
-
bytes[i] = binary.charCodeAt(i);
|
|
1939
|
-
}
|
|
1940
|
-
return bytes.buffer;
|
|
1941
|
-
}
|
|
1942
|
-
function isWebAuthnSupported() {
|
|
1943
|
-
return typeof window !== "undefined" && !!window.PublicKeyCredential && typeof window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable === "function";
|
|
1944
|
-
}
|
|
1945
|
-
function getRpId() {
|
|
1946
|
-
if (typeof window === "undefined") return WEBAUTHN_RP_ID_FALLBACK;
|
|
1947
|
-
return window.location.hostname || WEBAUTHN_RP_ID_FALLBACK;
|
|
1948
|
-
}
|
|
1949
|
-
async function createWebAuthnCredential(walletAddress) {
|
|
1950
|
-
if (!isWebAuthnSupported()) {
|
|
1951
|
-
throw new Error("WebAuthn is not supported in this browser");
|
|
1952
|
-
}
|
|
1953
|
-
const userId = new TextEncoder().encode(walletAddress);
|
|
1954
|
-
const createOptions = {
|
|
1955
|
-
challenge: STATIC_CHALLENGE,
|
|
1956
|
-
rp: {
|
|
1957
|
-
name: WEBAUTHN_RP_NAME,
|
|
1958
|
-
id: getRpId()
|
|
1959
|
-
},
|
|
1960
|
-
user: {
|
|
1961
|
-
id: userId,
|
|
1962
|
-
name: `TON Pay - ${walletAddress.slice(0, 8)}...`,
|
|
1963
|
-
displayName: "TON Pay Signless"
|
|
1964
|
-
},
|
|
1965
|
-
pubKeyCredParams: [
|
|
1966
|
-
{ type: "public-key", alg: -7 },
|
|
1967
|
-
{ type: "public-key", alg: -257 }
|
|
1968
|
-
],
|
|
1969
|
-
timeout: 6e4,
|
|
1970
|
-
authenticatorSelection: {
|
|
1971
|
-
authenticatorAttachment: "platform",
|
|
1972
|
-
userVerification: "required",
|
|
1973
|
-
residentKey: "preferred"
|
|
1974
|
-
},
|
|
1975
|
-
attestation: "none"
|
|
1976
|
-
};
|
|
1977
|
-
const credential = await navigator.credentials.create({
|
|
1978
|
-
publicKey: createOptions
|
|
1979
|
-
});
|
|
1980
|
-
if (!credential) {
|
|
1981
|
-
throw new Error("Failed to create WebAuthn credential");
|
|
1982
|
-
}
|
|
1983
|
-
const response = credential.response;
|
|
1984
|
-
return {
|
|
1985
|
-
credentialId: arrayBufferToBase64Url(credential.rawId),
|
|
1986
|
-
publicKey: arrayBufferToBase64Url(_nullishCoalesce(_optionalChain([response, 'access', _37 => _37.getPublicKey, 'optionalCall', _38 => _38()]), () => ( new ArrayBuffer(0)))),
|
|
1987
|
-
transports: _optionalChain([response, 'access', _39 => _39.getTransports, 'optionalCall', _40 => _40()])
|
|
1988
|
-
};
|
|
1989
|
-
}
|
|
1990
|
-
async function getWebAuthnCredential(credentialInfo) {
|
|
1991
|
-
if (!isWebAuthnSupported()) {
|
|
1992
|
-
throw new Error("WebAuthn is not supported in this browser");
|
|
1993
|
-
}
|
|
1994
|
-
const credentialId = base64UrlToArrayBuffer(credentialInfo.credentialId);
|
|
1995
|
-
const getOptions = {
|
|
1996
|
-
challenge: STATIC_CHALLENGE,
|
|
1997
|
-
rpId: getRpId(),
|
|
1998
|
-
timeout: 6e4,
|
|
1999
|
-
userVerification: "required",
|
|
2000
|
-
allowCredentials: [
|
|
2001
|
-
{
|
|
2002
|
-
type: "public-key",
|
|
2003
|
-
id: credentialId,
|
|
2004
|
-
transports: credentialInfo.transports
|
|
2005
|
-
}
|
|
2006
|
-
]
|
|
2007
|
-
};
|
|
2008
|
-
const assertion = await navigator.credentials.get({
|
|
2009
|
-
publicKey: getOptions
|
|
2010
|
-
});
|
|
2011
|
-
if (!assertion) {
|
|
2012
|
-
throw new Error("WebAuthn authentication failed");
|
|
2013
|
-
}
|
|
2014
|
-
const response = assertion.response;
|
|
2015
|
-
return response.signature;
|
|
2016
|
-
}
|
|
2017
|
-
|
|
2018
|
-
// src/signless/storage.ts
|
|
2019
|
-
var DEFAULT_STORAGE_KEY = "tonpay_signless_vault";
|
|
2020
|
-
var SignlessStorage = class {
|
|
2021
|
-
|
|
2022
|
-
constructor(storageKey = DEFAULT_STORAGE_KEY) {
|
|
2023
|
-
this.storageKey = storageKey;
|
|
2024
|
-
}
|
|
2025
|
-
getStorage() {
|
|
2026
|
-
if (typeof window === "undefined") return null;
|
|
2027
|
-
return window.localStorage;
|
|
2028
|
-
}
|
|
2029
|
-
async saveVault(walletAddress, vault, authMethod, webauthnCredential) {
|
|
2030
|
-
const storage = this.getStorage();
|
|
2031
|
-
if (!storage) return;
|
|
2032
|
-
const data = {
|
|
2033
|
-
vault,
|
|
2034
|
-
authMethod,
|
|
2035
|
-
walletAddress,
|
|
2036
|
-
webauthnCredential,
|
|
2037
|
-
createdAt: Date.now(),
|
|
2038
|
-
updatedAt: Date.now()
|
|
2039
|
-
};
|
|
2040
|
-
const key = this.getStorageKeyForWallet(walletAddress);
|
|
2041
|
-
storage.setItem(key, JSON.stringify(data));
|
|
2042
|
-
}
|
|
2043
|
-
async loadVault(walletAddress) {
|
|
2044
|
-
const storage = this.getStorage();
|
|
2045
|
-
if (!storage) return null;
|
|
2046
|
-
const key = this.getStorageKeyForWallet(walletAddress);
|
|
2047
|
-
const data = storage.getItem(key);
|
|
2048
|
-
if (!data) return null;
|
|
2049
|
-
try {
|
|
2050
|
-
return JSON.parse(data);
|
|
2051
|
-
} catch (e5) {
|
|
2052
|
-
return null;
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
async deleteVault(walletAddress) {
|
|
2056
|
-
const storage = this.getStorage();
|
|
2057
|
-
if (!storage) return;
|
|
2058
|
-
const key = this.getStorageKeyForWallet(walletAddress);
|
|
2059
|
-
storage.removeItem(key);
|
|
2060
|
-
}
|
|
2061
|
-
async hasVault(walletAddress) {
|
|
2062
|
-
const vault = await this.loadVault(walletAddress);
|
|
2063
|
-
return vault !== null;
|
|
2064
|
-
}
|
|
2065
|
-
async updateVaultTimestamp(walletAddress) {
|
|
2066
|
-
const storage = this.getStorage();
|
|
2067
|
-
if (!storage) return;
|
|
2068
|
-
const vault = await this.loadVault(walletAddress);
|
|
2069
|
-
if (!vault) return;
|
|
2070
|
-
vault.updatedAt = Date.now();
|
|
2071
|
-
const key = this.getStorageKeyForWallet(walletAddress);
|
|
2072
|
-
storage.setItem(key, JSON.stringify(vault));
|
|
2073
|
-
}
|
|
2074
|
-
async getAllWalletsWithVaults() {
|
|
2075
|
-
const storage = this.getStorage();
|
|
2076
|
-
if (!storage) return [];
|
|
2077
|
-
const wallets = [];
|
|
2078
|
-
const prefix = `${this.storageKey}_`;
|
|
2079
|
-
for (let i = 0; i < storage.length; i++) {
|
|
2080
|
-
const key = storage.key(i);
|
|
2081
|
-
if (_optionalChain([key, 'optionalAccess', _41 => _41.startsWith, 'call', _42 => _42(prefix)])) {
|
|
2082
|
-
const walletAddress = key.slice(prefix.length);
|
|
2083
|
-
wallets.push(walletAddress);
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
|
-
return wallets;
|
|
2087
|
-
}
|
|
2088
|
-
getStorageKeyForWallet(walletAddress) {
|
|
2089
|
-
return `${this.storageKey}_${walletAddress}`;
|
|
2090
|
-
}
|
|
2091
|
-
};
|
|
2092
|
-
var signlessStorage = new SignlessStorage();
|
|
2093
|
-
|
|
2094
|
-
// src/signless/context.tsx
|
|
2095
|
-
|
|
2096
|
-
var DEFAULT_CONFIG = {
|
|
2097
|
-
enabled: false,
|
|
2098
|
-
authMethod: "none",
|
|
2099
|
-
autoLockTimeout: 5 * 60 * 1e3,
|
|
2100
|
-
storageKey: "tonpay_signless_vault"
|
|
2101
|
-
};
|
|
2102
|
-
var DEFAULT_STATE = {
|
|
2103
|
-
status: "disabled",
|
|
2104
|
-
isEnabled: false,
|
|
2105
|
-
isSetup: false,
|
|
2106
|
-
isUnlocked: false,
|
|
2107
|
-
authMethod: "none",
|
|
2108
|
-
publicKey: null,
|
|
2109
|
-
walletAddress: null
|
|
2110
|
-
};
|
|
2111
|
-
var SignlessContext = React9.createContext(null);
|
|
2112
|
-
function SignlessProvider({ children, config }) {
|
|
2113
|
-
const walletAddress = _uireact.useTonAddress.call(void 0, true);
|
|
2114
|
-
const [state, setState] = React9.useState(DEFAULT_STATE);
|
|
2115
|
-
const [currentConfig, setCurrentConfig] = React9.useState({
|
|
2116
|
-
...DEFAULT_CONFIG,
|
|
2117
|
-
...config
|
|
2118
|
-
});
|
|
2119
|
-
const storageRef = React9.useRef(
|
|
2120
|
-
new SignlessStorage(currentConfig.storageKey)
|
|
2121
|
-
);
|
|
2122
|
-
const privateKeyRef = React9.useRef(null);
|
|
2123
|
-
const lockTimeoutRef = React9.useRef(
|
|
2124
|
-
null
|
|
2125
|
-
);
|
|
2126
|
-
const webauthnCredentialRef = React9.useRef(
|
|
2127
|
-
null
|
|
2128
|
-
);
|
|
2129
|
-
const [isBiometricAvailable, setIsBiometricAvailable] = React9.useState(false);
|
|
2130
|
-
React9.useEffect(() => {
|
|
2131
|
-
async function checkBiometric() {
|
|
2132
|
-
if (!isWebAuthnSupported()) {
|
|
2133
|
-
setIsBiometricAvailable(false);
|
|
2134
|
-
return;
|
|
2135
|
-
}
|
|
2136
|
-
try {
|
|
2137
|
-
const available = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
|
|
2138
|
-
setIsBiometricAvailable(available);
|
|
2139
|
-
} catch (e6) {
|
|
2140
|
-
setIsBiometricAvailable(false);
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
checkBiometric();
|
|
2144
|
-
}, []);
|
|
2145
|
-
React9.useEffect(() => {
|
|
2146
|
-
async function loadVaultState() {
|
|
2147
|
-
if (!walletAddress) {
|
|
2148
|
-
setState({ ...DEFAULT_STATE });
|
|
2149
|
-
return;
|
|
2150
|
-
}
|
|
2151
|
-
if (!currentConfig.enabled) {
|
|
2152
|
-
setState({
|
|
2153
|
-
...DEFAULT_STATE,
|
|
2154
|
-
status: "disabled",
|
|
2155
|
-
walletAddress
|
|
2156
|
-
});
|
|
2157
|
-
return;
|
|
2158
|
-
}
|
|
2159
|
-
const vaultData = await storageRef.current.loadVault(walletAddress);
|
|
2160
|
-
if (!vaultData) {
|
|
2161
|
-
setState({
|
|
2162
|
-
...DEFAULT_STATE,
|
|
2163
|
-
status: "not_setup",
|
|
2164
|
-
isEnabled: true,
|
|
2165
|
-
walletAddress
|
|
2166
|
-
});
|
|
2167
|
-
return;
|
|
2168
|
-
}
|
|
2169
|
-
webauthnCredentialRef.current = vaultData.webauthnCredential || null;
|
|
2170
|
-
setState({
|
|
2171
|
-
status: "locked",
|
|
2172
|
-
isEnabled: true,
|
|
2173
|
-
isSetup: true,
|
|
2174
|
-
isUnlocked: false,
|
|
2175
|
-
authMethod: vaultData.authMethod,
|
|
2176
|
-
publicKey: vaultData.vault.publicKey,
|
|
2177
|
-
walletAddress
|
|
2178
|
-
});
|
|
2179
|
-
}
|
|
2180
|
-
loadVaultState();
|
|
2181
|
-
}, [walletAddress, currentConfig.enabled]);
|
|
2182
|
-
const resetLockTimeout = React9.useCallback(() => {
|
|
2183
|
-
if (lockTimeoutRef.current) {
|
|
2184
|
-
clearTimeout(lockTimeoutRef.current);
|
|
2185
|
-
}
|
|
2186
|
-
if (currentConfig.autoLockTimeout && currentConfig.autoLockTimeout > 0) {
|
|
2187
|
-
lockTimeoutRef.current = setTimeout(() => {
|
|
2188
|
-
if (privateKeyRef.current) {
|
|
2189
|
-
privateKeyRef.current.fill(0);
|
|
2190
|
-
privateKeyRef.current = null;
|
|
2191
|
-
}
|
|
2192
|
-
setState((prev) => ({
|
|
2193
|
-
...prev,
|
|
2194
|
-
status: "locked",
|
|
2195
|
-
isUnlocked: false
|
|
2196
|
-
}));
|
|
2197
|
-
}, currentConfig.autoLockTimeout);
|
|
2198
|
-
}
|
|
2199
|
-
}, [currentConfig.autoLockTimeout]);
|
|
2200
|
-
const setup = React9.useCallback(
|
|
2201
|
-
async (params) => {
|
|
2202
|
-
if (!walletAddress) {
|
|
2203
|
-
throw new Error("Wallet not connected");
|
|
2204
|
-
}
|
|
2205
|
-
setState((prev) => ({ ...prev, status: "setting_up" }));
|
|
2206
|
-
try {
|
|
2207
|
-
const keyPair = await generateKeyPair();
|
|
2208
|
-
let webauthnCredential;
|
|
2209
|
-
if (params.authMethod === "biometric") {
|
|
2210
|
-
webauthnCredential = await createWebAuthnCredential(walletAddress);
|
|
2211
|
-
webauthnCredentialRef.current = webauthnCredential;
|
|
2212
|
-
const signature = await getWebAuthnCredential(webauthnCredential);
|
|
2213
|
-
const signatureBytes = new Uint8Array(signature);
|
|
2214
|
-
const biometricPin = Array.from(signatureBytes.slice(0, 32)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2215
|
-
const vault = await encryptPrivateKey(
|
|
2216
|
-
keyPair.privateKey,
|
|
2217
|
-
keyPair.publicKey,
|
|
2218
|
-
biometricPin
|
|
2219
|
-
);
|
|
2220
|
-
await storageRef.current.saveVault(
|
|
2221
|
-
walletAddress,
|
|
2222
|
-
vault,
|
|
2223
|
-
"biometric",
|
|
2224
|
-
webauthnCredential
|
|
2225
|
-
);
|
|
2226
|
-
privateKeyRef.current = keyPair.privateKey;
|
|
2227
|
-
} else if (params.authMethod === "pin") {
|
|
2228
|
-
if (!params.pin) {
|
|
2229
|
-
throw new Error("PIN is required for PIN authentication");
|
|
2230
|
-
}
|
|
2231
|
-
const vault = await encryptPrivateKey(
|
|
2232
|
-
keyPair.privateKey,
|
|
2233
|
-
keyPair.publicKey,
|
|
2234
|
-
params.pin
|
|
2235
|
-
);
|
|
2236
|
-
await storageRef.current.saveVault(walletAddress, vault, "pin");
|
|
2237
|
-
privateKeyRef.current = keyPair.privateKey;
|
|
2238
|
-
} else {
|
|
2239
|
-
throw new Error("Invalid authentication method");
|
|
2240
|
-
}
|
|
2241
|
-
setState({
|
|
2242
|
-
status: "unlocked",
|
|
2243
|
-
isEnabled: true,
|
|
2244
|
-
isSetup: true,
|
|
2245
|
-
isUnlocked: true,
|
|
2246
|
-
authMethod: params.authMethod,
|
|
2247
|
-
publicKey: arrayBufferToBase642(keyPair.publicKey.buffer),
|
|
2248
|
-
walletAddress
|
|
2249
|
-
});
|
|
2250
|
-
resetLockTimeout();
|
|
2251
|
-
} catch (error) {
|
|
2252
|
-
setState((prev) => ({
|
|
2253
|
-
...prev,
|
|
2254
|
-
status: prev.isSetup ? "locked" : "not_setup"
|
|
2255
|
-
}));
|
|
2256
|
-
throw error;
|
|
2257
|
-
}
|
|
2258
|
-
},
|
|
2259
|
-
[walletAddress, resetLockTimeout]
|
|
2260
|
-
);
|
|
2261
|
-
const unlock = React9.useCallback(
|
|
2262
|
-
async (params) => {
|
|
2263
|
-
if (!walletAddress) {
|
|
2264
|
-
throw new Error("Wallet not connected");
|
|
2265
|
-
}
|
|
2266
|
-
const vaultData = await storageRef.current.loadVault(walletAddress);
|
|
2267
|
-
if (!vaultData) {
|
|
2268
|
-
throw new Error("No signless vault found");
|
|
2269
|
-
}
|
|
2270
|
-
try {
|
|
2271
|
-
let pin;
|
|
2272
|
-
if (vaultData.authMethod === "biometric") {
|
|
2273
|
-
if (!vaultData.webauthnCredential) {
|
|
2274
|
-
throw new Error("WebAuthn credential not found");
|
|
2275
|
-
}
|
|
2276
|
-
const signature = await getWebAuthnCredential(
|
|
2277
|
-
vaultData.webauthnCredential
|
|
2278
|
-
);
|
|
2279
|
-
const signatureBytes = new Uint8Array(signature);
|
|
2280
|
-
pin = Array.from(signatureBytes.slice(0, 32)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2281
|
-
} else if (vaultData.authMethod === "pin") {
|
|
2282
|
-
if (!params.pin) {
|
|
2283
|
-
throw new Error("PIN is required");
|
|
2284
|
-
}
|
|
2285
|
-
pin = params.pin;
|
|
2286
|
-
} else {
|
|
2287
|
-
throw new Error("Invalid authentication method");
|
|
2288
|
-
}
|
|
2289
|
-
const privateKey = await decryptPrivateKey(vaultData.vault, pin);
|
|
2290
|
-
privateKeyRef.current = privateKey;
|
|
2291
|
-
setState((prev) => ({
|
|
2292
|
-
...prev,
|
|
2293
|
-
status: "unlocked",
|
|
2294
|
-
isUnlocked: true
|
|
2295
|
-
}));
|
|
2296
|
-
resetLockTimeout();
|
|
2297
|
-
} catch (error) {
|
|
2298
|
-
throw new Error("Failed to unlock vault");
|
|
2299
|
-
}
|
|
2300
|
-
},
|
|
2301
|
-
[walletAddress, resetLockTimeout]
|
|
2302
|
-
);
|
|
2303
|
-
const lock = React9.useCallback(() => {
|
|
2304
|
-
if (lockTimeoutRef.current) {
|
|
2305
|
-
clearTimeout(lockTimeoutRef.current);
|
|
2306
|
-
}
|
|
2307
|
-
if (privateKeyRef.current) {
|
|
2308
|
-
privateKeyRef.current.fill(0);
|
|
2309
|
-
privateKeyRef.current = null;
|
|
2310
|
-
}
|
|
2311
|
-
setState((prev) => ({
|
|
2312
|
-
...prev,
|
|
2313
|
-
status: "locked",
|
|
2314
|
-
isUnlocked: false
|
|
2315
|
-
}));
|
|
2316
|
-
}, []);
|
|
2317
|
-
const reset = React9.useCallback(async () => {
|
|
2318
|
-
if (!walletAddress) return;
|
|
2319
|
-
if (lockTimeoutRef.current) {
|
|
2320
|
-
clearTimeout(lockTimeoutRef.current);
|
|
2321
|
-
}
|
|
2322
|
-
if (privateKeyRef.current) {
|
|
2323
|
-
privateKeyRef.current.fill(0);
|
|
2324
|
-
privateKeyRef.current = null;
|
|
2325
|
-
}
|
|
2326
|
-
webauthnCredentialRef.current = null;
|
|
2327
|
-
await storageRef.current.deleteVault(walletAddress);
|
|
2328
|
-
setState({
|
|
2329
|
-
...DEFAULT_STATE,
|
|
2330
|
-
status: currentConfig.enabled ? "not_setup" : "disabled",
|
|
2331
|
-
isEnabled: currentConfig.enabled,
|
|
2332
|
-
walletAddress
|
|
2333
|
-
});
|
|
2334
|
-
}, [walletAddress, currentConfig.enabled]);
|
|
2335
|
-
const signPayload = React9.useCallback(
|
|
2336
|
-
async (params) => {
|
|
2337
|
-
if (!privateKeyRef.current) {
|
|
2338
|
-
throw new Error("Signless is locked. Please unlock first.");
|
|
2339
|
-
}
|
|
2340
|
-
if (!state.publicKey) {
|
|
2341
|
-
throw new Error("Public key not available");
|
|
2342
|
-
}
|
|
2343
|
-
resetLockTimeout();
|
|
2344
|
-
const reference = params.reference || generateReference();
|
|
2345
|
-
const validUntil = params.validUntil || Math.floor(Date.now() / 1e3) + 300;
|
|
2346
|
-
const payloadData = {
|
|
2347
|
-
recipient: params.recipient,
|
|
2348
|
-
amount: params.amount,
|
|
2349
|
-
token: params.token || "TON",
|
|
2350
|
-
payload: params.payload || "",
|
|
2351
|
-
reference,
|
|
2352
|
-
validUntil
|
|
2353
|
-
};
|
|
2354
|
-
const encoder = new TextEncoder();
|
|
2355
|
-
const payloadBytes = encoder.encode(JSON.stringify(payloadData));
|
|
2356
|
-
const signature = await signMessage(privateKeyRef.current, payloadBytes);
|
|
2357
|
-
return {
|
|
2358
|
-
payload: payloadBytes,
|
|
2359
|
-
signature,
|
|
2360
|
-
publicKey: state.publicKey,
|
|
2361
|
-
reference,
|
|
2362
|
-
validUntil
|
|
2363
|
-
};
|
|
2364
|
-
},
|
|
2365
|
-
[state.publicKey, resetLockTimeout]
|
|
2366
|
-
);
|
|
2367
|
-
const updateConfig = React9.useCallback(
|
|
2368
|
-
(newConfig) => {
|
|
2369
|
-
setCurrentConfig((prev) => ({ ...prev, ...newConfig }));
|
|
2370
|
-
},
|
|
2371
|
-
[]
|
|
2372
|
-
);
|
|
2373
|
-
React9.useEffect(() => {
|
|
2374
|
-
return () => {
|
|
2375
|
-
if (lockTimeoutRef.current) {
|
|
2376
|
-
clearTimeout(lockTimeoutRef.current);
|
|
2377
|
-
}
|
|
2378
|
-
if (privateKeyRef.current) {
|
|
2379
|
-
privateKeyRef.current.fill(0);
|
|
2380
|
-
privateKeyRef.current = null;
|
|
2381
|
-
}
|
|
2382
|
-
};
|
|
2383
|
-
}, []);
|
|
2384
|
-
const contextValue = {
|
|
2385
|
-
state,
|
|
2386
|
-
config: currentConfig,
|
|
2387
|
-
setup,
|
|
2388
|
-
unlock,
|
|
2389
|
-
lock,
|
|
2390
|
-
reset,
|
|
2391
|
-
signPayload,
|
|
2392
|
-
updateConfig,
|
|
2393
|
-
isBiometricAvailable
|
|
2394
|
-
};
|
|
2395
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SignlessContext.Provider, { value: contextValue, children });
|
|
2396
|
-
}
|
|
2397
|
-
function useSignless() {
|
|
2398
|
-
const context = React9.useContext(SignlessContext);
|
|
2399
|
-
if (!context) {
|
|
2400
|
-
throw new Error("useSignless must be used within a SignlessProvider");
|
|
2401
|
-
}
|
|
2402
|
-
return context;
|
|
2403
|
-
}
|
|
2404
|
-
function generateReference() {
|
|
2405
|
-
const bytes = new Uint8Array(16);
|
|
2406
|
-
crypto.getRandomValues(bytes);
|
|
2407
|
-
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2408
|
-
}
|
|
2409
|
-
function arrayBufferToBase642(buffer) {
|
|
2410
|
-
const bytes = new Uint8Array(buffer);
|
|
2411
|
-
let binary = "";
|
|
2412
|
-
for (let i = 0; i < bytes.byteLength; i++) {
|
|
2413
|
-
binary += String.fromCharCode(bytes[i]);
|
|
2414
|
-
}
|
|
2415
|
-
return btoa(binary);
|
|
2416
|
-
}
|
|
2417
|
-
|
|
2418
|
-
// src/signless/hooks/useTonPaySignless.ts
|
|
2419
|
-
|
|
2420
|
-
function useTonPaySignless() {
|
|
2421
|
-
const { pay, address } = useTonPay();
|
|
2422
|
-
const signlessContext = useSignless();
|
|
2423
|
-
const {
|
|
2424
|
-
state,
|
|
2425
|
-
config,
|
|
2426
|
-
setup,
|
|
2427
|
-
unlock,
|
|
2428
|
-
lock,
|
|
2429
|
-
reset,
|
|
2430
|
-
signPayload,
|
|
2431
|
-
updateConfig,
|
|
2432
|
-
isBiometricAvailable
|
|
2433
|
-
} = signlessContext;
|
|
2434
|
-
const paySignless = React10.useCallback(
|
|
2435
|
-
async (params) => {
|
|
2436
|
-
if (!config.enabled) {
|
|
2437
|
-
throw new Error("Signless is not enabled");
|
|
2438
|
-
}
|
|
2439
|
-
if (!state.isSetup) {
|
|
2440
|
-
throw new Error("Signless is not set up. Please complete setup first.");
|
|
2441
|
-
}
|
|
2442
|
-
if (!state.isUnlocked) {
|
|
2443
|
-
throw new Error("Signless is locked. Please unlock first.");
|
|
2444
|
-
}
|
|
2445
|
-
return signPayload(params);
|
|
2446
|
-
},
|
|
2447
|
-
[config.enabled, state.isSetup, state.isUnlocked, signPayload]
|
|
2448
|
-
);
|
|
2449
|
-
const requiresUnlock = React10.useMemo(() => {
|
|
2450
|
-
return config.enabled && state.isSetup && !state.isUnlocked;
|
|
2451
|
-
}, [config.enabled, state.isSetup, state.isUnlocked]);
|
|
2452
|
-
return {
|
|
2453
|
-
pay,
|
|
2454
|
-
paySignless,
|
|
2455
|
-
address,
|
|
2456
|
-
signless: {
|
|
2457
|
-
state,
|
|
2458
|
-
config,
|
|
2459
|
-
setup,
|
|
2460
|
-
unlock,
|
|
2461
|
-
lock,
|
|
2462
|
-
reset,
|
|
2463
|
-
updateConfig,
|
|
2464
|
-
isBiometricAvailable,
|
|
2465
|
-
isEnabled: config.enabled,
|
|
2466
|
-
isSetup: state.isSetup,
|
|
2467
|
-
isUnlocked: state.isUnlocked,
|
|
2468
|
-
requiresUnlock
|
|
2469
|
-
}
|
|
2470
|
-
};
|
|
2471
|
-
}
|
|
2472
|
-
|
|
2473
|
-
// src/signless/hooks/useSignlessModal.ts
|
|
2474
|
-
|
|
2475
|
-
function useSignlessModal() {
|
|
2476
|
-
const { state, config } = useSignless();
|
|
2477
|
-
const [modalType, setModalType] = React11.useState(null);
|
|
2478
|
-
const openSetup = React11.useCallback(() => {
|
|
2479
|
-
if (!config.enabled) {
|
|
2480
|
-
console.warn("Signless is not enabled");
|
|
2481
|
-
return;
|
|
2482
|
-
}
|
|
2483
|
-
setModalType("setup");
|
|
2484
|
-
}, [config.enabled]);
|
|
2485
|
-
const openUnlock = React11.useCallback(() => {
|
|
2486
|
-
if (!config.enabled) {
|
|
2487
|
-
console.warn("Signless is not enabled");
|
|
2488
|
-
return;
|
|
2489
|
-
}
|
|
2490
|
-
if (!state.isSetup) {
|
|
2491
|
-
console.warn("Signless is not set up");
|
|
2492
|
-
return;
|
|
2493
|
-
}
|
|
2494
|
-
setModalType("unlock");
|
|
2495
|
-
}, [config.enabled, state.isSetup]);
|
|
2496
|
-
const close = React11.useCallback(() => {
|
|
2497
|
-
setModalType(null);
|
|
2498
|
-
}, []);
|
|
2499
|
-
const onSetupComplete = React11.useCallback(() => {
|
|
2500
|
-
setModalType(null);
|
|
2501
|
-
}, []);
|
|
2502
|
-
const onUnlockComplete = React11.useCallback(() => {
|
|
2503
|
-
setModalType(null);
|
|
2504
|
-
}, []);
|
|
2505
|
-
return {
|
|
2506
|
-
modalType,
|
|
2507
|
-
isOpen: modalType !== null,
|
|
2508
|
-
openSetup,
|
|
2509
|
-
openUnlock,
|
|
2510
|
-
close,
|
|
2511
|
-
onSetupComplete,
|
|
2512
|
-
onUnlockComplete
|
|
2513
|
-
};
|
|
2514
|
-
}
|
|
2515
|
-
|
|
2516
|
-
// src/signless/components/PinInput.tsx
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
// src/signless/components/styles.ts
|
|
2520
|
-
var pinInputStyles = {
|
|
2521
|
-
container: {
|
|
2522
|
-
display: "flex",
|
|
2523
|
-
flexDirection: "column",
|
|
2524
|
-
alignItems: "center",
|
|
2525
|
-
padding: "24px",
|
|
2526
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
2527
|
-
color: "#ffffff",
|
|
2528
|
-
minWidth: "280px"
|
|
2529
|
-
},
|
|
2530
|
-
header: {
|
|
2531
|
-
textAlign: "center",
|
|
2532
|
-
marginBottom: "32px"
|
|
2533
|
-
},
|
|
2534
|
-
title: {
|
|
2535
|
-
fontSize: "20px",
|
|
2536
|
-
fontWeight: 600,
|
|
2537
|
-
margin: "0 0 8px 0",
|
|
2538
|
-
color: "#ffffff"
|
|
2539
|
-
},
|
|
2540
|
-
subtitle: {
|
|
2541
|
-
fontSize: "14px",
|
|
2542
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2543
|
-
margin: 0
|
|
2544
|
-
},
|
|
2545
|
-
hiddenInput: {
|
|
2546
|
-
position: "absolute",
|
|
2547
|
-
opacity: 0,
|
|
2548
|
-
pointerEvents: "none"
|
|
2549
|
-
},
|
|
2550
|
-
dotsContainer: {
|
|
2551
|
-
display: "flex",
|
|
2552
|
-
gap: "16px",
|
|
2553
|
-
marginBottom: "32px",
|
|
2554
|
-
cursor: "pointer"
|
|
2555
|
-
},
|
|
2556
|
-
dotsContainerShake: {
|
|
2557
|
-
animation: "tonpay-pin-shake 0.5s ease-in-out"
|
|
2558
|
-
},
|
|
2559
|
-
dot: {
|
|
2560
|
-
width: "14px",
|
|
2561
|
-
height: "14px",
|
|
2562
|
-
borderRadius: "50%",
|
|
2563
|
-
backgroundColor: "rgba(255, 255, 255, 0.2)",
|
|
2564
|
-
border: "2px solid rgba(255, 255, 255, 0.3)",
|
|
2565
|
-
transition: "all 0.15s ease"
|
|
2566
|
-
},
|
|
2567
|
-
dotFilled: {
|
|
2568
|
-
backgroundColor: "#0098EA",
|
|
2569
|
-
borderColor: "#0098EA",
|
|
2570
|
-
transform: "scale(1.1)"
|
|
2571
|
-
},
|
|
2572
|
-
dotLoading: {
|
|
2573
|
-
animation: "tonpay-pin-pulse 1s ease-in-out infinite"
|
|
2574
|
-
},
|
|
2575
|
-
error: {
|
|
2576
|
-
fontSize: "14px",
|
|
2577
|
-
color: "#FF5252",
|
|
2578
|
-
margin: "-16px 0 24px 0",
|
|
2579
|
-
textAlign: "center"
|
|
2580
|
-
},
|
|
2581
|
-
keypad: {
|
|
2582
|
-
display: "grid",
|
|
2583
|
-
gridTemplateColumns: "repeat(3, 1fr)",
|
|
2584
|
-
gap: "8px",
|
|
2585
|
-
width: "100%",
|
|
2586
|
-
maxWidth: "260px"
|
|
2587
|
-
},
|
|
2588
|
-
keypadButton: {
|
|
2589
|
-
width: "72px",
|
|
2590
|
-
height: "56px",
|
|
2591
|
-
fontSize: "24px",
|
|
2592
|
-
fontWeight: 500,
|
|
2593
|
-
color: "#ffffff",
|
|
2594
|
-
backgroundColor: "transparent",
|
|
2595
|
-
border: "none",
|
|
2596
|
-
borderRadius: "12px",
|
|
2597
|
-
cursor: "pointer",
|
|
2598
|
-
transition: "background-color 0.15s ease",
|
|
2599
|
-
display: "flex",
|
|
2600
|
-
alignItems: "center",
|
|
2601
|
-
justifyContent: "center"
|
|
2602
|
-
},
|
|
2603
|
-
keypadButtonEmpty: {
|
|
2604
|
-
width: "72px",
|
|
2605
|
-
height: "56px",
|
|
2606
|
-
display: "flex",
|
|
2607
|
-
alignItems: "center",
|
|
2608
|
-
justifyContent: "center"
|
|
2609
|
-
},
|
|
2610
|
-
biometricButton: {
|
|
2611
|
-
width: "56px",
|
|
2612
|
-
height: "56px",
|
|
2613
|
-
fontSize: "24px",
|
|
2614
|
-
color: "#0098EA",
|
|
2615
|
-
backgroundColor: "transparent",
|
|
2616
|
-
border: "none",
|
|
2617
|
-
borderRadius: "12px",
|
|
2618
|
-
cursor: "pointer",
|
|
2619
|
-
transition: "background-color 0.15s ease",
|
|
2620
|
-
display: "flex",
|
|
2621
|
-
alignItems: "center",
|
|
2622
|
-
justifyContent: "center"
|
|
2623
|
-
},
|
|
2624
|
-
backspaceButton: {
|
|
2625
|
-
width: "72px",
|
|
2626
|
-
height: "56px",
|
|
2627
|
-
fontSize: "24px",
|
|
2628
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2629
|
-
backgroundColor: "transparent",
|
|
2630
|
-
border: "none",
|
|
2631
|
-
borderRadius: "12px",
|
|
2632
|
-
cursor: "pointer",
|
|
2633
|
-
transition: "all 0.15s ease",
|
|
2634
|
-
display: "flex",
|
|
2635
|
-
alignItems: "center",
|
|
2636
|
-
justifyContent: "center"
|
|
2637
|
-
},
|
|
2638
|
-
cancelButton: {
|
|
2639
|
-
marginTop: "24px",
|
|
2640
|
-
padding: "12px 32px",
|
|
2641
|
-
fontSize: "16px",
|
|
2642
|
-
fontWeight: 500,
|
|
2643
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2644
|
-
backgroundColor: "transparent",
|
|
2645
|
-
border: "none",
|
|
2646
|
-
borderRadius: "8px",
|
|
2647
|
-
cursor: "pointer",
|
|
2648
|
-
transition: "color 0.15s ease"
|
|
2649
|
-
}
|
|
2650
|
-
};
|
|
2651
|
-
var setupModalStyles = {
|
|
2652
|
-
container: {
|
|
2653
|
-
display: "flex",
|
|
2654
|
-
flexDirection: "column",
|
|
2655
|
-
alignItems: "center",
|
|
2656
|
-
padding: "24px",
|
|
2657
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
2658
|
-
color: "#ffffff"
|
|
2659
|
-
},
|
|
2660
|
-
header: {
|
|
2661
|
-
textAlign: "center",
|
|
2662
|
-
marginBottom: "24px"
|
|
2663
|
-
},
|
|
2664
|
-
title: {
|
|
2665
|
-
fontSize: "22px",
|
|
2666
|
-
fontWeight: 600,
|
|
2667
|
-
margin: "0 0 8px 0",
|
|
2668
|
-
color: "#ffffff"
|
|
2669
|
-
},
|
|
2670
|
-
subtitle: {
|
|
2671
|
-
fontSize: "14px",
|
|
2672
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2673
|
-
margin: 0,
|
|
2674
|
-
lineHeight: 1.5,
|
|
2675
|
-
maxWidth: "280px"
|
|
2676
|
-
},
|
|
2677
|
-
methodSelector: {
|
|
2678
|
-
display: "flex",
|
|
2679
|
-
flexDirection: "column",
|
|
2680
|
-
gap: "12px",
|
|
2681
|
-
width: "100%",
|
|
2682
|
-
marginBottom: "24px"
|
|
2683
|
-
},
|
|
2684
|
-
methodButton: {
|
|
2685
|
-
display: "flex",
|
|
2686
|
-
alignItems: "center",
|
|
2687
|
-
gap: "16px",
|
|
2688
|
-
padding: "16px",
|
|
2689
|
-
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
|
2690
|
-
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
2691
|
-
borderRadius: "12px",
|
|
2692
|
-
cursor: "pointer",
|
|
2693
|
-
transition: "all 0.15s ease",
|
|
2694
|
-
textAlign: "left",
|
|
2695
|
-
width: "100%"
|
|
2696
|
-
},
|
|
2697
|
-
methodButtonSelected: {
|
|
2698
|
-
backgroundColor: "rgba(0, 152, 234, 0.15)",
|
|
2699
|
-
borderColor: "#0098EA"
|
|
2700
|
-
},
|
|
2701
|
-
methodIcon: {
|
|
2702
|
-
width: "48px",
|
|
2703
|
-
height: "48px",
|
|
2704
|
-
borderRadius: "12px",
|
|
2705
|
-
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
2706
|
-
display: "flex",
|
|
2707
|
-
alignItems: "center",
|
|
2708
|
-
justifyContent: "center",
|
|
2709
|
-
color: "#0098EA",
|
|
2710
|
-
flexShrink: 0
|
|
2711
|
-
},
|
|
2712
|
-
methodContent: {
|
|
2713
|
-
flex: 1,
|
|
2714
|
-
minWidth: 0
|
|
2715
|
-
},
|
|
2716
|
-
methodTitle: {
|
|
2717
|
-
fontSize: "16px",
|
|
2718
|
-
fontWeight: 600,
|
|
2719
|
-
color: "#ffffff",
|
|
2720
|
-
margin: "0 0 4px 0"
|
|
2721
|
-
},
|
|
2722
|
-
methodDescription: {
|
|
2723
|
-
fontSize: "13px",
|
|
2724
|
-
color: "rgba(255, 255, 255, 0.5)",
|
|
2725
|
-
margin: 0,
|
|
2726
|
-
lineHeight: 1.4
|
|
2727
|
-
},
|
|
2728
|
-
continueButton: {
|
|
2729
|
-
width: "100%",
|
|
2730
|
-
padding: "14px 24px",
|
|
2731
|
-
fontSize: "16px",
|
|
2732
|
-
fontWeight: 600,
|
|
2733
|
-
color: "#ffffff",
|
|
2734
|
-
backgroundColor: "#0098EA",
|
|
2735
|
-
border: "none",
|
|
2736
|
-
borderRadius: "12px",
|
|
2737
|
-
cursor: "pointer",
|
|
2738
|
-
transition: "opacity 0.15s ease"
|
|
2739
|
-
},
|
|
2740
|
-
continueButtonDisabled: {
|
|
2741
|
-
opacity: 0.5,
|
|
2742
|
-
cursor: "not-allowed"
|
|
2743
|
-
},
|
|
2744
|
-
stepIndicator: {
|
|
2745
|
-
display: "flex",
|
|
2746
|
-
gap: "8px",
|
|
2747
|
-
marginBottom: "24px"
|
|
2748
|
-
},
|
|
2749
|
-
stepDot: {
|
|
2750
|
-
width: "8px",
|
|
2751
|
-
height: "8px",
|
|
2752
|
-
borderRadius: "50%",
|
|
2753
|
-
backgroundColor: "rgba(255, 255, 255, 0.2)"
|
|
2754
|
-
},
|
|
2755
|
-
stepDotActive: {
|
|
2756
|
-
backgroundColor: "#0098EA"
|
|
2757
|
-
}
|
|
2758
|
-
};
|
|
2759
|
-
var unlockModalStyles = {
|
|
2760
|
-
container: {
|
|
2761
|
-
display: "flex",
|
|
2762
|
-
flexDirection: "column",
|
|
2763
|
-
alignItems: "center",
|
|
2764
|
-
padding: "24px",
|
|
2765
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
2766
|
-
color: "#ffffff"
|
|
2767
|
-
},
|
|
2768
|
-
biometricPrompt: {
|
|
2769
|
-
display: "flex",
|
|
2770
|
-
flexDirection: "column",
|
|
2771
|
-
alignItems: "center",
|
|
2772
|
-
padding: "32px",
|
|
2773
|
-
textAlign: "center"
|
|
2774
|
-
},
|
|
2775
|
-
biometricIcon: {
|
|
2776
|
-
width: "80px",
|
|
2777
|
-
height: "80px",
|
|
2778
|
-
borderRadius: "20px",
|
|
2779
|
-
backgroundColor: "rgba(0, 152, 234, 0.15)",
|
|
2780
|
-
display: "flex",
|
|
2781
|
-
alignItems: "center",
|
|
2782
|
-
justifyContent: "center",
|
|
2783
|
-
color: "#0098EA",
|
|
2784
|
-
marginBottom: "24px"
|
|
2785
|
-
},
|
|
2786
|
-
biometricTitle: {
|
|
2787
|
-
fontSize: "20px",
|
|
2788
|
-
fontWeight: 600,
|
|
2789
|
-
margin: "0 0 8px 0",
|
|
2790
|
-
color: "#ffffff"
|
|
2791
|
-
},
|
|
2792
|
-
biometricSubtitle: {
|
|
2793
|
-
fontSize: "14px",
|
|
2794
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
2795
|
-
margin: "0 0 24px 0"
|
|
2796
|
-
},
|
|
2797
|
-
usePinButton: {
|
|
2798
|
-
padding: "12px 24px",
|
|
2799
|
-
fontSize: "14px",
|
|
2800
|
-
fontWeight: 500,
|
|
2801
|
-
color: "#0098EA",
|
|
2802
|
-
backgroundColor: "transparent",
|
|
2803
|
-
border: "none",
|
|
2804
|
-
cursor: "pointer",
|
|
2805
|
-
transition: "opacity 0.15s ease"
|
|
2806
|
-
}
|
|
2807
|
-
};
|
|
2808
|
-
|
|
2809
|
-
// src/signless/components/PinInput.tsx
|
|
2810
|
-
|
|
2811
|
-
var PIN_LENGTH = 6;
|
|
2812
|
-
var PinInput = ({
|
|
2813
|
-
length = PIN_LENGTH,
|
|
2814
|
-
onComplete,
|
|
2815
|
-
onCancel,
|
|
2816
|
-
title = "Enter PIN",
|
|
2817
|
-
subtitle,
|
|
2818
|
-
error,
|
|
2819
|
-
isLoading = false,
|
|
2820
|
-
showBiometric = false,
|
|
2821
|
-
onBiometricPress
|
|
2822
|
-
}) => {
|
|
2823
|
-
const [pin, setPin] = React12.useState("");
|
|
2824
|
-
const [shake, setShake] = React12.useState(false);
|
|
2825
|
-
const inputRef = React12.useRef(null);
|
|
2826
|
-
React12.useEffect(() => {
|
|
2827
|
-
if (error) {
|
|
2828
|
-
setShake(true);
|
|
2829
|
-
setPin("");
|
|
2830
|
-
const timer = setTimeout(() => setShake(false), 500);
|
|
2831
|
-
return () => clearTimeout(timer);
|
|
2832
|
-
}
|
|
2833
|
-
}, [error]);
|
|
2834
|
-
React12.useEffect(() => {
|
|
2835
|
-
_optionalChain([inputRef, 'access', _43 => _43.current, 'optionalAccess', _44 => _44.focus, 'call', _45 => _45()]);
|
|
2836
|
-
}, []);
|
|
2837
|
-
const handleChange = (e) => {
|
|
2838
|
-
const value = e.target.value.replace(/\D/g, "").slice(0, length);
|
|
2839
|
-
setPin(value);
|
|
2840
|
-
if (value.length === length) {
|
|
2841
|
-
onComplete(value);
|
|
2842
|
-
}
|
|
2843
|
-
};
|
|
2844
|
-
const handleKeyDown = (e) => {
|
|
2845
|
-
if (e.key === "Escape" && onCancel) {
|
|
2846
|
-
onCancel();
|
|
2847
|
-
}
|
|
2848
|
-
};
|
|
2849
|
-
const handleDotClick = () => {
|
|
2850
|
-
_optionalChain([inputRef, 'access', _46 => _46.current, 'optionalAccess', _47 => _47.focus, 'call', _48 => _48()]);
|
|
2851
|
-
};
|
|
2852
|
-
const handleKeyPress = (digit) => {
|
|
2853
|
-
if (pin.length >= length || isLoading) return;
|
|
2854
|
-
const newPin = pin + digit;
|
|
2855
|
-
setPin(newPin);
|
|
2856
|
-
if (newPin.length === length) {
|
|
2857
|
-
onComplete(newPin);
|
|
2858
|
-
}
|
|
2859
|
-
};
|
|
2860
|
-
const handleBackspace = () => {
|
|
2861
|
-
if (isLoading) return;
|
|
2862
|
-
setPin((prev) => prev.slice(0, -1));
|
|
2863
|
-
};
|
|
2864
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: pinInputStyles.container, children: [
|
|
2865
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "style", { children: keyframes }),
|
|
2866
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: pinInputStyles.header, children: [
|
|
2867
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { style: pinInputStyles.title, children: title }),
|
|
2868
|
-
subtitle && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: pinInputStyles.subtitle, children: subtitle })
|
|
2869
|
-
] }),
|
|
2870
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2871
|
-
"input",
|
|
2872
|
-
{
|
|
2873
|
-
ref: inputRef,
|
|
2874
|
-
type: "text",
|
|
2875
|
-
inputMode: "numeric",
|
|
2876
|
-
pattern: "[0-9]*",
|
|
2877
|
-
value: pin,
|
|
2878
|
-
onChange: handleChange,
|
|
2879
|
-
onKeyDown: handleKeyDown,
|
|
2880
|
-
maxLength: length,
|
|
2881
|
-
autoComplete: "off",
|
|
2882
|
-
style: pinInputStyles.hiddenInput,
|
|
2883
|
-
disabled: isLoading
|
|
2884
|
-
}
|
|
2885
|
-
),
|
|
2886
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2887
|
-
"div",
|
|
2888
|
-
{
|
|
2889
|
-
style: {
|
|
2890
|
-
...pinInputStyles.dotsContainer,
|
|
2891
|
-
...shake ? pinInputStyles.dotsContainerShake : {}
|
|
2892
|
-
},
|
|
2893
|
-
onClick: handleDotClick,
|
|
2894
|
-
children: Array.from({ length }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2895
|
-
"div",
|
|
2896
|
-
{
|
|
2897
|
-
style: {
|
|
2898
|
-
...pinInputStyles.dot,
|
|
2899
|
-
...i < pin.length ? pinInputStyles.dotFilled : {},
|
|
2900
|
-
...isLoading ? pinInputStyles.dotLoading : {}
|
|
2901
|
-
}
|
|
2902
|
-
},
|
|
2903
|
-
i
|
|
2904
|
-
))
|
|
2905
|
-
}
|
|
2906
|
-
),
|
|
2907
|
-
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: pinInputStyles.error, children: error }),
|
|
2908
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: pinInputStyles.keypad, children: [
|
|
2909
|
-
[1, 2, 3, 4, 5, 6, 7, 8, 9].map((digit) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2910
|
-
"button",
|
|
2911
|
-
{
|
|
2912
|
-
type: "button",
|
|
2913
|
-
style: pinInputStyles.keypadButton,
|
|
2914
|
-
onClick: () => handleKeyPress(String(digit)),
|
|
2915
|
-
disabled: isLoading,
|
|
2916
|
-
onMouseEnter: (e) => {
|
|
2917
|
-
e.target.style.backgroundColor = "rgba(255, 255, 255, 0.1)";
|
|
2918
|
-
},
|
|
2919
|
-
onMouseLeave: (e) => {
|
|
2920
|
-
e.target.style.backgroundColor = "transparent";
|
|
2921
|
-
},
|
|
2922
|
-
children: digit
|
|
2923
|
-
},
|
|
2924
|
-
digit
|
|
2925
|
-
)),
|
|
2926
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: pinInputStyles.keypadButtonEmpty, children: showBiometric && onBiometricPress && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2927
|
-
"button",
|
|
2928
|
-
{
|
|
2929
|
-
type: "button",
|
|
2930
|
-
style: pinInputStyles.biometricButton,
|
|
2931
|
-
onClick: onBiometricPress,
|
|
2932
|
-
disabled: isLoading,
|
|
2933
|
-
"aria-label": "Use biometric authentication",
|
|
2934
|
-
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BiometricIcon, {})
|
|
2935
|
-
}
|
|
2936
|
-
) }),
|
|
2937
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2938
|
-
"button",
|
|
2939
|
-
{
|
|
2940
|
-
type: "button",
|
|
2941
|
-
style: pinInputStyles.keypadButton,
|
|
2942
|
-
onClick: () => handleKeyPress("0"),
|
|
2943
|
-
disabled: isLoading,
|
|
2944
|
-
onMouseEnter: (e) => {
|
|
2945
|
-
e.target.style.backgroundColor = "rgba(255, 255, 255, 0.1)";
|
|
2946
|
-
},
|
|
2947
|
-
onMouseLeave: (e) => {
|
|
2948
|
-
e.target.style.backgroundColor = "transparent";
|
|
2949
|
-
},
|
|
2950
|
-
children: "0"
|
|
2951
|
-
}
|
|
2952
|
-
),
|
|
2953
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2954
|
-
"button",
|
|
2955
|
-
{
|
|
2956
|
-
type: "button",
|
|
2957
|
-
style: pinInputStyles.backspaceButton,
|
|
2958
|
-
onClick: handleBackspace,
|
|
2959
|
-
disabled: isLoading || pin.length === 0,
|
|
2960
|
-
"aria-label": "Backspace",
|
|
2961
|
-
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BackspaceIcon, {})
|
|
2962
|
-
}
|
|
2963
|
-
)
|
|
2964
|
-
] }),
|
|
2965
|
-
onCancel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2966
|
-
"button",
|
|
2967
|
-
{
|
|
2968
|
-
type: "button",
|
|
2969
|
-
style: pinInputStyles.cancelButton,
|
|
2970
|
-
onClick: onCancel,
|
|
2971
|
-
disabled: isLoading,
|
|
2972
|
-
children: "Cancel"
|
|
2973
|
-
}
|
|
2974
|
-
)
|
|
2975
|
-
] });
|
|
2976
|
-
};
|
|
2977
|
-
var BiometricIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2978
|
-
"svg",
|
|
2979
|
-
{
|
|
2980
|
-
width: "28",
|
|
2981
|
-
height: "28",
|
|
2982
|
-
viewBox: "0 0 24 24",
|
|
2983
|
-
fill: "none",
|
|
2984
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
2985
|
-
children: [
|
|
2986
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2987
|
-
"path",
|
|
2988
|
-
{
|
|
2989
|
-
d: "M12 14.5V16.5M7 10.5C7 7.73858 9.23858 5.5 12 5.5C14.7614 5.5 17 7.73858 17 10.5V11.5M12 11.5C10.6193 11.5 9.5 12.6193 9.5 14C9.5 15.3807 10.6193 16.5 12 16.5C13.3807 16.5 14.5 15.3807 14.5 14C14.5 12.6193 13.3807 11.5 12 11.5Z",
|
|
2990
|
-
stroke: "currentColor",
|
|
2991
|
-
strokeWidth: "1.5",
|
|
2992
|
-
strokeLinecap: "round",
|
|
2993
|
-
strokeLinejoin: "round"
|
|
2994
|
-
}
|
|
2995
|
-
),
|
|
2996
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2997
|
-
"path",
|
|
2998
|
-
{
|
|
2999
|
-
d: "M3 7V5C3 3.89543 3.89543 3 5 3H7M17 3H19C20.1046 3 21 3.89543 21 5V7M21 17V19C21 20.1046 20.1046 21 19 21H17M7 21H5C3.89543 21 3 20.1046 3 19V17",
|
|
3000
|
-
stroke: "currentColor",
|
|
3001
|
-
strokeWidth: "1.5",
|
|
3002
|
-
strokeLinecap: "round",
|
|
3003
|
-
strokeLinejoin: "round"
|
|
3004
|
-
}
|
|
3005
|
-
)
|
|
3006
|
-
]
|
|
3007
|
-
}
|
|
3008
|
-
);
|
|
3009
|
-
var BackspaceIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3010
|
-
"svg",
|
|
3011
|
-
{
|
|
3012
|
-
width: "24",
|
|
3013
|
-
height: "24",
|
|
3014
|
-
viewBox: "0 0 24 24",
|
|
3015
|
-
fill: "none",
|
|
3016
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
3017
|
-
children: [
|
|
3018
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3019
|
-
"path",
|
|
3020
|
-
{
|
|
3021
|
-
d: "M9.00195 7L4.00195 12L9.00195 17M19.002 7H8.00195L4.00195 12L8.00195 17H19.002C19.5325 17 20.0412 16.7893 20.4163 16.4142C20.7914 16.0391 21.002 15.5304 21.002 15V9C21.002 8.46957 20.7914 7.96086 20.4163 7.58579C20.0412 7.21071 19.5325 7 19.002 7Z",
|
|
3022
|
-
stroke: "currentColor",
|
|
3023
|
-
strokeWidth: "1.5",
|
|
3024
|
-
strokeLinecap: "round",
|
|
3025
|
-
strokeLinejoin: "round"
|
|
3026
|
-
}
|
|
3027
|
-
),
|
|
3028
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3029
|
-
"path",
|
|
3030
|
-
{
|
|
3031
|
-
d: "M14 10L10 14M10 10L14 14",
|
|
3032
|
-
stroke: "currentColor",
|
|
3033
|
-
strokeWidth: "1.5",
|
|
3034
|
-
strokeLinecap: "round",
|
|
3035
|
-
strokeLinejoin: "round"
|
|
3036
|
-
}
|
|
3037
|
-
)
|
|
3038
|
-
]
|
|
3039
|
-
}
|
|
3040
|
-
);
|
|
3041
|
-
var keyframes = `
|
|
3042
|
-
@keyframes tonpay-pin-shake {
|
|
3043
|
-
0%, 100% { transform: translateX(0); }
|
|
3044
|
-
10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
|
|
3045
|
-
20%, 40%, 60%, 80% { transform: translateX(4px); }
|
|
3046
|
-
}
|
|
3047
|
-
@keyframes tonpay-pin-pulse {
|
|
3048
|
-
0%, 100% { opacity: 1; }
|
|
3049
|
-
50% { opacity: 0.5; }
|
|
3050
|
-
}
|
|
3051
|
-
`;
|
|
3052
|
-
|
|
3053
|
-
// src/signless/components/SignlessSetupModal.tsx
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
var SignlessSetupModal = ({
|
|
3057
|
-
isOpen,
|
|
3058
|
-
onClose,
|
|
3059
|
-
onComplete,
|
|
3060
|
-
showBiometric = true
|
|
3061
|
-
}) => {
|
|
3062
|
-
const { setup, isBiometricAvailable, state } = useSignless();
|
|
3063
|
-
const [step, setStep] = React13.useState("select_method");
|
|
3064
|
-
const [selectedMethod, setSelectedMethod] = React13.useState(null);
|
|
3065
|
-
const [pin, setPin] = React13.useState("");
|
|
3066
|
-
const [error, setError] = React13.useState(null);
|
|
3067
|
-
const [isLoading, setIsLoading] = React13.useState(false);
|
|
3068
|
-
React13.useEffect(() => {
|
|
3069
|
-
if (isOpen) {
|
|
3070
|
-
setStep("select_method");
|
|
3071
|
-
setSelectedMethod(null);
|
|
3072
|
-
setPin("");
|
|
3073
|
-
setError(null);
|
|
3074
|
-
setIsLoading(false);
|
|
3075
|
-
}
|
|
3076
|
-
}, [isOpen]);
|
|
3077
|
-
const handleMethodSelect = (method) => {
|
|
3078
|
-
setSelectedMethod(method);
|
|
3079
|
-
};
|
|
3080
|
-
const handleContinue = async () => {
|
|
3081
|
-
if (!selectedMethod) return;
|
|
3082
|
-
if (selectedMethod === "biometric") {
|
|
3083
|
-
setIsLoading(true);
|
|
3084
|
-
setError(null);
|
|
3085
|
-
try {
|
|
3086
|
-
await setup({ authMethod: "biometric" });
|
|
3087
|
-
onComplete();
|
|
3088
|
-
onClose();
|
|
3089
|
-
} catch (err) {
|
|
3090
|
-
setError(
|
|
3091
|
-
err instanceof Error ? err.message : "Biometric setup failed"
|
|
3092
|
-
);
|
|
3093
|
-
} finally {
|
|
3094
|
-
setIsLoading(false);
|
|
3095
|
-
}
|
|
3096
|
-
} else if (selectedMethod === "pin") {
|
|
3097
|
-
setStep("create_pin");
|
|
3098
|
-
}
|
|
3099
|
-
};
|
|
3100
|
-
const handlePinCreate = (newPin) => {
|
|
3101
|
-
setPin(newPin);
|
|
3102
|
-
setError(null);
|
|
3103
|
-
setStep("confirm_pin");
|
|
3104
|
-
};
|
|
3105
|
-
const handlePinConfirm = async (confirmPin) => {
|
|
3106
|
-
if (confirmPin !== pin) {
|
|
3107
|
-
setError("PINs do not match. Please try again.");
|
|
3108
|
-
setStep("create_pin");
|
|
3109
|
-
setPin("");
|
|
3110
|
-
return;
|
|
3111
|
-
}
|
|
3112
|
-
setIsLoading(true);
|
|
3113
|
-
setError(null);
|
|
3114
|
-
try {
|
|
3115
|
-
await setup({ authMethod: "pin", pin });
|
|
3116
|
-
onComplete();
|
|
3117
|
-
onClose();
|
|
3118
|
-
} catch (err) {
|
|
3119
|
-
setError(err instanceof Error ? err.message : "Setup failed");
|
|
3120
|
-
setStep("create_pin");
|
|
3121
|
-
setPin("");
|
|
3122
|
-
} finally {
|
|
3123
|
-
setIsLoading(false);
|
|
3124
|
-
}
|
|
3125
|
-
};
|
|
3126
|
-
const handleBack = () => {
|
|
3127
|
-
if (step === "confirm_pin") {
|
|
3128
|
-
setStep("create_pin");
|
|
3129
|
-
setError(null);
|
|
3130
|
-
} else if (step === "create_pin") {
|
|
3131
|
-
setStep("select_method");
|
|
3132
|
-
setPin("");
|
|
3133
|
-
setError(null);
|
|
3134
|
-
}
|
|
3135
|
-
};
|
|
3136
|
-
if (!isOpen) return null;
|
|
3137
|
-
const renderStepIndicator = () => {
|
|
3138
|
-
const steps = selectedMethod === "pin" ? 3 : 2;
|
|
3139
|
-
const currentStep = step === "select_method" ? 1 : step === "create_pin" ? 2 : 3;
|
|
3140
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: setupModalStyles.stepIndicator, children: Array.from({ length: steps }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3141
|
-
"div",
|
|
3142
|
-
{
|
|
3143
|
-
style: {
|
|
3144
|
-
...setupModalStyles.stepDot,
|
|
3145
|
-
...i < currentStep ? setupModalStyles.stepDotActive : {}
|
|
3146
|
-
}
|
|
3147
|
-
},
|
|
3148
|
-
i
|
|
3149
|
-
)) });
|
|
3150
|
-
};
|
|
3151
|
-
const renderMethodSelection = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3152
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.header, children: [
|
|
3153
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { style: setupModalStyles.title, children: "Setup Signless" }),
|
|
3154
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: setupModalStyles.subtitle, children: "Enable fast payments without wallet confirmations. Choose your preferred authentication method." })
|
|
3155
|
-
] }),
|
|
3156
|
-
renderStepIndicator(),
|
|
3157
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.methodSelector, children: [
|
|
3158
|
-
showBiometric && isBiometricAvailable && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3159
|
-
"button",
|
|
3160
|
-
{
|
|
3161
|
-
type: "button",
|
|
3162
|
-
style: {
|
|
3163
|
-
...setupModalStyles.methodButton,
|
|
3164
|
-
...selectedMethod === "biometric" ? setupModalStyles.methodButtonSelected : {}
|
|
3165
|
-
},
|
|
3166
|
-
onClick: () => handleMethodSelect("biometric"),
|
|
3167
|
-
children: [
|
|
3168
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: setupModalStyles.methodIcon, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FaceIdIcon, {}) }),
|
|
3169
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.methodContent, children: [
|
|
3170
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { style: setupModalStyles.methodTitle, children: "Face ID / Touch ID" }),
|
|
3171
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: setupModalStyles.methodDescription, children: "Use biometric authentication for quick and secure access" })
|
|
3172
|
-
] })
|
|
3173
|
-
]
|
|
3174
|
-
}
|
|
3175
|
-
),
|
|
3176
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3177
|
-
"button",
|
|
3178
|
-
{
|
|
3179
|
-
type: "button",
|
|
3180
|
-
style: {
|
|
3181
|
-
...setupModalStyles.methodButton,
|
|
3182
|
-
...selectedMethod === "pin" ? setupModalStyles.methodButtonSelected : {}
|
|
3183
|
-
},
|
|
3184
|
-
onClick: () => handleMethodSelect("pin"),
|
|
3185
|
-
children: [
|
|
3186
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: setupModalStyles.methodIcon, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PinIcon, {}) }),
|
|
3187
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.methodContent, children: [
|
|
3188
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { style: setupModalStyles.methodTitle, children: "PIN Code" }),
|
|
3189
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: setupModalStyles.methodDescription, children: "Create a 6-digit PIN for payment authorization" })
|
|
3190
|
-
] })
|
|
3191
|
-
]
|
|
3192
|
-
}
|
|
3193
|
-
)
|
|
3194
|
-
] }),
|
|
3195
|
-
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { color: "#FF5252", fontSize: "14px", marginBottom: "16px" }, children: error }),
|
|
3196
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3197
|
-
"button",
|
|
3198
|
-
{
|
|
3199
|
-
type: "button",
|
|
3200
|
-
style: {
|
|
3201
|
-
...setupModalStyles.continueButton,
|
|
3202
|
-
...!selectedMethod ? setupModalStyles.continueButtonDisabled : {}
|
|
3203
|
-
},
|
|
3204
|
-
onClick: handleContinue,
|
|
3205
|
-
disabled: !selectedMethod || isLoading,
|
|
3206
|
-
children: isLoading ? "Setting up..." : "Continue"
|
|
3207
|
-
}
|
|
3208
|
-
)
|
|
3209
|
-
] });
|
|
3210
|
-
const renderPinCreation = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3211
|
-
renderStepIndicator(),
|
|
3212
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3213
|
-
PinInput,
|
|
3214
|
-
{
|
|
3215
|
-
title: "Create PIN",
|
|
3216
|
-
subtitle: "Enter a 6-digit PIN to secure your signless payments",
|
|
3217
|
-
onComplete: handlePinCreate,
|
|
3218
|
-
onCancel: handleBack,
|
|
3219
|
-
error,
|
|
3220
|
-
isLoading
|
|
3221
|
-
}
|
|
3222
|
-
)
|
|
3223
|
-
] });
|
|
3224
|
-
const renderPinConfirmation = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3225
|
-
renderStepIndicator(),
|
|
3226
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3227
|
-
PinInput,
|
|
3228
|
-
{
|
|
3229
|
-
title: "Confirm PIN",
|
|
3230
|
-
subtitle: "Re-enter your PIN to confirm",
|
|
3231
|
-
onComplete: handlePinConfirm,
|
|
3232
|
-
onCancel: handleBack,
|
|
3233
|
-
error,
|
|
3234
|
-
isLoading
|
|
3235
|
-
}
|
|
3236
|
-
)
|
|
3237
|
-
] });
|
|
3238
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: setupModalStyles.container, children: [
|
|
3239
|
-
step === "select_method" && renderMethodSelection(),
|
|
3240
|
-
step === "create_pin" && renderPinCreation(),
|
|
3241
|
-
step === "confirm_pin" && renderPinConfirmation()
|
|
3242
|
-
] });
|
|
3243
|
-
};
|
|
3244
|
-
var FaceIdIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3245
|
-
"svg",
|
|
3246
|
-
{
|
|
3247
|
-
width: "28",
|
|
3248
|
-
height: "28",
|
|
3249
|
-
viewBox: "0 0 24 24",
|
|
3250
|
-
fill: "none",
|
|
3251
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
3252
|
-
children: [
|
|
3253
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3254
|
-
"path",
|
|
3255
|
-
{
|
|
3256
|
-
d: "M12 14.5V16.5M7 10.5C7 7.73858 9.23858 5.5 12 5.5C14.7614 5.5 17 7.73858 17 10.5V11.5M12 11.5C10.6193 11.5 9.5 12.6193 9.5 14C9.5 15.3807 10.6193 16.5 12 16.5C13.3807 16.5 14.5 15.3807 14.5 14C14.5 12.6193 13.3807 11.5 12 11.5Z",
|
|
3257
|
-
stroke: "currentColor",
|
|
3258
|
-
strokeWidth: "1.5",
|
|
3259
|
-
strokeLinecap: "round",
|
|
3260
|
-
strokeLinejoin: "round"
|
|
3261
|
-
}
|
|
3262
|
-
),
|
|
3263
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3264
|
-
"path",
|
|
3265
|
-
{
|
|
3266
|
-
d: "M3 7V5C3 3.89543 3.89543 3 5 3H7M17 3H19C20.1046 3 21 3.89543 21 5V7M21 17V19C21 20.1046 20.1046 21 19 21H17M7 21H5C3.89543 21 3 20.1046 3 19V17",
|
|
3267
|
-
stroke: "currentColor",
|
|
3268
|
-
strokeWidth: "1.5",
|
|
3269
|
-
strokeLinecap: "round",
|
|
3270
|
-
strokeLinejoin: "round"
|
|
3271
|
-
}
|
|
3272
|
-
)
|
|
3273
|
-
]
|
|
3274
|
-
}
|
|
3275
|
-
);
|
|
3276
|
-
var PinIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3277
|
-
"svg",
|
|
3278
|
-
{
|
|
3279
|
-
width: "28",
|
|
3280
|
-
height: "28",
|
|
3281
|
-
viewBox: "0 0 24 24",
|
|
3282
|
-
fill: "none",
|
|
3283
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
3284
|
-
children: [
|
|
3285
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3286
|
-
"rect",
|
|
3287
|
-
{
|
|
3288
|
-
x: "3",
|
|
3289
|
-
y: "6",
|
|
3290
|
-
width: "18",
|
|
3291
|
-
height: "12",
|
|
3292
|
-
rx: "2",
|
|
3293
|
-
stroke: "currentColor",
|
|
3294
|
-
strokeWidth: "1.5"
|
|
3295
|
-
}
|
|
3296
|
-
),
|
|
3297
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "7", cy: "12", r: "1.5", fill: "currentColor" }),
|
|
3298
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "12", cy: "12", r: "1.5", fill: "currentColor" }),
|
|
3299
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "17", cy: "12", r: "1.5", fill: "currentColor" })
|
|
3300
|
-
]
|
|
3301
|
-
}
|
|
3302
|
-
);
|
|
3303
|
-
|
|
3304
|
-
// src/signless/components/SignlessUnlockModal.tsx
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
var SignlessUnlockModal = ({
|
|
3308
|
-
isOpen,
|
|
3309
|
-
onClose,
|
|
3310
|
-
onUnlock,
|
|
3311
|
-
showBiometric = true
|
|
3312
|
-
}) => {
|
|
3313
|
-
const { unlock, state, isBiometricAvailable } = useSignless();
|
|
3314
|
-
const [view, setView] = React14.useState("biometric");
|
|
3315
|
-
const [error, setError] = React14.useState(null);
|
|
3316
|
-
const [isLoading, setIsLoading] = React14.useState(false);
|
|
3317
|
-
const shouldShowBiometric = showBiometric && isBiometricAvailable && state.authMethod === "biometric";
|
|
3318
|
-
React14.useEffect(() => {
|
|
3319
|
-
if (isOpen) {
|
|
3320
|
-
setError(null);
|
|
3321
|
-
setIsLoading(false);
|
|
3322
|
-
setView(shouldShowBiometric ? "biometric" : "pin");
|
|
3323
|
-
}
|
|
3324
|
-
}, [isOpen, shouldShowBiometric]);
|
|
3325
|
-
React14.useEffect(() => {
|
|
3326
|
-
if (isOpen && view === "biometric" && shouldShowBiometric) {
|
|
3327
|
-
handleBiometricAuth();
|
|
3328
|
-
}
|
|
3329
|
-
}, [isOpen, view]);
|
|
3330
|
-
const handleBiometricAuth = async () => {
|
|
3331
|
-
setIsLoading(true);
|
|
3332
|
-
setError(null);
|
|
3333
|
-
try {
|
|
3334
|
-
await unlock({});
|
|
3335
|
-
onUnlock();
|
|
3336
|
-
onClose();
|
|
3337
|
-
} catch (err) {
|
|
3338
|
-
setError(
|
|
3339
|
-
err instanceof Error ? err.message : "Biometric authentication failed"
|
|
3340
|
-
);
|
|
3341
|
-
setView("pin");
|
|
3342
|
-
} finally {
|
|
3343
|
-
setIsLoading(false);
|
|
3344
|
-
}
|
|
3345
|
-
};
|
|
3346
|
-
const handlePinSubmit = async (pin) => {
|
|
3347
|
-
setIsLoading(true);
|
|
3348
|
-
setError(null);
|
|
3349
|
-
try {
|
|
3350
|
-
await unlock({ pin });
|
|
3351
|
-
onUnlock();
|
|
3352
|
-
onClose();
|
|
3353
|
-
} catch (err) {
|
|
3354
|
-
setError("Invalid PIN. Please try again.");
|
|
3355
|
-
} finally {
|
|
3356
|
-
setIsLoading(false);
|
|
3357
|
-
}
|
|
3358
|
-
};
|
|
3359
|
-
const handleUsePinInstead = () => {
|
|
3360
|
-
setView("pin");
|
|
3361
|
-
setError(null);
|
|
3362
|
-
};
|
|
3363
|
-
if (!isOpen) return null;
|
|
3364
|
-
const renderBiometricPrompt = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: unlockModalStyles.biometricPrompt, children: [
|
|
3365
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: unlockModalStyles.biometricIcon, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BiometricLargeIcon, {}) }),
|
|
3366
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { style: unlockModalStyles.biometricTitle, children: "Unlock Signless" }),
|
|
3367
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: unlockModalStyles.biometricSubtitle, children: isLoading ? "Authenticating..." : "Use Face ID or Touch ID to continue" }),
|
|
3368
|
-
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { color: "#FF5252", fontSize: "14px", marginBottom: "16px" }, children: error }),
|
|
3369
|
-
!isLoading && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3370
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3371
|
-
"button",
|
|
3372
|
-
{
|
|
3373
|
-
type: "button",
|
|
3374
|
-
style: {
|
|
3375
|
-
padding: "14px 32px",
|
|
3376
|
-
fontSize: "16px",
|
|
3377
|
-
fontWeight: 600,
|
|
3378
|
-
color: "#ffffff",
|
|
3379
|
-
backgroundColor: "#0098EA",
|
|
3380
|
-
border: "none",
|
|
3381
|
-
borderRadius: "12px",
|
|
3382
|
-
cursor: "pointer",
|
|
3383
|
-
marginBottom: "16px"
|
|
3384
|
-
},
|
|
3385
|
-
onClick: handleBiometricAuth,
|
|
3386
|
-
children: "Try Again"
|
|
3387
|
-
}
|
|
3388
|
-
),
|
|
3389
|
-
state.authMethod === "biometric" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3390
|
-
"button",
|
|
3391
|
-
{
|
|
3392
|
-
type: "button",
|
|
3393
|
-
style: unlockModalStyles.usePinButton,
|
|
3394
|
-
onClick: handleUsePinInstead,
|
|
3395
|
-
children: "Use PIN instead"
|
|
3396
|
-
}
|
|
3397
|
-
)
|
|
3398
|
-
] })
|
|
3399
|
-
] });
|
|
3400
|
-
const renderPinInput = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3401
|
-
PinInput,
|
|
3402
|
-
{
|
|
3403
|
-
title: "Enter PIN",
|
|
3404
|
-
subtitle: "Enter your PIN to unlock signless payments",
|
|
3405
|
-
onComplete: handlePinSubmit,
|
|
3406
|
-
onCancel: onClose,
|
|
3407
|
-
error,
|
|
3408
|
-
isLoading,
|
|
3409
|
-
showBiometric: shouldShowBiometric,
|
|
3410
|
-
onBiometricPress: () => {
|
|
3411
|
-
setView("biometric");
|
|
3412
|
-
setError(null);
|
|
3413
|
-
}
|
|
3414
|
-
}
|
|
3415
|
-
);
|
|
3416
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: unlockModalStyles.container, children: view === "biometric" && shouldShowBiometric ? renderBiometricPrompt() : renderPinInput() });
|
|
3417
|
-
};
|
|
3418
|
-
var BiometricLargeIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3419
|
-
"svg",
|
|
3420
|
-
{
|
|
3421
|
-
width: "48",
|
|
3422
|
-
height: "48",
|
|
3423
|
-
viewBox: "0 0 24 24",
|
|
3424
|
-
fill: "none",
|
|
3425
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
3426
|
-
children: [
|
|
3427
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3428
|
-
"path",
|
|
3429
|
-
{
|
|
3430
|
-
d: "M12 14.5V16.5M7 10.5C7 7.73858 9.23858 5.5 12 5.5C14.7614 5.5 17 7.73858 17 10.5V11.5M12 11.5C10.6193 11.5 9.5 12.6193 9.5 14C9.5 15.3807 10.6193 16.5 12 16.5C13.3807 16.5 14.5 15.3807 14.5 14C14.5 12.6193 13.3807 11.5 12 11.5Z",
|
|
3431
|
-
stroke: "currentColor",
|
|
3432
|
-
strokeWidth: "1.5",
|
|
3433
|
-
strokeLinecap: "round",
|
|
3434
|
-
strokeLinejoin: "round"
|
|
3435
|
-
}
|
|
3436
|
-
),
|
|
3437
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3438
|
-
"path",
|
|
3439
|
-
{
|
|
3440
|
-
d: "M3 7V5C3 3.89543 3.89543 3 5 3H7M17 3H19C20.1046 3 21 3.89543 21 5V7M21 17V19C21 20.1046 20.1046 21 19 21H17M7 21H5C3.89543 21 3 20.1046 3 19V17",
|
|
3441
|
-
stroke: "currentColor",
|
|
3442
|
-
strokeWidth: "1.5",
|
|
3443
|
-
strokeLinecap: "round",
|
|
3444
|
-
strokeLinejoin: "round"
|
|
3445
|
-
}
|
|
3446
|
-
)
|
|
3447
|
-
]
|
|
3448
|
-
}
|
|
3449
|
-
);
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
1837
|
|
|
3469
1838
|
|
|
3470
1839
|
|
|
@@ -3473,5 +1842,5 @@ var BiometricLargeIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
|
3473
1842
|
|
|
3474
1843
|
|
|
3475
1844
|
|
|
3476
|
-
exports.BottomSheet = BottomSheet_default; exports.ErrorTransactionNotification = ErrorTransactionNotification; exports.NotificationCard = NotificationCard; exports.NotificationRoot = NotificationRoot; exports.PaymentModal = PaymentModal; exports.
|
|
1845
|
+
exports.BottomSheet = BottomSheet_default; exports.ErrorTransactionNotification = ErrorTransactionNotification; exports.NotificationCard = NotificationCard; exports.NotificationRoot = NotificationRoot; exports.PaymentModal = PaymentModal; exports.TonPayButton = TonPayButton; exports.useMoonPayIframe = useMoonPayIframe; exports.useTonPay = useTonPay;
|
|
3477
1846
|
//# sourceMappingURL=index.js.map
|