@ton-pay/ui-react 0.1.2 → 0.2.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/ilya/work/tonpay/ton-pay/packages/ui-react/dist/index.js","../src/components/ton-pay-btn.tsx","../src/components/notification/Notification.tsx","../src/components/notification/ErrorTransactionNotification.tsx","../src/hooks/useTonPay.ts"],"names":["jsx","jsxs","React","useEffect"],"mappings":"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","file":"/Users/ilya/work/tonpay/ton-pay/packages/ui-react/dist/index.js","sourcesContent":[null,"import { useTonAddress, useTonConnectModal, useTonConnectUI, useTonWallet } from \"@tonconnect/ui-react\";\nimport { CHAIN, toUserFriendlyAddress } from \"@tonconnect/ui\";\nimport { useEffect, useState } from \"react\";\nimport { NotificationRoot } from \"./notification/Notification\";\nimport { ErrorTransactionNotification } from \"./notification/ErrorTransactionNotification\";\n\ntype TonPayPreset = \"default\" | \"gradient\";\n\ntype TonPayButtonProps = {\n handlePay: () => Promise<void>,\n isLoading?: boolean,\n variant?: \"long\" | \"short\",\n preset?: TonPayPreset,\n onError?: (error: unknown) => void,\n showErrorNotification?: boolean,\n bgColor?: string,\n textColor?: string,\n borderRadius?: number | string,\n fontFamily?: string,\n width?: number | string,\n height?: number | string,\n text?: string,\n loadingText?: string,\n style?: Record<string, any>,\n className?: string,\n showMenu?: boolean,\n disabled?: boolean,\n}\n\nconst PRESETS: Record<TonPayPreset, { bgColor: string, textColor: string }> = {\n default: {\n bgColor: \"#0098EA\",\n textColor: \"#FFFFFF\",\n },\n gradient: {\n bgColor: \"linear-gradient(91.69deg, #2A82EB 8.9%, #0355CF 158.29%)\",\n textColor: \"#FFFFFF\",\n },\n};\n\nconst stylesAndAnimations = `\n @keyframes tp-pulse { 0%{opacity:1;transform:scale(1)} 50%{opacity:.5;transform:scale(1.02)} 100%{opacity:1;transform:scale(1)} }\n @keyframes tp-fade-in { from{opacity:0;transform:translateY(-4px) scale(.98)} to{opacity:1;transform:translateY(0) scale(1)} }\n @keyframes tp-spin { to{transform:rotate(360deg)} }\n .tp-wrap{display:inline-flex;flex-direction:column;position:relative;width:var(--tp-width,300px);max-width:100%}\n .tp-btn-container{display:flex;flex-direction:row;width:100%}\n .tp-btn{display:flex;flex-direction:column;justify-content:center;align-items:center;padding:13px 10px;gap:10px;flex:1;min-height:var(--tp-height,44px);background:var(--tp-bg,#0098EA);color:var(--tp-text,#fff);border:none;border-radius:var(--tp-radius,8px) 0 0 var(--tp-radius,8px);cursor:pointer;transition:filter .12s ease, transform .12s ease;font-family:var(--tp-font,inherit);font-style:normal;font-weight:500;font-size:20px;line-height:25px;text-align:center;position:relative}\n .tp-btn.with-menu{padding-left:calc(10px + (var(--tp-height,44px))/2)}\n .tp-btn.no-menu{border-radius:var(--tp-radius,8px)}\n .tp-btn-content{display:flex;flex-direction:row;align-items:center;padding:0;gap:5px;white-space:nowrap;margin-top:-4px}\n .tp-btn-content svg{margin-top:4px}\n .tp-btn:hover:not(:disabled){filter:brightness(0.92)}\n .tp-btn:active:not(:disabled){filter:brightness(0.85);transform:translateY(1px)}\n .tp-btn:disabled{cursor:not-allowed;opacity:.85}\n .tp-btn.loading{animation:none}\n .tp-arrow{display:flex;align-items:center;justify-content:center;padding:13px 10px;min-width:calc(var(--tp-height,44px));min-height:var(--tp-height,44px);background:var(--tp-bg,#0098EA);color:var(--tp-text,#fff);border:none;border-left:1px solid rgba(255,255,255,.2);border-radius:0 var(--tp-radius,8px) var(--tp-radius,8px) 0;cursor:pointer;transition:filter .12s ease, transform .12s ease;font-size:14px}\n .tp-arrow:hover:not(:disabled){filter:brightness(0.92)}\n .tp-arrow:active:not(:disabled){filter:brightness(0.85);transform:translateY(1px)}\n .tp-arrow:disabled{cursor:not-allowed;opacity:.85;transition:none;filter:none;transform:none}\n .tp-menu{position:absolute;right:0;top:calc(100% + 8px);width:256px;background:var(--tp-menu-bg,#ffffff);color:var(--tp-menu-text,#111827);border:1px solid rgba(0,0,0,.08);border-radius:var(--tp-menu-radius,16px);padding:8px;box-shadow:0 8px 24px rgba(0,0,0,.12);z-index:1000;animation:tp-fade-in .15s ease}\n .tp-menu-arrow{position:absolute;top:-8px;right:20px;width:0;height:0;border-style:solid;border-width:0 8px 8px 8px;border-color:transparent transparent var(--tp-menu-bg,#ffffff) transparent;filter:drop-shadow(0 -1px 1px rgba(0,0,0,.08))}\n .tp-menu-address{padding:.5rem .75rem;font-size:.85rem;color:var(--tp-menu-muted,#6b7280);cursor:default;user-select:text}\n .tp-menu-item{display:flex;align-items:center;gap:8px;width:100%;height:40px;padding-left:12px;padding-right:12px;border:none;background:transparent;text-align:left;cursor:pointer;font-size:15px;font-weight:590;color:var(--tp-menu-text,#111827);transition:background-color .15s ease, transform .1s ease-in-out;border-radius:8px;margin:2px}\n .tp-menu-item:hover:not(:disabled){background:var(--tp-menu-hover,rgba(0,0,0,.06))}\n .tp-menu-item:active{transform:scale(0.96)}\n .tp-menu-item.danger{color:#e74c3c}\n .tp-menu-item.danger:hover:not(:disabled){background:rgba(231,76,60,.12);color:#c0392b}\n .tp-menu-item:disabled{cursor:default;opacity:1;color:var(--tp-menu-muted,#6b7280)}\n .tp-menu-item:disabled:hover{background:transparent}\n .tp-menu-icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;color:currentColor}\n .tp-menu-item:disabled .tp-menu-icon{opacity:.5}\n .tp-spinner{border:2px solid rgba(255,255,255,.35);border-top-color:var(--tp-text,#fff);border-radius:50%;width:18px;height:18px;animation:tp-spin .6s linear infinite}\n`;\n\nif (typeof document !== 'undefined') {\n const style = document.createElement('style');\n style.textContent = stylesAndAnimations;\n document.head.appendChild(style);\n}\n\nconst TonGlyph = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden>\n <g clipPath=\"url(#clip0_144_4719)\">\n <path 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\" fill=\"#0098EA\"/>\n <path 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\" fill=\"white\"/>\n <path 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\" fill=\"#0098EA\"/>\n </g>\n <defs>\n <clipPath id=\"clip0_144_4719\">\n <rect width=\"24\" height=\"24\" fill=\"white\"/>\n </clipPath>\n </defs>\n </svg>\n);\n\nconst CopyGlyph = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden>\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M7.76228 2.09998H10.2378C11.0458 2.09997 11.7067 2.09996 12.2438 2.14384C12.7997 2.18926 13.3017 2.28614 13.7706 2.52505C14.5045 2.89896 15.1011 3.49558 15.475 4.22941C15.7139 4.6983 15.8108 5.20038 15.8562 5.75629C15.9001 6.29337 15.9001 6.95422 15.9001 7.76227V8.1H16.2377C17.0457 8.09999 17.7066 8.09998 18.2437 8.14386C18.7996 8.18928 19.3017 8.28616 19.7705 8.52507C20.5044 8.89898 21.101 9.4956 21.4749 10.2294C21.7138 10.6983 21.8107 11.2004 21.8561 11.7563C21.9 12.2934 21.9 12.9542 21.9 13.7623V16.2377C21.9 17.0458 21.9 17.7066 21.8561 18.2437C21.8107 18.7996 21.7138 19.3017 21.4749 19.7706C21.101 20.5044 20.5044 21.101 19.7705 21.4749C19.3017 21.7138 18.7996 21.8107 18.2437 21.8561C17.7066 21.9 17.0458 21.9 16.2378 21.9H13.7623C12.9543 21.9 12.2934 21.9 11.7563 21.8561C11.2004 21.8107 10.6983 21.7138 10.2294 21.4749C9.49561 21.101 8.89898 20.5044 8.52508 19.7706C8.28616 19.3017 8.18928 18.7996 8.14386 18.2437C8.09998 17.7066 8.09999 17.0458 8.1 16.2377V15.9H7.76227C6.95426 15.9 6.29335 15.9 5.75629 15.8561C5.20038 15.8107 4.6983 15.7138 4.22941 15.4749C3.49558 15.101 2.89896 14.5044 2.52505 13.7705C2.28614 13.3017 2.18926 12.7996 2.14384 12.2437C2.09996 11.7066 2.09997 11.0458 2.09998 10.2377V7.76228C2.09997 6.95424 2.09996 6.29336 2.14384 5.75629C2.18926 5.20038 2.28614 4.6983 2.52505 4.22941C2.89896 3.49558 3.49558 2.89896 4.22941 2.52505C4.6983 2.28614 5.20038 2.18926 5.75629 2.14384C6.29336 2.09996 6.95425 2.09997 7.76228 2.09998ZM8.1 14.1V13.7623C8.09999 12.9542 8.09998 12.2934 8.14386 11.7563C8.18928 11.2004 8.28616 10.6983 8.52508 10.2294C8.89898 9.4956 9.49561 8.89898 10.2294 8.52507C10.6983 8.28616 11.2004 8.18928 11.7563 8.14386C12.2934 8.09998 12.9542 8.09999 13.7623 8.1H14.1001V7.79998C14.1001 6.94505 14.0994 6.35798 14.0622 5.90287C14.0259 5.45827 13.9593 5.21944 13.8712 5.0466C13.6699 4.65146 13.3486 4.3302 12.9535 4.12886C12.7806 4.04079 12.5418 3.97419 12.0972 3.93786C11.6421 3.90068 11.055 3.89998 10.2001 3.89998H7.79998C6.94505 3.89998 6.35798 3.90068 5.90287 3.93786C5.45827 3.97419 5.21944 4.04079 5.0466 4.12886C4.65146 4.3302 4.3302 4.65146 4.12886 5.0466C4.04079 5.21944 3.97419 5.45827 3.93786 5.90287C3.90068 6.35798 3.89998 6.94505 3.89998 7.79998V10.2C3.89998 11.0549 3.90068 11.642 3.93786 12.0971C3.97419 12.5417 4.04079 12.7805 4.12886 12.9534C4.3302 13.3485 4.65146 13.6698 5.0466 13.8711C5.21944 13.9592 5.45827 14.0258 5.90287 14.0621C6.35798 14.0993 6.94505 14.1 7.79998 14.1H8.1ZM11.0466 10.1289C11.2195 10.0408 11.4583 9.97421 11.9029 9.93788C12.358 9.9007 12.9451 9.9 13.8 9.9H16.2C17.0549 9.9 17.642 9.9007 18.0971 9.93788C18.5417 9.97421 18.7805 10.0408 18.9534 10.1289C19.3485 10.3302 19.6698 10.6515 19.8711 11.0466C19.9592 11.2195 20.0258 11.4583 20.0621 11.9029C20.0993 12.358 20.1 12.9451 20.1 13.8V16.2C20.1 17.0549 20.0993 17.642 20.0621 18.0971C20.0258 18.5417 19.9592 18.7805 19.8711 18.9534C19.6698 19.3485 19.3485 19.6698 18.9534 19.8711C18.7805 19.9592 18.5417 20.0258 18.0971 20.0621C17.642 20.0993 17.0549 20.1 16.2 20.1H13.8C12.9451 20.1 12.358 20.0993 11.9029 20.0621C11.4583 20.0258 11.2195 19.9592 11.0466 19.8711C10.6515 19.6698 10.3302 19.3485 10.1289 18.9534C10.0408 18.7805 9.97421 18.5417 9.93788 18.0971C9.9007 17.642 9.9 17.0549 9.9 16.2V13.8C9.9 12.9451 9.9007 12.358 9.93788 11.9029C9.97421 11.4583 10.0408 11.2195 10.1289 11.0466C10.3302 10.6515 10.6515 10.3302 11.0466 10.1289Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nconst DisconnectGlyph = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden>\n <path\n d=\"M8.7624 3.10001C7.95435 3.1 7.29349 3.09999 6.75642 3.14387C6.2005 3.18929 5.69842 3.28617 5.22954 3.52508C4.4957 3.89899 3.89908 4.49561 3.52517 5.22944C3.28626 5.69833 3.18938 6.20041 3.14396 6.75632C3.10008 7.2934 3.10009 7.95424 3.1001 8.76229V15.2377C3.10009 16.0458 3.10008 16.7066 3.14396 17.2437C3.18938 17.7996 3.28626 18.3017 3.52517 18.7706C3.89908 19.5044 4.4957 20.101 5.22954 20.4749C5.69842 20.7138 6.2005 20.8107 6.75642 20.8561C7.29349 20.9 7.95434 20.9 8.76239 20.9H12.0001C12.4972 20.9 12.9001 20.4971 12.9001 20C12.9001 19.503 12.4972 19.1 12.0001 19.1H8.8001C7.94517 19.1 7.3581 19.0993 6.90299 19.0621C6.45839 19.0258 6.21956 18.9592 6.04672 18.8711C5.65158 18.6698 5.33032 18.3485 5.12898 17.9534C5.04092 17.7805 4.97431 17.5417 4.93798 17.0971C4.9008 16.642 4.9001 16.0549 4.9001 15.2V8.80001C4.9001 7.94508 4.9008 7.35801 4.93798 6.9029C4.97431 6.4583 5.04092 6.21947 5.12898 6.04663C5.33032 5.65149 5.65158 5.33023 6.04672 5.12889C6.21956 5.04082 6.45839 4.97422 6.90299 4.93789C7.3581 4.90071 7.94517 4.90001 8.8001 4.90001H12.0001C12.4972 4.90001 12.9001 4.49706 12.9001 4.00001C12.9001 3.50295 12.4972 3.10001 12.0001 3.10001H8.7624Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M17.6364 7.3636C17.2849 7.01212 16.7151 7.01212 16.3636 7.3636C16.0121 7.71507 16.0121 8.28492 16.3636 8.63639L18.8272 11.1H9.00001C8.50295 11.1 8.10001 11.5029 8.10001 12C8.10001 12.497 8.50295 12.9 9.00001 12.9H18.8272L16.3636 15.3636C16.0121 15.7151 16.0121 16.2849 16.3636 16.6364C16.7151 16.9879 17.2849 16.9879 17.6364 16.6364L21.6364 12.6364C21.9879 12.2849 21.9879 11.7151 21.6364 11.3636L17.6364 7.3636Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nfunction shortenAddress(addr: string | null | undefined, head: number = 4, tail: number = 4) {\n if (!addr || typeof addr !== \"string\") return \"\";\n if (addr.length <= head + tail + 3) return addr;\n return `${addr.slice(0, head)}...${addr.slice(-tail)}`;\n}\n\nfunction toCssSize(v?: number | string) {\n if (v === undefined) return undefined;\n return typeof v === \"number\" ? `${v}px` : v;\n}\n\nfunction isGradient(value: string) {\n return value.includes(\"gradient(\");\n}\n\nfunction getMenuBg(bg: string) {\n if (isGradient(bg)) {\n return \"#0098EA\";\n }\n return bg;\n}\n\nexport const TonPayButton = ({\n handlePay,\n isLoading = false,\n variant = \"long\",\n preset,\n bgColor,\n textColor,\n borderRadius = 8,\n fontFamily = \"inherit\",\n width = 300,\n height = 44,\n text,\n loadingText = \"Processing...\",\n style,\n className,\n showMenu = true,\n disabled = false,\n onError,\n showErrorNotification = true,\n}: TonPayButtonProps) => {\n const address = useTonAddress(true);\n const modal = useTonConnectModal();\n const [tonConnectUI] = useTonConnectUI();\n const wallet = useTonWallet();\n const disconnect = tonConnectUI.disconnect.bind(tonConnectUI);\n\n const [showContextMenu, setShowContextMenu] = useState(false);\n const [isCopiedShown, setIsCopiedShown] = useState(false);\n const [errorMessage, setErrorMessage] = useState(null as string | null);\n\n useEffect(() => {\n const handleClickOutside = () => {\n if (showContextMenu) setShowContextMenu(false);\n };\n if (showContextMenu) {\n document.addEventListener('click', handleClickOutside);\n return () => document.removeEventListener('click', handleClickOutside);\n }\n }, [showContextMenu]);\n\n useEffect(() => {\n if (!showContextMenu && isCopiedShown) {\n setIsCopiedShown(false);\n }\n }, [showContextMenu, isCopiedShown]);\n\n useEffect(() => {\n if (!errorMessage) return;\n const timerId = setTimeout(() => setErrorMessage(null), 3000);\n return () => clearTimeout(timerId);\n }, [errorMessage]);\n\n const handleDropdownToggle = (e: any) => {\n e.preventDefault();\n e.stopPropagation();\n if (isLoading || disabled || !address) return;\n setShowContextMenu(!showContextMenu);\n };\n\n const handleDisconnect = () => {\n disconnect();\n setShowContextMenu(false);\n setIsCopiedShown(false);\n };\n\n const handleCopyAddress = async () => {\n const rawAddress = wallet?.account?.address;\n const chain = wallet?.account?.chain;\n const toCopy = rawAddress\n ? toUserFriendlyAddress(rawAddress, chain === CHAIN.TESTNET)\n : address;\n if (toCopy) {\n try {\n await navigator.clipboard.writeText(toCopy);\n setIsCopiedShown(true);\n setTimeout(() => setIsCopiedShown(false), 1000);\n } catch {}\n }\n };\n\n const handleConnect = () => {\n modal.open();\n setShowContextMenu(false);\n };\n\n const onPayClick = async () => {\n try {\n await handlePay();\n } catch (err) {\n try {\n onError?.(err);\n } catch {}\n if (showErrorNotification) {\n const raw = typeof err === \"object\" && err && \"message\" in (err as any)\n ? String((err as any).message)\n : String(err ?? \"\");\n const msg = raw || \"Wallet connection modal closed\";\n setErrorMessage(msg);\n }\n }\n };\n\n const presetConfig = preset ? PRESETS[preset] : null;\n const finalBgColor = bgColor ?? presetConfig?.bgColor ?? PRESETS.default.bgColor;\n const finalTextColor = textColor ?? presetConfig?.textColor ?? PRESETS.default.textColor;\n \n const vars: Record<string, string | number | undefined> = {\n \"--tp-bg\": finalBgColor,\n \"--tp-text\": finalTextColor,\n \"--tp-radius\": typeof borderRadius === \"number\" ? `${borderRadius}px` : borderRadius,\n \"--tp-font\": fontFamily,\n \"--tp-width\": toCssSize(width),\n \"--tp-height\": toCssSize(height),\n \"--tp-menu-bg\": \"#ffffff\",\n \"--tp-menu-text\": \"#111827\",\n \"--tp-menu-muted\": \"#6b7280\",\n \"--tp-menu-hover\": \"rgba(0,0,0,.06)\",\n };\n\n const isDisabled = isLoading || disabled;\n const hasMenu = showMenu && !!address;\n\n const content = text ? (\n <span>{text}</span>\n ) : variant === \"short\" ? (\n <div className=\"tp-btn-content\">\n <TonGlyph />\n <span>Pay</span>\n </div>\n ) : (\n <div className=\"tp-btn-content\">\n <span>Pay with</span>\n <TonGlyph />\n <span>Pay</span>\n </div>\n );\n\n return (\n <div style={{ ...vars, ...style }} className={[\"tp-wrap\", className].filter(Boolean).join(\" \")}> \n <div className=\"tp-btn-container\">\n <button\n type=\"button\"\n className={[\"tp-btn\", isLoading ? \"loading\" : \"\", !hasMenu ? \"no-menu\" : \"with-menu\"].filter(Boolean).join(\" \")}\n onClick={isDisabled ? undefined : onPayClick}\n disabled={isDisabled}\n >\n {isLoading ? (\n <div className=\"tp-btn-content\">\n <span className=\"tp-spinner\" />\n <span>{loadingText}</span>\n </div>\n ) : (\n content\n )}\n </button>\n {hasMenu && (\n <button\n type=\"button\"\n className=\"tp-arrow\"\n onClick={handleDropdownToggle}\n disabled={isDisabled}\n >\n ▼\n </button>\n )}\n </div>\n {hasMenu && showContextMenu && (\n <div className=\"tp-menu\" onClick={(e: any) => e.stopPropagation()}>\n <div className=\"tp-menu-arrow\" />\n {address && (\n <>\n <div className=\"tp-menu-address\">{shortenAddress(address)}</div>\n <button onClick={handleCopyAddress} className=\"tp-menu-item\" disabled={isCopiedShown}>\n <span className=\"tp-menu-icon\"><CopyGlyph /></span>\n <span>{isCopiedShown ? \"Address copied!\" : \"Copy address\"}</span>\n </button>\n <button onClick={handleDisconnect} className=\"tp-menu-item danger\">\n <span className=\"tp-menu-icon\"><DisconnectGlyph /></span>\n <span>Disconnect</span>\n </button>\n </>\n )}\n </div>\n )}\n {errorMessage && (\n <NotificationRoot>\n <ErrorTransactionNotification text={errorMessage} />\n </NotificationRoot>\n )}\n </div>\n );\n}","import React from 'react'\nconst notificationStyles = `\n .tp-noti-root{position:fixed;top:16px;right:16px;z-index:10000;display:flex;flex-direction:column;gap:10px}\n .tp-noti-card{width:256px;padding:12px 16px;display:flex;gap:9px;align-items:flex-start;background:#ffffff;color:#111827;border-radius:16px;box-shadow:0 4px 24px rgba(0,0,0,.16);animation:tp-fade-in .2s ease}\n .tp-noti-content{flex:1;min-width:0}\n .tp-noti-title{font-size:15px;font-weight:700;line-height:20px;margin:0}\n .tp-noti-text{margin-top:4px;color:#6b7280;font-size:13px;line-height:18px;word-break:break-word}\n .tp-noti-icon{width:24px;height:24px;margin-top:2px;flex:0 0 auto}\n`;\n\nif (typeof document !== \"undefined\") {\n const id = \"tp-notification-styles\";\n if (!document.getElementById(id)) {\n const style = document.createElement(\"style\");\n style.id = id;\n style.textContent = notificationStyles;\n document.head.appendChild(style);\n }\n}\n\nexport type NotificationProps = {\n title: string;\n text?: string;\n icon?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n};\n\nexport const NotificationCard: React.FC<NotificationProps> = ({ \n title, \n text, \n icon, \n className, \n style \n}: NotificationProps) => {\n return (\n <div className={[\"tp-noti-card\", className].filter(Boolean).join(\" \")} style={style}>\n <div className=\"tp-noti-content\">\n <h3 className=\"tp-noti-title\">{title}</h3>\n {text ? <div className=\"tp-noti-text\">{text}</div> : null}\n </div>\n {icon ? <div className=\"tp-noti-icon\">{icon}</div> : null}\n </div>\n );\n};\n\nexport const NotificationRoot: React.FC<{ children?: React.ReactNode }> = ({ children }: { children?: React.ReactNode }) => {\n return <div className=\"tp-noti-root\">{children}</div>;\n};\n\nexport const ErrorDotIcon: React.FC<{ color?: string }> = ({ color = \"#FF5252\" }) => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"11\" fill={color} />\n <path d=\"M7.864 9.136A1.5 1.5 0 0 1 9.136 7.864L12 10.727 14.864 7.864A1.5 1.5 0 0 1 16.136 9.136L13.273 12 16.136 14.864a1.5 1.5 0 0 1-2.272 2.272L12 13.273 9.136 17.136A1.5 1.5 0 1 1 7.864 14.864L10.727 12 7.864 9.136Z\" fill=\"#fff\" />\n </svg>\n);\n\n\n","import React from \"react\";\nimport { ErrorDotIcon, NotificationCard } from \"./Notification\";\n\nexport const ErrorTransactionNotification: React.FC<{ text?: string; className?: string; style?: React.CSSProperties }>\n = ({ text, className, style }) => {\n return (\n <NotificationCard\n title=\"Transaction cancelled\"\n text={text}\n icon={<ErrorDotIcon />}\n className={className}\n style={style}\n />\n );\n };\n\n\n","import React, { useEffect } from 'react';\nimport {\n useTonAddress,\n useTonConnectModal,\n useTonConnectUI\n} from \"@tonconnect/ui-react\";\n\nimport {type SendTransactionRequest, type SendTransactionResponse} from \"@tonconnect/sdk\";\n\nexport type TonPayMessage = SendTransactionRequest[\"messages\"][number] & {\n payload: string;\n};\n\nexport type GetMessageFn<T extends object = object> = (\n senderAddr: string\n) => Promise<{ message: TonPayMessage } & T>;\n\nexport type PayInfo<T extends object = object> = {\n message: TonPayMessage;\n txResult: SendTransactionResponse;\n} & T;\n\nexport const useTonPay = () => {\n const address = useTonAddress(true);\n const modal = useTonConnectModal();\n const [tonConnectUI] = useTonConnectUI();\n\n useEffect(() => {\n if (address) {\n console.log(address);\n }\n }, [address]);\n\n const waitForWalletConnection = React.useCallback((): Promise<string> => {\n return new Promise((resolve, reject) => {\n if (address) {\n resolve(address);\n return;\n }\n\n modal.open();\n\n const unsubscribe = tonConnectUI.onStatusChange((wallet: any) => {\n if (wallet && wallet.account) {\n unsubscribe();\n unsubscribeModal();\n resolve(wallet.account.address);\n }\n });\n\n const unsubscribeModal = tonConnectUI.onModalStateChange((state: any) => {\n if (state.status === \"closed\") {\n unsubscribe();\n unsubscribeModal();\n reject(new Error(\"Wallet connection modal closed\"));\n }\n });\n\n setTimeout(() => {\n unsubscribe();\n unsubscribeModal();\n reject(new Error(\"Wallet connection timeout\"));\n }, 5 * 60 * 1000);\n });\n }, [address, modal, tonConnectUI]);\n\n const pay = React.useCallback(\n async <T extends object = object>(\n getMessage: GetMessageFn<T>\n ): Promise<PayInfo<T>> => {\n try {\n const walletAddress = await waitForWalletConnection();\n\n const validUntil = Math.floor(Date.now() / 1e3) + 5 * 60; // 5 minutes\n const messageResult = await getMessage(walletAddress);\n\n const txResult = await tonConnectUI.sendTransaction({\n messages: [messageResult.message],\n validUntil,\n from: walletAddress,\n });\n\n return { ...messageResult, txResult };\n } catch (error) {\n console.error(\"Payment failed:\", error);\n throw error;\n }\n },\n [waitForWalletConnection, tonConnectUI]\n );\n\n return { pay, address };\n};\n"]}
1
+ {"version":3,"sources":["/Users/ilya/work/tonpay/ton-pay/packages/ui-react/dist/index.js","../src/components/ton-pay-button/TonPayButton.tsx","../src/utils/index.ts","../src/components/icons/index.tsx","../src/components/notification/Notification.tsx","../src/components/notification/ErrorTransactionNotification.tsx","../src/components/payment-modal/PaymentModal.tsx","../src/components/bottom-sheet/BottomSheet.tsx","../src/components/bottom-sheet/BottomSheet.css","../src/components/payment-modal/PaymentModal.css","../src/hooks/useMoonPayIframe.ts","../../api/src/common/const.ts","../../api/src/common/get-base-url.ts","../../api/src/create-moonpay-transfer/create-moonpay-transfer.ts","../../api/src/check-moonpay-geo/check-moonpay-geo.ts","../../api/src/check-moonpay-limits/check-moonpay-limits.ts","../../api/src/utils/verify-signature.ts","../src/components/ton-pay-button/styles.ts","../src/hooks/useTonPay.ts","../src/signless/context.tsx","../src/signless/crypto/ed25519.ts","../src/signless/crypto/encryption.ts","../src/signless/crypto/webauthn.ts","../src/signless/storage.ts","../src/signless/hooks/useTonPaySignless.ts","../src/signless/hooks/useSignlessModal.ts","../src/signless/components/PinInput.tsx","../src/signless/components/styles.ts","../src/signless/components/SignlessSetupModal.tsx","../src/signless/components/SignlessUnlockModal.tsx"],"names":["jsxs","jsx","useState","useCallback","useTonAddress","useTonConnectUI","arrayBufferToBase64"],"mappings":"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AA;AACI,IAAA;AAClB,EAAA;AACiB,EAAA;AACR,IAAA;AACC,IAAA;AACE,IAAA;AACH,IAAA;AACU,IAAA;AACT,IAAA;AACM,IAAA;AACN,IAAA;AACI,IAAA;AACH,IAAA;AACG,IAAA;AACI,IAAA;AAClB,EAAA;AACc,EAAA;AACD,IAAA;AACF,IAAA;AACC,IAAA;AACE,IAAA;AACL,IAAA;AACU,IAAA;AACT,IAAA;AACM,IAAA;AACN,IAAA;AACI,IAAA;AACd,EAAA;AACF;AAE+D;AAClD,EAAA;AACA,IAAA;AACM,IAAA;AACH,IAAA;AACH,IAAA;AAEP,IAAA;AACK,IAAA;AACT,EAAA;AACQ,EAAA;AACK,IAAA;AACG,IAAA;AAChB,EAAA;AACO,EAAA;AACK,IAAA;AACE,IAAA;AACJ,IAAA;AACD,IAAA;AACT,EAAA;AACU,EAAA;AACE,IAAA;AACH,IAAA;AACC,IAAA;AACI,IAAA;AACF,IAAA;AACZ,EAAA;AACgB,EAAA;AACL,IAAA;AACM,IAAA;AACV,IAAA;AACE,IAAA;AACO,IAAA;AAChB,EAAA;AACc,EAAA;AACH,IAAA;AACG,IAAA;AACP,IAAA;AACI,IAAA;AACQ,IAAA;AACT,IAAA;AACM,IAAA;AACN,IAAA;AACI,IAAA;AACD,IAAA;AACJ,IAAA;AACT,EAAA;AACsB,EAAA;AACH,IAAA;AACJ,IAAA;AACf,EAAA;AACY,EAAA;AACH,IAAA;AACC,IAAA;AACM,IAAA;AACG,IAAA;AACR,IAAA;AACG,IAAA;AACI,IAAA;AACT,IAAA;AACK,IAAA;AACd,EAAA;AACe,EAAA;AACP,IAAA;AACI,IAAA;AACZ,EAAA;AACa,EAAA;AACD,IAAA;AACE,IAAA;AACL,IAAA;AACC,IAAA;AACV,EAAA;AACmB,EAAA;AACP,IAAA;AACH,IAAA;AACC,IAAA;AACI,IAAA;AACd,EAAA;AACgB,EAAA;AACP,IAAA;AACE,IAAA;AACC,IAAA;AACE,IAAA;AACL,IAAA;AACU,IAAA;AACT,IAAA;AACM,IAAA;AACN,IAAA;AACI,IAAA;AACd,EAAA;AACwB,EAAA;AACb,IAAA;AACD,IAAA;AACV,EAAA;AACe,EAAA;AACJ,IAAA;AACJ,IAAA;AACS,IAAA;AAChB,EAAA;AACS,EAAA;AACA,IAAA;AACC,IAAA;AACM,IAAA;AACG,IAAA;AACnB,EAAA;AACe,EAAA;AACI,IAAA;AACnB,EAAA;AACF;AAEgE;AACnD,EAAA;AACA,IAAA;AACM,IAAA;AACH,IAAA;AACH,IAAA;AAEP,IAAA;AACK,IAAA;AACT,EAAA;AACiB,EAAA;AACN,IAAA;AACM,IAAA;AACH,IAAA;AACH,IAAA;AACE,IAAA;AACb,EAAA;AACe,EAAA;AACN,IAAA;AACC,IAAA;AACM,IAAA;AACG,IAAA;AACR,IAAA;AACG,IAAA;AACI,IAAA;AACT,IAAA;AACO,IAAA;AAChB,EAAA;AACgB,EAAA;AACJ,IAAA;AACE,IAAA;AACJ,IAAA;AACD,IAAA;AACT,EAAA;AACmB,EAAA;AACP,IAAA;AACH,IAAA;AACC,IAAA;AACV,EAAA;AACc,EAAA;AACH,IAAA;AACC,IAAA;AACE,IAAA;AACL,IAAA;AACU,IAAA;AACT,IAAA;AACA,IAAA;AACI,IAAA;AACd,EAAA;AACF;A3BoxEsC;AACA;A0Bl/EhCN;AArEa;AAE+B;AACvC,EAAA;AACT,EAAA;AACA,EAAA;AACQ,EAAA;AACR,EAAA;AACA,EAAA;AACY,EAAA;AACI,EAAA;AAChB,EAAA;AACI;AACwB,EAAA;AACI,EAAA;AACoB,EAAA;AAE9B,EAAA;AACT,IAAA;AACI,MAAA;AACJ,MAAA;AACsB,MAAA;AACA,MAAA;AACjC,IAAA;AACQ,EAAA;AAEY,EAAA;AACI,oBAAA;AACrB,EAAA;AAE4D,EAAA;AAClC,IAAA;AACjB,IAAA;AAEiB,IAAA;AACX,MAAA;AAClB,IAAA;AACF,EAAA;AAEkD,EAAA;AACtB,IAAA;AACf,MAAA;AACX,IAAA;AACF,EAAA;AAE6B,EAAA;AACH,oBAAA;AAC1B,EAAA;AAE0C,EAAA;AACZ,IAAA;AAEP,IAAA;AACR,IAAA;AAEiB,IAAA;AACX,MAAA;AACnB,IAAA;AACF,EAAA;AAE8B,EAAA;AACb,IAAA;AACmB,IAAA;AACpC,EAAA;AAGG,EAAA;AACS,oBAAA;AAEH,oBAAA;AACC,sBAAA;AACSC,MAAAA;AACf,IAAA;AAEAA,oBAAAA;AAAC,MAAA;AAAA,MAAA;AACM,QAAA;AACA,QAAA;AACK,QAAA;AACF,QAAA;AACD,QAAA;AACG,QAAA;AACC,QAAA;AACA,QAAA;AACE,QAAA;AACS,QAAA;AACZ,QAAA;AAAA,MAAA;AACZ,IAAA;AAEAA,oBAAAA;AAAC,MAAA;AAAA,MAAA;AACQ,QAAA;AACa,UAAA;AACS,UAAA;AAC7B,QAAA;AACS,QAAA;AAEY,QAAA;AAClB,UAAA;AAAA,UAAA;AAEQ,YAAA;AACa,cAAA;AACG,cAAA;AACL,cAAA;AAClB,YAAA;AAAA,UAAA;AALK,UAAA;AAOR,QAAA;AAAA,MAAA;AACH,IAAA;AAEW,IAAA;AAEN,oBAAA;AAC8B,MAAA;AAC9B,QAAA;AAAA,QAAA;AAEM,UAAA;AACiB,UAAA;AACP,UAAA;AACL,UAAA;AACW,UAAA;AACmB,YAAA;AAExC,UAAA;AACqB,UAAA;AACmB,YAAA;AAExC,UAAA;AAEC,UAAA;AAAA,QAAA;AAdI,QAAA;AAgBR,MAAA;AAEI,sBAAA;AAEA,QAAA;AAAA,QAAA;AACM,UAAA;AACiB,UAAA;AACb,UAAA;AACC,UAAA;AACC,UAAA;AAEXA,UAAAA;AAAe,QAAA;AAGrB,MAAA;AAEAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACM,UAAA;AACiB,UAAA;AACP,UAAA;AACL,UAAA;AACW,UAAA;AACmB,YAAA;AAExC,UAAA;AACqB,UAAA;AACmB,YAAA;AAExC,UAAA;AACD,UAAA;AAAA,QAAA;AAED,MAAA;AAEAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACM,UAAA;AACiB,UAAA;AACb,UAAA;AACkB,UAAA;AAChB,UAAA;AAEXA,UAAAA;AAAe,QAAA;AACjB,MAAA;AACF,IAAA;AAGEA,IAAAA;AAAC,MAAA;AAAA,MAAA;AACM,QAAA;AACiB,QAAA;AACb,QAAA;AACC,QAAA;AACX,QAAA;AAAA,MAAA;AAED,IAAA;AAEJ,EAAA;AAEJ;AAGE;AAAC,EAAA;AAAA,EAAA;AACO,IAAA;AACC,IAAA;AACC,IAAA;AACH,IAAA;AACC,IAAA;AAEN,IAAA;AAAAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACK,UAAA;AACK,UAAA;AACE,UAAA;AACC,UAAA;AAAA,QAAA;AACjB,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACK,UAAA;AACK,UAAA;AACE,UAAA;AACC,UAAA;AAAA,QAAA;AACjB,MAAA;AAAA,IAAA;AAAA,EAAA;AACF;AAIA;AAAC,EAAA;AAAA,EAAA;AACO,IAAA;AACC,IAAA;AACC,IAAA;AACH,IAAA;AACC,IAAA;AAEN,IAAA;AAAAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACK,UAAA;AACK,UAAA;AACE,UAAA;AACC,UAAA;AAAA,QAAA;AACjB,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACK,UAAA;AACK,UAAA;AACE,UAAA;AACC,UAAA;AAAA,QAAA;AACjB,MAAA;AAAA,IAAA;AAAA,EAAA;AACF;AAGgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A1B8jFoB;AACA;A4B/yFf;AA8Gb;AAtG4D;AACpE,EAAA;AACA,EAAA;AACA,EAAA;AACgB,EAAA;AACZ;AACW,EAAA;AACe,EAAA;AACP,EAAA;AAEK,EAAA;AACI,EAAA;AACQ,EAAA;AAElB,EAAA;AACR,IAAA;AACa,MAAA;AACD,MAAA;AACb,MAAA;AACI,MAAA;AACK,MAAA;AACpB,IAAA;AACS,EAAA;AAEiB,EAAA;AACF,IAAA;AAC1B,EAAA;AAEmC,EAAA;AACZ,IAAA;AAEE,IAAA;AACJ,MAAA;AACJ,MAAA;AAET,MAAA;AACwB,QAAA;AACf,QAAA;AACH,QAAA;AACI,MAAA;AACZ,QAAA;AAC6B,UAAA;AAC7B,QAAA;AACA,MAAA;AACkB,QAAA;AACpB,MAAA;AAC4B,IAAA;AACR,MAAA;AACtB,IAAA;AACF,EAAA;AAE4C,EAAA;AAC7B,IAAA;AACA,IAAA;AACQ,IAAA;AACvB,EAAA;AAEgC,EAAA;AACN,IAAA;AACb,MAAA;AACW,MAAA;AACX,MAAA;AACT,MAAA;AACF,IAAA;AAEiB,IAAA;AACJ,IAAA;AAET,IAAA;AACwB,MAAA;AACf,MAAA;AACH,MAAA;AACI,IAAA;AACoB,MAAA;AACZ,MAAA;AACX,MAAA;AACT,IAAA;AACkB,MAAA;AACpB,IAAA;AACF,EAAA;AAEyB,EAAA;AACK,IAAA;AACN,MAAA;AACP,MAAA;AACmB,IAAA;AACT,MAAA;AACd,MAAA;AACI,MAAA;AACf,IAAA;AACF,EAAA;AAEoB,EAAA;AAEc,EAAA;AACC,IAAA;AAEtB,IAAA;AAGR,IAAA;AAEI,MAAA;AAAA,MAAA;AAEQ,QAAA;AACe,UAAA;AACE,UAAA;AACxB,QAAA;AAAA,MAAA;AAJK,MAAA;AAOX,IAAA;AAEJ,EAAA;AAGE,EAAA;AACO,oBAAA;AACC,sBAAA;AACD,sBAAA;AAIL,IAAA;AAEqB,IAAA;AAEhB,oBAAA;AACe,MAAA;AACf,QAAA;AAAA,QAAA;AACM,UAAA;AACE,UAAA;AACe,YAAA;AACG,YAAA;AAGzB,UAAA;AACe,UAAA;AAEf,UAAA;AAAC,4BAAA;AAGA,4BAAA;AACE,8BAAA;AACA,8BAAA;AAGH,YAAA;AAAA,UAAA;AAAA,QAAA;AACF,MAAA;AAGFD,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACM,UAAA;AACE,UAAA;AACe,YAAA;AACG,YAAA;AAGzB,UAAA;AACe,UAAA;AAEf,UAAA;AAAC,4BAAA;AAGA,4BAAA;AACE,8BAAA;AACA,8BAAA;AAGH,YAAA;AAAA,UAAA;AAAA,QAAA;AACF,MAAA;AACF,IAAA;AAGG,IAAA;AAKHC,oBAAAA;AAAC,MAAA;AAAA,MAAA;AACM,QAAA;AACE,QAAA;AACe,UAAA;AACE,UAAA;AACxB,QAAA;AACS,QAAA;AACoB,QAAA;AAEhB,QAAA;AAAkB,MAAA;AACjC,IAAA;AACF,EAAA;AAIA,EAAA;AACuB,IAAA;AACrBA,oBAAAA;AAAC,MAAA;AAAA,MAAA;AACO,QAAA;AACG,QAAA;AACG,QAAA;AACF,QAAA;AACV,QAAA;AACA,QAAA;AAAA,MAAA;AACF,IAAA;AACF,EAAA;AAIA,EAAA;AACuB,IAAA;AACrBA,oBAAAA;AAAC,MAAA;AAAA,MAAA;AACO,QAAA;AACG,QAAA;AACG,QAAA;AACF,QAAA;AACV,QAAA;AACA,QAAA;AAAA,MAAA;AACF,IAAA;AACF,EAAA;AAIC,EAAA;AAC8B,IAAA;AACH,IAAA;AACC,IAAA;AAC7B,EAAA;AAEJ;AAGE;AAAC,EAAA;AAAA,EAAA;AACO,IAAA;AACC,IAAA;AACC,IAAA;AACH,IAAA;AACC,IAAA;AAEN,IAAA;AAAAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACK,UAAA;AACK,UAAA;AACE,UAAA;AACC,UAAA;AAAA,QAAA;AACjB,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACK,UAAA;AACK,UAAA;AACE,UAAA;AACC,UAAA;AAAA,QAAA;AACjB,MAAA;AAAA,IAAA;AAAA,EAAA;AACF;AAIAD;AAAC,EAAA;AAAA,EAAA;AACO,IAAA;AACC,IAAA;AACC,IAAA;AACH,IAAA;AACC,IAAA;AAEN,IAAA;AAAAC,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACA,UAAA;AACI,UAAA;AACC,UAAA;AACJ,UAAA;AACI,UAAA;AACK,UAAA;AAAA,QAAA;AACd,MAAA;AACC,sBAAA;AACA,sBAAA;AACA,sBAAA;AAAmD,IAAA;AAAA,EAAA;AACtD;A5B+wFoC;AACA;A6B1iGf;AAmFf;AA3EgE;AACtE,EAAA;AACA,EAAA;AACA,EAAA;AACgB,EAAA;AACZ;AACmB,EAAA;AACO,EAAA;AACE,EAAA;AACQ,EAAA;AAGtC,EAAA;AAIoB,EAAA;AACR,IAAA;AACG,MAAA;AACK,MAAA;AACY,MAAA;AAChC,IAAA;AAC8B,EAAA;AAEV,EAAA;AACG,IAAA;AACD,MAAA;AACtB,IAAA;AACe,EAAA;AAEW,EAAA;AACT,IAAA;AACJ,IAAA;AAET,IAAA;AACa,MAAA;AACN,MAAA;AACD,MAAA;AACI,IAAA;AACZ,MAAA;AAEU,QAAA;AAEV,MAAA;AACa,MAAA;AACb,IAAA;AACkB,MAAA;AACpB,IAAA;AACF,EAAA;AAE+B,EAAA;AACZ,IAAA;AACJ,IAAA;AAET,IAAA;AACkB,MAAA;AACX,MAAA;AACD,MAAA;AACI,IAAA;AACH,MAAA;AACT,IAAA;AACkB,MAAA;AACpB,IAAA;AACF,EAAA;AAEkC,EAAA;AACnB,IAAA;AACA,IAAA;AACf,EAAA;AAEoB,EAAA;AAGlB,EAAA;AACO,oBAAA;AAGD,oBAAA;AACD,oBAAA;AAOA,IAAA;AAMDD,IAAAA;AACEC,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACM,UAAA;AACE,UAAA;AACI,YAAA;AACC,YAAA;AACE,YAAA;AACL,YAAA;AACU,YAAA;AACT,YAAA;AACM,YAAA;AACN,YAAA;AACM,YAAA;AAChB,UAAA;AACS,UAAA;AACV,UAAA;AAAA,QAAA;AAED,MAAA;AAEsB,MAAA;AACnB,QAAA;AAAA,QAAA;AACM,UAAA;AACoB,UAAA;AAChB,UAAA;AACV,UAAA;AAAA,QAAA;AAED,MAAA;AAEJ,IAAA;AAEJ,EAAA;AAIA,EAAA;AAAC,IAAA;AAAA,IAAA;AACO,MAAA;AACG,MAAA;AACG,MAAA;AACF,MAAA;AACV,MAAA;AACA,MAAA;AACe,MAAA;AACS,MAAA;AACH,QAAA;AACN,QAAA;AACf,MAAA;AAAA,IAAA;AACF,EAAA;AAIC,EAAA;AAML;AAGE;AAAC,EAAA;AAAA,EAAA;AACO,IAAA;AACC,IAAA;AACC,IAAA;AACH,IAAA;AACC,IAAA;AAEN,IAAA;AAAAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACK,UAAA;AACK,UAAA;AACE,UAAA;AACC,UAAA;AAAA,QAAA;AACjB,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACK,UAAA;AACK,UAAA;AACE,UAAA;AACC,UAAA;AAAA,QAAA;AACjB,MAAA;AAAA,IAAA;AAAA,EAAA;AACF;A7BygGoC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/Users/ilya/work/tonpay/ton-pay/packages/ui-react/dist/index.js","sourcesContent":[null,"import * as React from \"react\";\nimport { useEffect, useState, useCallback } from \"react\";\nimport { useTonAddress, useTonConnectUI } from \"@tonconnect/ui-react\";\nimport type { TonPayButtonProps } from \"../../types\";\nimport { classNames, toCssSize, getUserIp } from \"../../utils\";\nimport { TonIcon } from \"../icons\";\nimport { NotificationRoot, ErrorTransactionNotification } from \"../notification\";\nimport { PaymentModal } from \"../payment-modal/PaymentModal\";\nimport { useMoonPayIframe } from \"../../hooks/useMoonPayIframe\";\nimport { PRESETS, injectStyles } from \"./styles\";\n\ninjectStyles();\n\nexport const TonPayButton: React.FC<TonPayButtonProps> = ({\n handlePay,\n isLoading = false,\n variant = \"long\",\n preset,\n bgColor,\n textColor,\n borderRadius = 8,\n fontFamily = \"inherit\",\n width = 300,\n height = 44,\n text,\n loadingText = \"Processing...\",\n style,\n className,\n disabled = false,\n onError,\n showErrorNotification = true,\n amount,\n currency,\n apiKey,\n isOnRampAvailable = false,\n onCardPaymentSuccess,\n itemTitle,\n}) => {\n const address = useTonAddress(true);\n const [tonConnectUI] = useTonConnectUI();\n\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [onRampAvailable, setOnRampAvailable] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [internalLoading, setInternalLoading] = useState(false);\n const [userIp, setUserIp] = useState(\"\");\n\n const { checkAvailability, fetchOnRampLink } = useMoonPayIframe({\n apiKey,\n chain: \"mainnet\",\n });\n\n useEffect(() => {\n getUserIp().then(setUserIp);\n }, []);\n\n useEffect(() => {\n if (!errorMessage) return;\n const timerId = setTimeout(() => setErrorMessage(null), 3000);\n return () => clearTimeout(timerId);\n }, [errorMessage]);\n\n useEffect(() => {\n let isActive = true;\n\n const check = async () => {\n if (isOnRampAvailable && apiKey && userIp) {\n setInternalLoading(true);\n try {\n const parsedAmount =\n typeof amount === \"string\" ? parseFloat(amount) : amount || 0;\n const available = await checkAvailability(\n parsedAmount,\n currency || \"TON\",\n userIp\n );\n if (isActive) setOnRampAvailable(available);\n } catch {\n if (isActive) setOnRampAvailable(false);\n } finally {\n if (isActive) setInternalLoading(false);\n }\n } else {\n if (isActive) setOnRampAvailable(false);\n }\n };\n\n check();\n return () => {\n isActive = false;\n };\n }, [apiKey, amount, currency, isOnRampAvailable, checkAvailability, userIp]);\n\n const handleDisconnect = useCallback(() => {\n tonConnectUI.disconnect();\n }, [tonConnectUI]);\n\n const handlePayWithCrypto = useCallback(async () => {\n setIsModalOpen(false);\n try {\n await handlePay();\n } catch (err) {\n onError?.(err);\n if (showErrorNotification) {\n const raw =\n typeof err === \"object\" && err && \"message\" in err\n ? String((err as Error).message)\n : String(err ?? \"\");\n setErrorMessage(raw || \"Wallet connection modal closed\");\n }\n }\n }, [handlePay, onError, showErrorNotification]);\n\n const onPayClick = useCallback(async () => {\n if (onRampAvailable) {\n setIsModalOpen(true);\n } else {\n handlePayWithCrypto();\n }\n }, [onRampAvailable, handlePayWithCrypto]);\n\n const handleFetchOnRampLink = useCallback(\n async (_providerId: string) => {\n return fetchOnRampLink({\n amount:\n typeof amount === \"string\" ? parseFloat(amount) : amount || 0,\n asset: currency || \"TON\",\n recipientAddr: address,\n userIp,\n redirectURL: \"\",\n });\n },\n [fetchOnRampLink, amount, currency, address, userIp]\n );\n\n const presetConfig = preset ? PRESETS[preset] : null;\n const finalBgColor = bgColor ?? presetConfig?.bgColor ?? PRESETS.default.bgColor;\n const finalTextColor =\n textColor ?? presetConfig?.textColor ?? PRESETS.default.textColor;\n\n const cssVars: Record<string, string | number | undefined> = {\n \"--tp-bg\": finalBgColor,\n \"--tp-text\": finalTextColor,\n \"--tp-radius\":\n typeof borderRadius === \"number\" ? `${borderRadius}px` : borderRadius,\n \"--tp-font\": fontFamily,\n \"--tp-width\": toCssSize(width),\n \"--tp-height\": toCssSize(height),\n };\n\n const isDisabled = isLoading || disabled || internalLoading;\n\n const renderContent = () => {\n if (text) return <span>{text}</span>;\n \n if (variant === \"short\") {\n return (\n <div className=\"tp-btn-content\">\n <TonIcon />\n <span>Pay</span>\n </div>\n );\n }\n\n return (\n <div className=\"tp-btn-content\">\n <span>Pay with</span>\n <TonIcon />\n <span>Pay</span>\n </div>\n );\n };\n\n return (\n <div\n style={{ ...cssVars, ...style } as React.CSSProperties}\n className={classNames(\"tp-wrap\", className)}\n >\n <div className=\"tp-btn-container\">\n <button\n type=\"button\"\n className={classNames(\"tp-btn\", isLoading && \"loading\", \"no-menu\")}\n onClick={isDisabled ? undefined : onPayClick}\n disabled={isDisabled}\n >\n {isLoading ? (\n <div className=\"tp-btn-content\">\n <span className=\"tp-spinner\" />\n <span>{loadingText}</span>\n </div>\n ) : (\n renderContent()\n )}\n </button>\n </div>\n\n <PaymentModal\n isOpen={isModalOpen}\n onClose={() => setIsModalOpen(false)}\n onPayWithCrypto={handlePayWithCrypto}\n walletAddress={address}\n onDisconnect={handleDisconnect}\n amount={amount ? String(amount) : \"0.1\"}\n currency={currency || \"TON\"}\n itemTitle={itemTitle}\n fetchOnRampLink={handleFetchOnRampLink}\n onRampAvailable={onRampAvailable}\n onPaymentSuccess={onCardPaymentSuccess}\n />\n\n {errorMessage && (\n <NotificationRoot>\n <ErrorTransactionNotification text={errorMessage} />\n </NotificationRoot>\n )}\n </div>\n );\n};\n\n","export function shortenAddress(\n address: string | null | undefined,\n head: number = 4,\n tail: number = 4\n): string {\n if (!address || typeof address !== \"string\") return \"\";\n if (address.length <= head + tail + 3) return address;\n return `${address.slice(0, head)}...${address.slice(-tail)}`;\n}\n\nexport function toCssSize(value?: number | string): string | undefined {\n if (value === undefined) return undefined;\n return typeof value === \"number\" ? `${value}px` : value;\n}\n\nexport function isGradient(value: string): boolean {\n return value.includes(\"gradient(\");\n}\n\nexport function getMenuBgColor(bg: string): string {\n return isGradient(bg) ? \"#0098EA\" : bg;\n}\n\nexport function classNames(\n ...classes: (string | undefined | null | false)[]\n): string {\n return classes.filter(Boolean).join(\" \");\n}\n\nexport async function getUserIp(): Promise<string> {\n try {\n const response = await fetch(\"https://api.ipify.org?format=json\");\n const data = await response.json();\n return data.ip;\n } catch (error) {\n console.error(\"Failed to fetch user IP:\", error);\n return \"\";\n }\n}\n","import * as React from \"react\";\n\ninterface IconProps {\n size?: number;\n color?: string;\n className?: string;\n}\n\nexport const TonIcon: React.FC<IconProps> = ({ size = 24, className }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n aria-hidden\n >\n <g clipPath=\"url(#ton-icon-clip)\">\n <path\n 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\"\n fill=\"#0098EA\"\n />\n <path\n 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\"\n fill=\"white\"\n />\n <path\n 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\"\n fill=\"#0098EA\"\n />\n </g>\n <defs>\n <clipPath id=\"ton-icon-clip\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\nexport const TonIconBlue: React.FC<IconProps> = ({ size = 24, className }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n aria-hidden\n >\n <path\n 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\"\n fill=\"#0098EA\"\n />\n <path\n 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\"\n fill=\"white\"\n />\n </svg>\n);\n\nexport const CopyIcon: React.FC<IconProps> = ({\n size = 24,\n color = \"currentColor\",\n className,\n}) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n aria-hidden\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M7.76228 2.09998H10.2378C11.0458 2.09997 11.7067 2.09996 12.2438 2.14384C12.7997 2.18926 13.3017 2.28614 13.7706 2.52505C14.5045 2.89896 15.1011 3.49558 15.475 4.22941C15.7139 4.6983 15.8108 5.20038 15.8562 5.75629C15.9001 6.29337 15.9001 6.95422 15.9001 7.76227V8.1H16.2377C17.0457 8.09999 17.7066 8.09998 18.2437 8.14386C18.7996 8.18928 19.3017 8.28616 19.7705 8.52507C20.5044 8.89898 21.101 9.4956 21.4749 10.2294C21.7138 10.6983 21.8107 11.2004 21.8561 11.7563C21.9 12.2934 21.9 12.9542 21.9 13.7623V16.2377C21.9 17.0458 21.9 17.7066 21.8561 18.2437C21.8107 18.7996 21.7138 19.3017 21.4749 19.7706C21.101 20.5044 20.5044 21.101 19.7705 21.4749C19.3017 21.7138 18.7996 21.8107 18.2437 21.8561C17.7066 21.9 17.0458 21.9 16.2378 21.9H13.7623C12.9543 21.9 12.2934 21.9 11.7563 21.8561C11.2004 21.8107 10.6983 21.7138 10.2294 21.4749C9.49561 21.101 8.89898 20.5044 8.52508 19.7706C8.28616 19.3017 8.18928 18.7996 8.14386 18.2437C8.09998 17.7066 8.09999 17.0458 8.1 16.2377V15.9H7.76227C6.95426 15.9 6.29335 15.9 5.75629 15.8561C5.20038 15.8107 4.6983 15.7138 4.22941 15.4749C3.49558 15.101 2.89896 14.5044 2.52505 13.7705C2.28614 13.3017 2.18926 12.7996 2.14384 12.2437C2.09996 11.7066 2.09997 11.0458 2.09998 10.2377V7.76228C2.09997 6.95424 2.09996 6.29336 2.14384 5.75629C2.18926 5.20038 2.28614 4.6983 2.52505 4.22941C2.89896 3.49558 3.49558 2.89896 4.22941 2.52505C4.6983 2.28614 5.20038 2.18926 5.75629 2.14384C6.29336 2.09996 6.95425 2.09997 7.76228 2.09998ZM8.1 14.1V13.7623C8.09999 12.9542 8.09998 12.2934 8.14386 11.7563C8.18928 11.2004 8.28616 10.6983 8.52508 10.2294C8.89898 9.4956 9.49561 8.89898 10.2294 8.52507C10.6983 8.28616 11.2004 8.18928 11.7563 8.14386C12.2934 8.09998 12.9542 8.09999 13.7623 8.1H14.1001V7.79998C14.1001 6.94505 14.0994 6.35798 14.0622 5.90287C14.0259 5.45827 13.9593 5.21944 13.8712 5.0466C13.6699 4.65146 13.3486 4.3302 12.9535 4.12886C12.7806 4.04079 12.5418 3.97419 12.0972 3.93786C11.6421 3.90068 11.055 3.89998 10.2001 3.89998H7.79998C6.94505 3.89998 6.35798 3.90068 5.90287 3.93786C5.45827 3.97419 5.21944 4.04079 5.0466 4.12886C4.65146 4.3302 4.3302 4.65146 4.12886 5.0466C4.04079 5.21944 3.97419 5.45827 3.93786 5.90287C3.90068 6.35798 3.89998 6.94505 3.89998 7.79998V10.2C3.89998 11.0549 3.90068 11.642 3.93786 12.0971C3.97419 12.5417 4.04079 12.7805 4.12886 12.9534C4.3302 13.3485 4.65146 13.6698 5.0466 13.8711C5.21944 13.9592 5.45827 14.0258 5.90287 14.0621C6.35798 14.0993 6.94505 14.1 7.79998 14.1H8.1ZM11.0466 10.1289C11.2195 10.0408 11.4583 9.97421 11.9029 9.93788C12.358 9.9007 12.9451 9.9 13.8 9.9H16.2C17.0549 9.9 17.642 9.9007 18.0971 9.93788C18.5417 9.97421 18.7805 10.0408 18.9534 10.1289C19.3485 10.3302 19.6698 10.6515 19.8711 11.0466C19.9592 11.2195 20.0258 11.4583 20.0621 11.9029C20.0993 12.358 20.1 12.9451 20.1 13.8V16.2C20.1 17.0549 20.0993 17.642 20.0621 18.0971C20.0258 18.5417 19.9592 18.7805 19.8711 18.9534C19.6698 19.3485 19.3485 19.6698 18.9534 19.8711C18.7805 19.9592 18.5417 20.0258 18.0971 20.0621C17.642 20.0993 17.0549 20.1 16.2 20.1H13.8C12.9451 20.1 12.358 20.0993 11.9029 20.0621C11.4583 20.0258 11.2195 19.9592 11.0466 19.8711C10.6515 19.6698 10.3302 19.3485 10.1289 18.9534C10.0408 18.7805 9.97421 18.5417 9.93788 18.0971C9.9007 17.642 9.9 17.0549 9.9 16.2V13.8C9.9 12.9451 9.9007 12.358 9.93788 11.9029C9.97421 11.4583 10.0408 11.2195 10.1289 11.0466C10.3302 10.6515 10.6515 10.3302 11.0466 10.1289Z\"\n fill={color}\n />\n </svg>\n);\n\nexport const DisconnectIcon: React.FC<IconProps> = ({\n size = 24,\n color = \"currentColor\",\n className,\n}) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n aria-hidden\n >\n <path\n d=\"M8.7624 3.10001C7.95435 3.1 7.29349 3.09999 6.75642 3.14387C6.2005 3.18929 5.69842 3.28617 5.22954 3.52508C4.4957 3.89899 3.89908 4.49561 3.52517 5.22944C3.28626 5.69833 3.18938 6.20041 3.14396 6.75632C3.10008 7.2934 3.10009 7.95424 3.1001 8.76229V15.2377C3.10009 16.0458 3.10008 16.7066 3.14396 17.2437C3.18938 17.7996 3.28626 18.3017 3.52517 18.7706C3.89908 19.5044 4.4957 20.101 5.22954 20.4749C5.69842 20.7138 6.2005 20.8107 6.75642 20.8561C7.29349 20.9 7.95434 20.9 8.76239 20.9H12.0001C12.4972 20.9 12.9001 20.4971 12.9001 20C12.9001 19.503 12.4972 19.1 12.0001 19.1H8.8001C7.94517 19.1 7.3581 19.0993 6.90299 19.0621C6.45839 19.0258 6.21956 18.9592 6.04672 18.8711C5.65158 18.6698 5.33032 18.3485 5.12898 17.9534C5.04092 17.7805 4.97431 17.5417 4.93798 17.0971C4.9008 16.642 4.9001 16.0549 4.9001 15.2V8.80001C4.9001 7.94508 4.9008 7.35801 4.93798 6.9029C4.97431 6.4583 5.04092 6.21947 5.12898 6.04663C5.33032 5.65149 5.65158 5.33023 6.04672 5.12889C6.21956 5.04082 6.45839 4.97422 6.90299 4.93789C7.3581 4.90071 7.94517 4.90001 8.8001 4.90001H12.0001C12.4972 4.90001 12.9001 4.49706 12.9001 4.00001C12.9001 3.50295 12.4972 3.10001 12.0001 3.10001H8.7624Z\"\n fill={color}\n />\n <path\n d=\"M17.6364 7.3636C17.2849 7.01212 16.7151 7.01212 16.3636 7.3636C16.0121 7.71507 16.0121 8.28492 16.3636 8.63639L18.8272 11.1H9.00001C8.50295 11.1 8.10001 11.5029 8.10001 12C8.10001 12.497 8.50295 12.9 9.00001 12.9H18.8272L16.3636 15.3636C16.0121 15.7151 16.0121 16.2849 16.3636 16.6364C16.7151 16.9879 17.2849 16.9879 17.6364 16.6364L21.6364 12.6364C21.9879 12.2849 21.9879 11.7151 21.6364 11.3636L17.6364 7.3636Z\"\n fill={color}\n />\n </svg>\n);\n\nexport const CloseIcon: React.FC<IconProps> = ({\n size = 24,\n color = \"currentColor\",\n className,\n}) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n aria-hidden\n >\n <path\n d=\"M18 6L6 18\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M6 6L18 18\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const BackIcon: React.FC<IconProps> = ({\n size = 24,\n color = \"currentColor\",\n className,\n}) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n aria-hidden\n >\n <path\n d=\"M19 12H5\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M12 19L5 12L12 5\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const CheckIcon: React.FC<IconProps> = ({\n size = 24,\n color = \"currentColor\",\n className,\n}) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n aria-hidden\n >\n <path\n d=\"M20 6L9 17L4 12\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const ErrorIcon: React.FC<IconProps> = ({\n size = 24,\n color = \"currentColor\",\n className,\n}) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n aria-hidden\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke={color} strokeWidth=\"2\" />\n <path d=\"M12 8V12\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" />\n <circle cx=\"12\" cy=\"16\" r=\"1\" fill={color} />\n </svg>\n);\n\nexport const MenuIcon: React.FC<IconProps> = ({\n size = 24,\n color = \"currentColor\",\n className,\n}) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n aria-hidden\n >\n <circle cx=\"12\" cy=\"12\" r=\"2\" fill={color} />\n <circle cx=\"19\" cy=\"12\" r=\"2\" fill={color} />\n <circle cx=\"5\" cy=\"12\" r=\"2\" fill={color} />\n </svg>\n);\n\nexport const ErrorDotIcon: React.FC<{ color?: string }> = ({\n color = \"#FF5252\",\n}) => (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden\n >\n <circle cx=\"12\" cy=\"12\" r=\"11\" fill={color} />\n <path\n d=\"M7.864 9.136A1.5 1.5 0 0 1 9.136 7.864L12 10.727 14.864 7.864A1.5 1.5 0 0 1 16.136 9.136L13.273 12 16.136 14.864a1.5 1.5 0 0 1-2.272 2.272L12 13.273 9.136 17.136A1.5 1.5 0 1 1 7.864 14.864L10.727 12 7.864 9.136Z\"\n fill=\"#fff\"\n />\n </svg>\n);\n\nexport const SpinnerIcon: React.FC<{ className?: string }> = ({ className }) => (\n <span className={className} aria-hidden />\n);\n\n","import * as React from \"react\";\nimport type { NotificationProps } from \"../../types\";\n\nconst notificationStyles = `\n.tp-noti-root{position:fixed;top:16px;right:16px;z-index:10000;display:flex;flex-direction:column;gap:10px}\n.tp-noti-card{width:256px;padding:12px 16px;display:flex;gap:9px;align-items:flex-start;background:#ffffff;color:#111827;border-radius:16px;box-shadow:0 4px 24px rgba(0,0,0,.16);animation:tp-fade-in .2s ease}\n.tp-noti-content{flex:1;min-width:0}\n.tp-noti-title{font-size:15px;font-weight:700;line-height:20px;margin:0}\n.tp-noti-text{margin-top:4px;color:#6b7280;font-size:13px;line-height:18px;word-break:break-word}\n.tp-noti-icon{width:24px;height:24px;margin-top:2px;flex:0 0 auto}\n`;\n\nlet stylesInjected = false;\n\nfunction injectNotificationStyles(): void {\n if (typeof document === \"undefined\" || stylesInjected) return;\n const style = document.createElement(\"style\");\n style.id = \"tonpay-notification-styles\";\n style.textContent = notificationStyles;\n document.head.appendChild(style);\n stylesInjected = true;\n}\n\ninjectNotificationStyles();\n\nexport const NotificationCard: React.FC<NotificationProps> = ({\n title,\n text,\n icon,\n className,\n style,\n}) => {\n return (\n <div\n className={[\"tp-noti-card\", className].filter(Boolean).join(\" \")}\n style={style}\n >\n <div className=\"tp-noti-content\">\n <h3 className=\"tp-noti-title\">{title}</h3>\n {text && <div className=\"tp-noti-text\">{text}</div>}\n </div>\n {icon && <div className=\"tp-noti-icon\">{icon}</div>}\n </div>\n );\n};\n\nexport const NotificationRoot: React.FC<{ children?: React.ReactNode }> = ({\n children,\n}) => {\n return <div className=\"tp-noti-root\">{children}</div>;\n};\n","import * as React from \"react\";\nimport { ErrorDotIcon } from \"../icons\";\nimport { NotificationCard } from \"./Notification\";\n\ninterface ErrorTransactionNotificationProps {\n text?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport const ErrorTransactionNotification: React.FC<\n ErrorTransactionNotificationProps\n> = ({ text, className, style }) => {\n return (\n <NotificationCard\n title=\"Transaction cancelled\"\n text={text}\n icon={<ErrorDotIcon />}\n className={className}\n style={style}\n />\n );\n};\n","import * as React from \"react\";\nimport { useState, useEffect, useCallback, useRef } from \"react\";\nimport BottomSheet from \"../bottom-sheet/BottomSheet\";\nimport {\n TonIconBlue,\n CloseIcon,\n BackIcon,\n CheckIcon,\n ErrorIcon,\n MenuIcon,\n} from \"../icons\";\nimport type { PaymentModalProps, PaymentViewState } from \"../../types\";\nimport \"./PaymentModal.css\";\n\nconst PROVIDER = { id: \"moonpay\", name: \"Moonpay\", iconClass: \"icon-moonpay\" };\nconst IFRAME_LOAD_TIMEOUT = 30000;\n\nexport const PaymentModal: React.FC<PaymentModalProps> = ({\n isOpen,\n onClose,\n onPayWithCrypto,\n amount = \"0.1\",\n currency = \"TON\",\n itemTitle = \"Pay to Guitar from Demo Store\",\n walletAddress,\n onDisconnect,\n fetchOnRampLink,\n onRampAvailable = false,\n onPaymentSuccess,\n}) => {\n const [view, setView] = useState<PaymentViewState>(\"main\");\n const [isMobile, setIsMobile] = useState(false);\n const [showMenu, setShowMenu] = useState(false);\n const [onRampLink, setOnRampLink] = useState<string | null>(null);\n const [onRampError, setOnRampError] = useState<string | null>(null);\n const [isOnRampLoading, setIsOnRampLoading] = useState(false);\n const [iframeLoaded, setIframeLoaded] = useState(false);\n const [iframeError, setIframeError] = useState<string | null>(null);\n const [sheetDetent, setSheetDetent] = useState<number[]>([0.55]);\n\n const iframeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const fetchStartedRef = useRef(false);\n const contentRef = useRef<HTMLDivElement>(null);\n\n const handlePaymentSuccess = useCallback(() => {\n if (iframeTimeoutRef.current) {\n clearTimeout(iframeTimeoutRef.current);\n }\n setView(\"success\");\n onPaymentSuccess?.();\n setTimeout(() => {\n onClose();\n }, 2000);\n }, [onClose, onPaymentSuccess]);\n\n const handlePaymentError = useCallback((errorMessage: string) => {\n if (iframeTimeoutRef.current) {\n clearTimeout(iframeTimeoutRef.current);\n }\n setIframeError(errorMessage);\n setView(\"error\");\n }, []);\n\n const handleRetry = useCallback(() => {\n setOnRampLink(null);\n setOnRampError(null);\n setIframeError(null);\n setIframeLoaded(false);\n fetchStartedRef.current = false;\n setView(\"card\");\n }, []);\n\n useEffect(() => {\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === \"TONPAY_PAYMENT_SUCCESS\") {\n handlePaymentSuccess();\n }\n if (event.data?.type === \"TONPAY_PAYMENT_ERROR\") {\n const payload = event.data.payload;\n handlePaymentError(payload?.message || \"Payment failed\");\n }\n if (event.data?.type === \"TONPAY_IFRAME_LOADED\") {\n setIframeLoaded(true);\n if (iframeTimeoutRef.current) {\n clearTimeout(iframeTimeoutRef.current);\n }\n }\n if (event.data?.type === \"TONPAY_MOONPAY_EVENT\") {\n const payload = event.data.payload;\n if (\n payload?.type === \"onTransactionCompleted\" ||\n payload?.eventName === \"transactionCompleted\"\n ) {\n handlePaymentSuccess();\n }\n if (\n payload?.type === \"onTransactionFailed\" ||\n payload?.eventName === \"transactionFailed\"\n ) {\n handlePaymentError(payload?.message || \"Transaction failed\");\n }\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [handlePaymentSuccess, handlePaymentError]);\n\n useEffect(() => {\n if (view !== \"card\") {\n fetchStartedRef.current = false;\n }\n }, [view]);\n\n useEffect(() => {\n if (\n view === \"card\" &&\n !onRampLink &&\n !onRampError &&\n fetchOnRampLink &&\n !fetchStartedRef.current\n ) {\n fetchStartedRef.current = true;\n setIsOnRampLoading(true);\n setOnRampError(null);\n setIframeLoaded(false);\n setIframeError(null);\n\n fetchOnRampLink(PROVIDER.id)\n .then((link) => {\n setOnRampLink(link);\n iframeTimeoutRef.current = setTimeout(() => {\n if (!iframeLoaded) {\n handlePaymentError(\n \"Payment service is taking too long to load. Please try again.\"\n );\n }\n }, IFRAME_LOAD_TIMEOUT);\n })\n .catch((err) => {\n const errorMsg = err?.message || \"Failed to initialize payment\";\n setOnRampError(errorMsg);\n fetchStartedRef.current = false;\n })\n .finally(() => setIsOnRampLoading(false));\n }\n\n return () => {\n if (iframeTimeoutRef.current) {\n clearTimeout(iframeTimeoutRef.current);\n }\n };\n }, [view, onRampLink, onRampError, fetchOnRampLink, iframeLoaded, handlePaymentError]);\n\n useEffect(() => {\n const checkMobile = () => {\n setIsMobile(window.innerWidth < 768);\n };\n checkMobile();\n window.addEventListener(\"resize\", checkMobile);\n return () => window.removeEventListener(\"resize\", checkMobile);\n }, []);\n\n useEffect(() => {\n if (isOpen) {\n setView(\"main\");\n setShowMenu(false);\n setOnRampLink(null);\n setOnRampError(null);\n setIframeLoaded(false);\n setIframeError(null);\n if (iframeTimeoutRef.current) {\n clearTimeout(iframeTimeoutRef.current);\n }\n }\n }, [isOpen]);\n\n useEffect(() => {\n if (!isMobile || !isOpen) return;\n\n const updateHeight = () => {\n if (contentRef.current) {\n const height = contentRef.current.scrollHeight;\n const windowHeight = window.innerHeight;\n const detent = Math.min((height + 40) / windowHeight, 0.95);\n setSheetDetent([detent]);\n }\n };\n\n setTimeout(updateHeight, 50);\n\n const observer = new ResizeObserver(updateHeight);\n if (contentRef.current) {\n observer.observe(contentRef.current);\n }\n\n return () => observer.disconnect();\n }, [view, isMobile, isOpen]);\n\n const handleBack = () => setView(\"main\");\n\n const handleIframeLoad = () => {\n setIframeLoaded(true);\n if (iframeTimeoutRef.current) {\n clearTimeout(iframeTimeoutRef.current);\n }\n };\n\n const handleIframeError = () => {\n handlePaymentError(\"Failed to load payment service. Please try again.\");\n };\n\n const renderHeader = () => (\n <div className=\"pm-header\">\n {view !== \"main\" ? (\n <button className=\"pm-back-btn\" onClick={handleBack}>\n <BackIcon />\n </button>\n ) : (\n <div style={{ width: 32 }} />\n )}\n <div className=\"pm-title\">New Purchase</div>\n <div style={{ display: \"flex\", gap: 8 }}>\n {walletAddress && view === \"main\" && (\n <div style={{ position: \"relative\" }}>\n <button className=\"pm-close-btn\" onClick={() => setShowMenu(!showMenu)}>\n <MenuIcon />\n </button>\n {showMenu && (\n <div className=\"pm-menu-dropdown\">\n <div className=\"pm-menu-item disabled\">\n {walletAddress.slice(0, 4)}...{walletAddress.slice(-4)}\n </div>\n <div\n className=\"pm-menu-item danger\"\n onClick={() => {\n onDisconnect?.();\n setShowMenu(false);\n }}\n >\n Disconnect\n </div>\n </div>\n )}\n </div>\n )}\n <button className=\"pm-close-btn\" onClick={onClose}>\n <CloseIcon />\n </button>\n </div>\n </div>\n );\n\n const renderMainView = () => (\n <div className=\"pm-body-main\">\n <div className=\"pm-order-info\">\n <span className=\"pm-order-text\">{itemTitle}</span>\n </div>\n <div className=\"pm-amount-container\">\n <span className=\"pm-amount-label\">Amount</span>\n <div className=\"pm-amount-value\">\n {amount} {currency} <TonIconBlue />\n </div>\n </div>\n <div className=\"pm-actions\">\n <button className=\"pm-btn pm-btn-primary\" onClick={onPayWithCrypto}>\n Pay with Crypto\n </button>\n {onRampAvailable && (\n <button className=\"pm-btn pm-btn-black\" onClick={() => setView(\"card\")}>\n Pay with Card\n </button>\n )}\n </div>\n {onRampAvailable && (\n <div className=\"pm-footer\">\n <span className=\"pm-footer-text\">Processed by {PROVIDER.name}</span>\n </div>\n )}\n </div>\n );\n\n const renderCardView = () => (\n <div className=\"pm-iframe-container\">\n {isOnRampLoading && (\n <div className=\"pm-loading-container\">\n <div className=\"pm-spinner\" />\n <p>Loading {PROVIDER.name}...</p>\n </div>\n )}\n {onRampError && (\n <div className=\"pm-error-inline\">\n <ErrorIcon />\n <p>{onRampError}</p>\n <button className=\"pm-btn pm-btn-outline\" onClick={handleRetry}>\n Try Again\n </button>\n </div>\n )}\n {onRampLink && !isOnRampLoading && !onRampError && (\n <>\n {!iframeLoaded && (\n <div className=\"pm-loading-overlay\">\n <div className=\"pm-spinner\" />\n </div>\n )}\n <iframe\n src={onRampLink}\n title={PROVIDER.name}\n width=\"100%\"\n height=\"100%\"\n frameBorder=\"0\"\n allow=\"accelerometer; autoplay; camera; gyroscope; payment\"\n onLoad={handleIframeLoad}\n onError={handleIframeError}\n style={{ opacity: iframeLoaded ? 1 : 0 }}\n />\n </>\n )}\n </div>\n );\n\n const renderSuccessView = () => (\n <div className=\"pm-success-container\">\n <div className=\"pm-success-icon\">\n <CheckIcon />\n </div>\n <h2 className=\"pm-success-title\">Payment Successful</h2>\n <p className=\"pm-success-text\">Your purchase is being processed</p>\n </div>\n );\n\n const renderErrorView = () => (\n <div className=\"pm-error-container\">\n <div className=\"pm-error-icon\">\n <ErrorIcon />\n </div>\n <h2 className=\"pm-error-title\">Payment Failed</h2>\n <p className=\"pm-error-text\">{iframeError || \"Something went wrong\"}</p>\n <div className=\"pm-error-actions\">\n <button className=\"pm-btn pm-btn-primary\" onClick={handleRetry}>\n Try Again\n </button>\n <button className=\"pm-btn pm-btn-outline\" onClick={onPayWithCrypto}>\n Pay with Crypto Instead\n </button>\n </div>\n </div>\n );\n\n const renderContent = () => (\n <div className=\"pm-content\">\n {view !== \"success\" && view !== \"error\" && renderHeader()}\n {view === \"main\" && renderMainView()}\n {view === \"card\" && renderCardView()}\n {view === \"success\" && renderSuccessView()}\n {view === \"error\" && renderErrorView()}\n </div>\n );\n\n if (isMobile) {\n return (\n <BottomSheet\n isOpen={isOpen}\n onClose={onClose}\n detents={sheetDetent}\n initialDetent={0}\n enableSwipeToClose={view === \"main\"}\n >\n <div ref={contentRef}>{renderContent()}</div>\n </BottomSheet>\n );\n }\n\n if (!isOpen) return null;\n\n return (\n <div className=\"pm-desktop-overlay\" onClick={onClose}>\n <div className=\"pm-desktop-modal\" onClick={(e) => e.stopPropagation()}>\n {renderContent()}\n </div>\n </div>\n );\n};\n","import * as React from \"react\";\nimport { useEffect, useRef, useState, useCallback } from \"react\";\nimport \"./BottomSheet.css\";\nimport type { BottomSheetProps } from \"../../types\";\n\nconst BottomSheet: React.FC<BottomSheetProps> = ({\n isOpen,\n onClose,\n detents = [0.5, 0.9],\n initialDetent = 0,\n children,\n className = \"\",\n backdropClassName = \"\",\n handleClassName = \"\",\n contentClassName = \"\",\n enableBackdropClose = true,\n enableSwipeToClose = true,\n maxHeight = \"90vh\",\n minHeight = \"20vh\",\n}) => {\n const sheetRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const [currentDetent, setCurrentDetent] = useState(initialDetent);\n const [isDragging, setIsDragging] = useState(false);\n const [startY, setStartY] = useState(0);\n const [currentY, setCurrentY] = useState(0);\n const [isScrolling, setIsScrolling] = useState(false);\n const [sheetHeight, setSheetHeight] = useState(0);\n const [isClosing, setIsClosing] = useState(false);\n\n const touchStartYRef = useRef(0);\n const touchStartTimeRef = useRef(0);\n const mouseStartTimeRef = useRef(0);\n const scrollTopRef = useRef(0);\n const canDragRef = useRef(true);\n const closeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const openTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const isClosingRef = useRef(false);\n const isSnappingRef = useRef(false);\n const targetDetentRef = useRef<number | null>(null);\n\n const getDetentValue = useCallback(\n (index: number): number => {\n const clampedIndex = Math.max(0, Math.min(index, detents.length - 1));\n return detents[clampedIndex];\n },\n [detents]\n );\n\n const calculateSheetHeight = useCallback((): number => {\n if (!sheetRef.current) return 0;\n const viewportHeight = window.innerHeight;\n const detentValue = getDetentValue(currentDetent);\n return viewportHeight * detentValue;\n }, [currentDetent, getDetentValue]);\n\n useEffect(() => {\n if (isOpen) {\n if (isClosingRef.current) return;\n\n isClosingRef.current = false;\n setIsClosing(false);\n setCurrentDetent(initialDetent);\n\n if (openTimeoutRef.current) {\n clearTimeout(openTimeoutRef.current);\n }\n\n setSheetHeight(0);\n\n openTimeoutRef.current = setTimeout(() => {\n const viewportHeight = window.innerHeight;\n const detentValue = getDetentValue(initialDetent);\n setSheetHeight(viewportHeight * detentValue);\n openTimeoutRef.current = null;\n }, 10);\n } else {\n if (openTimeoutRef.current) {\n clearTimeout(openTimeoutRef.current);\n openTimeoutRef.current = null;\n }\n setSheetHeight(0);\n setCurrentDetent(initialDetent);\n }\n }, [isOpen, initialDetent, getDetentValue]);\n\n const handleClose = useCallback(() => {\n if (isClosing || isClosingRef.current) return;\n\n isClosingRef.current = true;\n setIsClosing(true);\n setSheetHeight(0);\n setCurrentDetent(initialDetent);\n\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current);\n }\n\n closeTimeoutRef.current = setTimeout(() => {\n isClosingRef.current = false;\n setIsClosing(false);\n onClose();\n }, 200);\n }, [isClosing, onClose, initialDetent]);\n\n useEffect(() => {\n if (\n isOpen &&\n !isDragging &&\n !isSnappingRef.current &&\n targetDetentRef.current === null\n ) {\n const expectedHeight = calculateSheetHeight();\n const heightDiff = Math.abs(sheetHeight - expectedHeight);\n if (heightDiff > 1) {\n setSheetHeight(expectedHeight);\n }\n }\n }, [isOpen, isDragging, currentDetent, sheetHeight, calculateSheetHeight]);\n\n const findNearestDetent = useCallback(\n (position: number): number => {\n const viewportHeight = window.innerHeight;\n const normalizedPosition = position / viewportHeight;\n\n let nearestIndex = 0;\n let minDistance = Math.abs(normalizedPosition - detents[0]);\n\n detents.forEach((detent, index) => {\n const distance = Math.abs(normalizedPosition - detent);\n if (distance < minDistance) {\n minDistance = distance;\n nearestIndex = index;\n }\n });\n\n return nearestIndex;\n },\n [detents]\n );\n\n const snapToDetent = useCallback(\n (detentIndex: number) => {\n const clampedIndex = Math.max(0, Math.min(detentIndex, detents.length - 1));\n isSnappingRef.current = true;\n targetDetentRef.current = clampedIndex;\n const viewportHeight = window.innerHeight;\n const newHeight = viewportHeight * getDetentValue(clampedIndex);\n setCurrentDetent(clampedIndex);\n setSheetHeight(newHeight);\n setTimeout(() => {\n isSnappingRef.current = false;\n targetDetentRef.current = null;\n }, 200);\n },\n [detents, getDetentValue]\n );\n\n const handleTouchStart = useCallback(\n (e: React.TouchEvent) => {\n if (!isOpen || isClosing) return;\n\n const touch = e.touches[0];\n touchStartYRef.current = touch.clientY;\n touchStartTimeRef.current = Date.now();\n setStartY(touch.clientY);\n setCurrentY(touch.clientY);\n\n if (contentRef.current) {\n scrollTopRef.current = contentRef.current.scrollTop;\n setIsScrolling(false);\n canDragRef.current = scrollTopRef.current === 0;\n } else {\n canDragRef.current = true;\n }\n },\n [isOpen, isClosing]\n );\n\n const calculateNewHeight = useCallback(\n (touchY: number): number => {\n const viewportHeight = window.innerHeight;\n const baseHeight = viewportHeight * getDetentValue(currentDetent);\n const delta = touchStartYRef.current - touchY;\n const maxDetentHeight = viewportHeight * Math.max(...detents);\n const minDetentHeight = viewportHeight * Math.min(...detents);\n const isAtMaxDetent = currentDetent === detents.length - 1;\n const isAtMinDetent = currentDetent === 0;\n const isDraggingDown = delta < 0;\n\n let newHeight = baseHeight + delta;\n\n if (isAtMaxDetent) {\n newHeight = Math.max(0, Math.min(maxDetentHeight, newHeight));\n } else if (isAtMinDetent) {\n if (isDraggingDown && enableSwipeToClose) {\n newHeight = Math.max(0, Math.min(maxDetentHeight, newHeight));\n } else {\n newHeight = Math.max(minDetentHeight, Math.min(maxDetentHeight, newHeight));\n }\n } else {\n newHeight = Math.max(minDetentHeight, Math.min(maxDetentHeight, newHeight));\n }\n\n return newHeight;\n },\n [currentDetent, detents, enableSwipeToClose, getDetentValue]\n );\n\n const handleTouchMoveNative = useCallback(\n (e: TouchEvent) => {\n if (!isOpen || isClosing) return;\n\n const touch = e.touches[0];\n if (!touch) return;\n\n const deltaY = touch.clientY - touchStartYRef.current;\n const currentScrollTop = contentRef.current?.scrollTop ?? 0;\n const isContentScrollable = contentRef.current\n ? contentRef.current.scrollHeight > contentRef.current.clientHeight\n : false;\n\n if (!contentRef.current) return;\n\n const touchTarget = e.target as HTMLElement;\n const isTouchingContent = contentRef.current.contains(touchTarget);\n const isTouchingHandle =\n touchTarget.closest(\".bottom-sheet-handle-container\") !== null;\n\n if (isDragging) {\n if (e.cancelable) e.preventDefault();\n setCurrentY(touch.clientY);\n setSheetHeight(calculateNewHeight(touch.clientY));\n return;\n }\n\n if (isTouchingHandle && Math.abs(deltaY) > 5) {\n if (e.cancelable) e.preventDefault();\n setIsDragging(true);\n setIsScrolling(false);\n setCurrentY(touch.clientY);\n setSheetHeight(calculateNewHeight(touch.clientY));\n return;\n }\n\n if (isTouchingContent && !isDragging) {\n if (currentScrollTop > 0) return;\n if (deltaY < 0 && isContentScrollable) return;\n\n if (\n currentScrollTop === 0 &&\n deltaY > 0 &&\n canDragRef.current &&\n Math.abs(deltaY) > 5\n ) {\n if (e.cancelable) e.preventDefault();\n setIsDragging(true);\n setIsScrolling(false);\n setCurrentY(touch.clientY);\n setSheetHeight(calculateNewHeight(touch.clientY));\n }\n }\n },\n [isOpen, isDragging, isClosing, calculateNewHeight]\n );\n\n const handleTouchEnd = useCallback(\n (e?: React.TouchEvent | TouchEvent) => {\n if (!isOpen || isClosing) return;\n if (isScrolling) {\n setIsScrolling(false);\n return;\n }\n if (!isDragging) return;\n\n setIsDragging(false);\n const viewportHeight = window.innerHeight;\n const currentPosition = sheetHeight / viewportHeight;\n const minDetentValue = Math.min(...detents);\n const maxDetentValue = Math.max(...detents);\n const swipeDuration = Date.now() - touchStartTimeRef.current;\n\n const finalTouchY =\n e && \"changedTouches\" in e && e.changedTouches[0]\n ? e.changedTouches[0].clientY\n : currentY;\n const swipeDistance = finalTouchY - touchStartYRef.current;\n const swipeVelocity = Math.abs(swipeDistance) / Math.max(swipeDuration, 1);\n const isAtMaxDetent = currentDetent === detents.length - 1;\n const isAtMinDetent = currentDetent === 0;\n const isSwipingDown = swipeDistance > 0;\n const isSwipingUp = swipeDistance < 0;\n\n if (isAtMaxDetent && isSwipingDown && enableSwipeToClose) {\n if (\n swipeDistance > 50 ||\n swipeVelocity > 0.3 ||\n currentPosition < maxDetentValue * 0.7\n ) {\n handleClose();\n return;\n }\n }\n\n if (isAtMinDetent && detents.length > 1) {\n const nextDetentIndex = Math.min(1, detents.length - 1);\n const nextDetentValue = detents[nextDetentIndex];\n const midpoint = (minDetentValue + nextDetentValue) / 2;\n\n const shouldGoToNextDetent =\n (isSwipingUp && (Math.abs(swipeDistance) > 30 || swipeVelocity > 0.2)) ||\n currentPosition >= midpoint;\n\n if (shouldGoToNextDetent) {\n snapToDetent(nextDetentIndex);\n return;\n }\n }\n\n const shouldClose =\n enableSwipeToClose &&\n (currentPosition < minDetentValue * 0.5 ||\n (swipeDistance > 100 && swipeVelocity > 0.5) ||\n sheetHeight < viewportHeight * 0.15);\n\n if (shouldClose) {\n handleClose();\n return;\n }\n\n const nearestDetentIndex = findNearestDetent(sheetHeight);\n snapToDetent(nearestDetentIndex);\n },\n [\n isOpen,\n isDragging,\n isClosing,\n isScrolling,\n sheetHeight,\n currentY,\n currentDetent,\n detents,\n enableSwipeToClose,\n handleClose,\n findNearestDetent,\n snapToDetent,\n ]\n );\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (!isOpen || isClosing) return;\n\n mouseStartTimeRef.current = Date.now();\n setStartY(e.clientY);\n setCurrentY(e.clientY);\n\n if (contentRef.current) {\n scrollTopRef.current = contentRef.current.scrollTop;\n setIsScrolling(false);\n canDragRef.current = scrollTopRef.current === 0;\n } else {\n canDragRef.current = true;\n }\n },\n [isOpen, isClosing]\n );\n\n const handleMouseMove = useCallback(\n (e: MouseEvent) => {\n if (!isOpen || !isDragging || isClosing) return;\n\n const viewportHeight = window.innerHeight;\n const baseHeight = viewportHeight * getDetentValue(currentDetent);\n const delta = startY - e.clientY;\n const maxDetentHeight = viewportHeight * Math.max(...detents);\n const minDetentHeight = viewportHeight * Math.min(...detents);\n const isAtMaxDetent = currentDetent === detents.length - 1;\n const isAtMinDetent = currentDetent === 0;\n\n let newHeight = baseHeight + delta;\n\n if (isAtMaxDetent) {\n newHeight = Math.max(0, Math.min(maxDetentHeight, newHeight));\n } else if (isAtMinDetent) {\n newHeight = Math.max(minDetentHeight, Math.min(maxDetentHeight, newHeight));\n } else {\n newHeight = Math.max(minDetentHeight, Math.min(maxDetentHeight, newHeight));\n }\n\n setSheetHeight(newHeight);\n setCurrentY(e.clientY);\n },\n [isOpen, isDragging, startY, currentDetent, detents, getDetentValue, isClosing]\n );\n\n const handleMouseUp = useCallback(() => {\n if (!isOpen || !isDragging || isClosing) return;\n\n setIsDragging(false);\n const viewportHeight = window.innerHeight;\n const currentPosition = sheetHeight / viewportHeight;\n const minDetentValue = Math.min(...detents);\n const maxDetentValue = Math.max(...detents);\n const swipeDuration = Date.now() - mouseStartTimeRef.current;\n const swipeDistance = currentY - startY;\n const swipeVelocity = Math.abs(swipeDistance) / Math.max(swipeDuration, 1);\n const isAtMaxDetent = currentDetent === detents.length - 1;\n const isAtMinDetent = currentDetent === 0;\n const isSwipingDown = swipeDistance > 0;\n const isSwipingUp = swipeDistance < 0;\n\n if (isAtMaxDetent && isSwipingDown && enableSwipeToClose) {\n if (\n swipeDistance > 50 ||\n swipeVelocity > 0.3 ||\n currentPosition < maxDetentValue * 0.7\n ) {\n handleClose();\n return;\n }\n }\n\n if (isAtMinDetent && detents.length > 1) {\n const nextDetentIndex = Math.min(1, detents.length - 1);\n const nextDetentValue = detents[nextDetentIndex];\n const midpoint = (minDetentValue + nextDetentValue) / 2;\n\n if (isSwipingUp && (swipeDistance < -30 || swipeVelocity > 0.2)) {\n snapToDetent(nextDetentIndex);\n return;\n }\n\n if (currentPosition >= midpoint) {\n snapToDetent(nextDetentIndex);\n return;\n }\n }\n\n const shouldClose =\n enableSwipeToClose &&\n (currentPosition < minDetentValue * 0.5 ||\n (swipeDistance > 100 && swipeVelocity > 0.5) ||\n sheetHeight < viewportHeight * 0.15);\n\n if (shouldClose) {\n handleClose();\n return;\n }\n\n const nearestDetentIndex = findNearestDetent(sheetHeight);\n snapToDetent(nearestDetentIndex);\n }, [\n isOpen,\n isDragging,\n isClosing,\n sheetHeight,\n currentY,\n startY,\n currentDetent,\n detents,\n enableSwipeToClose,\n handleClose,\n findNearestDetent,\n snapToDetent,\n ]);\n\n useEffect(() => {\n if (isDragging) {\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n return () => {\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }\n }, [isDragging, handleMouseMove, handleMouseUp]);\n\n const handleTouchEndNative = useCallback(\n (e: TouchEvent) => {\n handleTouchEnd(e);\n },\n [handleTouchEnd]\n );\n\n useEffect(() => {\n const sheetElement = sheetRef.current;\n if (!sheetElement || !isOpen) return;\n\n sheetElement.addEventListener(\"touchmove\", handleTouchMoveNative, {\n passive: false,\n });\n sheetElement.addEventListener(\"touchend\", handleTouchEndNative, {\n passive: false,\n });\n\n return () => {\n sheetElement.removeEventListener(\"touchmove\", handleTouchMoveNative);\n sheetElement.removeEventListener(\"touchend\", handleTouchEndNative);\n };\n }, [isOpen, handleTouchMoveNative, handleTouchEndNative]);\n\n useEffect(() => {\n if (isOpen) {\n document.body.style.overflow = \"hidden\";\n } else {\n document.body.style.overflow = \"\";\n }\n\n return () => {\n document.body.style.overflow = \"\";\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current);\n closeTimeoutRef.current = null;\n }\n if (openTimeoutRef.current) {\n clearTimeout(openTimeoutRef.current);\n openTimeoutRef.current = null;\n }\n isClosingRef.current = false;\n };\n }, [isOpen]);\n\n if (!isOpen && !isClosing) return null;\n\n const maxHeightValue = typeof maxHeight === \"number\" ? `${maxHeight}px` : maxHeight;\n const minHeightValue = typeof minHeight === \"number\" ? `${minHeight}px` : minHeight;\n const currentHeight = `${sheetHeight}px`;\n\n const calculateBackdropOpacity = (): number => {\n if (!isOpen) return 0.5;\n const viewportHeight = window.innerHeight;\n const maxDetentHeight = viewportHeight * Math.max(...detents);\n if (maxDetentHeight === 0) return 0.5;\n const progress = Math.max(0, Math.min(1, sheetHeight / maxDetentHeight));\n return progress * 0.5;\n };\n\n const calculateBackdropBlur = (): number => {\n if (!isOpen) return 8;\n const viewportHeight = window.innerHeight;\n const maxDetentHeight = viewportHeight * Math.max(...detents);\n if (maxDetentHeight === 0) return 8;\n const progress = Math.max(0, Math.min(1, sheetHeight / maxDetentHeight));\n return progress * 8;\n };\n\n const backdropOpacity = calculateBackdropOpacity();\n const backdropBlur = calculateBackdropBlur();\n\n const backdropStyle: React.CSSProperties = {\n backgroundColor: `rgba(0, 0, 0, ${backdropOpacity})`,\n backdropFilter: `blur(${backdropBlur}px)`,\n WebkitBackdropFilter: `blur(${backdropBlur}px)`,\n ...(isDragging\n ? {}\n : {\n transition:\n \"background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), backdrop-filter 0.3s cubic-bezier(0.4, 0, 0.2, 1)\",\n }),\n };\n\n return (\n <div\n className={`bottom-sheet-backdrop ${backdropClassName} ${isClosing ? \"closing\" : \"\"}`}\n onClick={enableBackdropClose ? handleClose : undefined}\n style={backdropStyle}\n >\n <div\n ref={sheetRef}\n className={`bottom-sheet ${className} ${isDragging ? \"dragging\" : \"\"} ${isClosing ? \"closing\" : \"\"}`}\n style={{\n height: currentHeight,\n maxHeight: maxHeightValue,\n minHeight: minHeightValue,\n }}\n onClick={(e) => e.stopPropagation()}\n onTouchStart={handleTouchStart}\n onMouseDown={handleMouseDown}\n >\n <div className=\"bottom-sheet-handle-container\">\n <div\n className={`bottom-sheet-handle ${handleClassName}`}\n onClick={(e) => {\n e.stopPropagation();\n handleClose();\n }}\n />\n </div>\n <div\n ref={contentRef}\n className={`bottom-sheet-content ${contentClassName} ${isScrolling ? \"scrolling\" : \"\"}`}\n >\n {children}\n </div>\n </div>\n </div>\n );\n};\n\nexport default BottomSheet;\n","import styleInject from '#style-inject';styleInject(\".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\")","import styleInject from '#style-inject';styleInject(\".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}\\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(0, 152, 234, 0.15);\\n --pm-order-border: rgba(0, 152, 234, 0.2);\\n --pm-order-text: #7DD3FC;\\n --pm-hover-bg: rgba(255, 255, 255, 0.05);\\n --pm-iframe-bg: #111827;\\n --pm-spinner-track: #374151;\\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.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 16px 24px;\\n gap: 20px;\\n box-sizing: border-box;\\n}\\n.pm-order-info {\\n display: flex;\\n flex-direction: row;\\n justify-content: center;\\n align-items: center;\\n padding: 8px 13px;\\n gap: 10px;\\n background: var(--pm-order-bg, #E9F5FA);\\n border: 1px solid var(--pm-order-border, rgba(0, 100, 153, 0.03));\\n border-radius: 9px;\\n margin-bottom: 10px;\\n}\\n.pm-order-text {\\n font-size: 13px;\\n line-height: 16px;\\n color: var(--pm-order-text, #004062);\\n text-align: center;\\n}\\n.pm-amount-container {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 10px;\\n margin-bottom: 10px;\\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: 500;\\n font-size: 20px;\\n line-height: 24px;\\n color: var(--pm-text, #000000);\\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;\\n gap: 10px;\\n width: 100%;\\n height: 44px;\\n border-radius: 8px;\\n border: none;\\n cursor: pointer;\\n font-weight: 500;\\n font-size: 16px;\\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-footer {\\n display: flex;\\n flex-direction: row;\\n justify-content: center;\\n align-items: center;\\n gap: 8px;\\n margin-top: 10px;\\n font-size: 14px;\\n line-height: 17px;\\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-providers-list {\\n display: flex;\\n flex-direction: column;\\n width: 100%;\\n padding: 0;\\n}\\n.pm-provider-item {\\n display: flex;\\n flex-direction: row;\\n justify-content: space-between;\\n align-items: center;\\n padding: 13px 16px 13px 32px;\\n width: 100%;\\n height: 52px;\\n background: var(--pm-bg, #FFFFFF);\\n border: none;\\n border-bottom: 1px solid var(--pm-border, rgba(0, 0, 0, 0.1));\\n cursor: pointer;\\n box-sizing: border-box;\\n position: relative;\\n}\\n.pm-provider-item:hover {\\n background-color: var(--pm-hover-bg, #F9F9F9);\\n}\\n.pm-provider-item.selected {\\n background: var(--pm-hover-bg, #F9F9F9);\\n}\\n.pm-provider-left {\\n display: flex;\\n align-items: center;\\n gap: 12px;\\n}\\n.pm-provider-icon {\\n width: 32px;\\n height: 32px;\\n border-radius: 8px;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n overflow: hidden;\\n}\\n.pm-provider-name {\\n font-size: 16px;\\n color: var(--pm-text, #000000);\\n}\\n.pm-check-icon {\\n color: #0098EA;\\n opacity: 0;\\n}\\n.pm-provider-item.selected .pm-check-icon {\\n opacity: 1;\\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: 16px;\\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@keyframes pm-spin {\\n to {\\n transform: rotate(360deg);\\n }\\n}\\n\")","import * as React from \"react\";\nimport {\n createMoonpayTransfer,\n checkMoonpayGeo,\n checkMoonpayLimits,\n} from \"@ton-pay/api\";\nimport type {\n CreateMoonpayTransferParams,\n MoonpayGeoResult,\n MoonpayAmountLimits,\n} from \"@ton-pay/api\";\nimport type { UseMoonPayIframeOptions } from \"../types\";\n\ninterface MoonPayLimitsResponse {\n limits?: {\n quoteCurrency?: {\n minBuyAmount: number;\n maxBuyAmount: number;\n };\n };\n quoteCurrency?: {\n minBuyAmount: number;\n maxBuyAmount: number;\n };\n}\n\nexport function useMoonPayIframe({\n apiKey,\n chain = \"mainnet\",\n}: UseMoonPayIframeOptions) {\n const [loading, setLoading] = React.useState(false);\n const [error, setError] = React.useState<string | null>(null);\n const [link, setLink] = React.useState<string | null>(null);\n const [geoResult, setGeoResult] = React.useState<MoonpayGeoResult | null>(\n null\n );\n const [limits, setLimits] = React.useState<MoonpayAmountLimits | null>(null);\n\n const checkAvailability = React.useCallback(\n async (amount: number, asset: string, ipAddress: string): Promise<boolean> => {\n if (!apiKey) return false;\n\n setLoading(true);\n setError(null);\n\n try {\n const geo = await checkMoonpayGeo({ ipAddress }, { apiKey, chain });\n setGeoResult(geo);\n\n if (!geo.isBuyAllowed) {\n return false;\n }\n\n const limitRes = (await checkMoonpayLimits(\n { asset },\n { apiKey, chain }\n )) as MoonPayLimitsResponse;\n setLimits(limitRes as unknown as MoonpayAmountLimits);\n\n const limitsData = limitRes?.limits || limitRes;\n\n if (!limitsData?.quoteCurrency) {\n return false;\n }\n\n const { minBuyAmount, maxBuyAmount } = limitsData.quoteCurrency;\n\n if (amount < minBuyAmount || amount > maxBuyAmount) {\n return false;\n }\n\n return true;\n } catch {\n return false;\n } finally {\n setLoading(false);\n }\n },\n [apiKey, chain]\n );\n\n const fetchOnRampLink = React.useCallback(\n async (params: CreateMoonpayTransferParams): Promise<string> => {\n if (!apiKey) throw new Error(\"API Key is required\");\n\n setLoading(true);\n setError(null);\n\n try {\n const response = await createMoonpayTransfer(params, { apiKey, chain });\n setLink(response.link);\n return response.link;\n } catch (e) {\n const msg =\n e instanceof Error ? e.message : \"Failed to generate OnRamp link\";\n setError(msg);\n throw new Error(msg);\n } finally {\n setLoading(false);\n }\n },\n [apiKey, chain]\n );\n\n return {\n loading,\n error,\n link,\n fetchOnRampLink,\n checkAvailability,\n geoResult,\n limits,\n };\n}\n","export const BASE_URL = \"https://tonpay.tech\";\nexport const TESTNET_BASE_URL = \"https://testnet.tonpay.tech\";\n","import type { Chain } from \"../types/chain\";\nimport { BASE_URL, TESTNET_BASE_URL } from \"./const\";\n\nexport const getBaseUrl = (chain?: Chain) => {\n // only for testing. do not use in production. do not use in docs\n // @ts-ignore\n if (typeof process !== 'undefined' && process.env && process.env.TONPAY_BASE_URL) {\n // @ts-ignore\n return process.env.TONPAY_BASE_URL;\n }\n if (!chain || chain === \"mainnet\") {\n return BASE_URL;\n }\n return TESTNET_BASE_URL;\n};\n","import { getBaseUrl } from \"../common/get-base-url\";\nimport type { APIOptions } from \"../types/api-options\";\nimport type {\n CreateMoonpayTransferParams,\n CreateMoonpayTransferResponse,\n} from \"../types/create-moonpay-transfer\";\n\n/**\n * Creates a MoonPay payment link for buying crypto\n * @param params - the parameters for the MoonPay transfer\n * @param options - the options for the transfer (requires API key)\n * @returns the payment link, geo restrictions, and amount limits\n */\nexport const createMoonpayTransfer = async (\n params: CreateMoonpayTransferParams,\n options: APIOptions\n): Promise<CreateMoonpayTransferResponse> => {\n if (!options?.apiKey) {\n throw new Error(\"API key is required for MoonPay transfers\");\n }\n\n const baseUrl = getBaseUrl(options.chain);\n const headers = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": options.apiKey,\n };\n\n const response = await fetch(\n `${baseUrl}/api/merchant/v1/create-moonpay-transfer`,\n {\n method: \"POST\",\n body: JSON.stringify(params),\n headers,\n }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to create MoonPay transfer: ${errorText}`, {\n cause: response.statusText,\n });\n }\n\n const data = await response.json();\n\n if (data.link && data.link.startsWith(\"/\")) {\n data.link = `${baseUrl}${data.link}`;\n }\n\n return data;\n};\n\n","import { getBaseUrl } from \"../common/get-base-url\";\nimport type { APIOptions } from \"../types/api-options\";\nimport type {\n CheckMoonpayGeoParams,\n CheckMoonpayGeoResponse,\n} from \"../types/check-moonpay-geo\";\n\n/**\n * Checks MoonPay geo restrictions for an IP address\n * @param params - the IP address to check\n * @param options - optional API options\n * @returns the geo location and restrictions\n */\nexport const checkMoonpayGeo = async (\n params: CheckMoonpayGeoParams,\n options?: APIOptions\n): Promise<CheckMoonpayGeoResponse> => {\n const baseUrl = getBaseUrl(options?.chain);\n const headers = {\n \"Content-Type\": \"application/json\",\n ...(options?.apiKey ? { \"x-api-key\": options.apiKey } : {}),\n };\n\n const response = await fetch(\n `${baseUrl}/api/external/moonpay/check-geo?ipAddress=${encodeURIComponent(params.ipAddress)}`,\n {\n method: \"GET\",\n headers,\n }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to check MoonPay geo: ${errorText}`, {\n cause: response.statusText,\n });\n }\n\n return response.json();\n};\n\n","import { getBaseUrl } from \"../common/get-base-url\";\nimport type { APIOptions } from \"../types/api-options\";\nimport type {\n CheckMoonpayLimitsParams,\n CheckMoonpayLimitsResponse,\n} from \"../types/check-moonpay-limits\";\n\n/**\n * Gets MoonPay amount limits for an asset\n * @param params - the asset to check limits for\n * @param options - optional API options\n * @returns the amount limits for the asset\n */\nexport const checkMoonpayLimits = async (\n params: CheckMoonpayLimitsParams,\n options?: APIOptions\n): Promise<CheckMoonpayLimitsResponse> => {\n const baseUrl = getBaseUrl(options?.chain);\n const headers = {\n \"Content-Type\": \"application/json\",\n ...(options?.apiKey ? { \"x-api-key\": options.apiKey } : {}),\n };\n\n const response = await fetch(`${baseUrl}/api/external/moonpay/limits`, {\n method: \"POST\",\n body: JSON.stringify(params),\n headers,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to check MoonPay limits: ${errorText}`, {\n cause: response.statusText,\n });\n }\n\n return response.json();\n};\n\n","import * as CryptoJS from \"crypto-js\";\n\n/**\n * Verifies the HMAC-SHA256 signature of a payload\n * @param payload - Raw JSON string or object to verify\n * @param signature - The signature from X-TON Pay-Signature header\n * @param apiSecret - Your TON Pay webhook API secret\n * @returns true if signature is valid, false otherwise\n *\n * @example\n * ```typescript\n * import { verifySignature } from \"@ton-pay/api\";\n *\n * // With raw string\n * app.post(\"/webhook\", (req, res) => {\n * const signature = req.headers[\"x-tonpay-signature\"] as string;\n * const payload = JSON.stringify(req.body);\n *\n * if (!verifySignature(payload, signature, YOUR_API_SECRET)) {\n * return res.status(401).json({ error: \"Invalid signature\" });\n * }\n *\n * res.status(200).json({ received: true });\n * });\n *\n * // With object (will be stringified automatically)\n * app.post(\"/webhook\", (req, res) => {\n * const signature = req.headers[\"x-tonpay-signature\"] as string;\n *\n * if (!verifySignature(req.body, signature, YOUR_API_SECRET)) {\n * return res.status(401).json({ error: \"Invalid signature\" });\n * }\n *\n * res.status(200).json({ received: true });\n * });\n * ```\n */\nexport function verifySignature(\n payload: string | object,\n signature: string,\n apiSecret: string\n): boolean {\n const payloadString =\n typeof payload === \"string\" ? payload : JSON.stringify(payload);\n\n const hmac = CryptoJS.HmacSHA256(payloadString, apiSecret);\n const expectedSignature = `sha256=${hmac.toString(CryptoJS.enc.Hex)}`;\n\n return signature === expectedSignature;\n}\n","import type { TonPayButtonPresetConfig, TonPayPreset } from \"../../types\";\n\nexport const PRESETS: Record<TonPayPreset, TonPayButtonPresetConfig> = {\n default: {\n bgColor: \"#0098EA\",\n textColor: \"#FFFFFF\",\n },\n gradient: {\n bgColor: \"linear-gradient(91.69deg, #2A82EB 8.9%, #0355CF 158.29%)\",\n textColor: \"#FFFFFF\",\n },\n};\n\nexport const buttonStyles = `\n@keyframes tp-pulse{0%{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.02)}100%{opacity:1;transform:scale(1)}}\n@keyframes tp-fade-in{from{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}\n@keyframes tp-spin{to{transform:rotate(360deg)}}\n\n.tp-wrap{display:inline-flex;flex-direction:column;position:relative;width:var(--tp-width,300px);max-width:100%;--tp-menu-bg:#ffffff;--tp-menu-text:#111827;--tp-menu-muted:#6b7280;--tp-menu-hover:rgba(0,0,0,.06);--tp-menu-border:rgba(0,0,0,.08);--tp-menu-shadow:0 8px 24px rgba(0,0,0,.12)}\n@media(prefers-color-scheme:dark){.tp-wrap{--tp-menu-bg:#1C2633;--tp-menu-text:#F9FAFB;--tp-menu-muted:#9CA3AF;--tp-menu-hover:rgba(255,255,255,.08);--tp-menu-border:rgba(255,255,255,.1);--tp-menu-shadow:0 8px 32px rgba(0,0,0,.4)}}\n.tp-btn-container{display:flex;flex-direction:row;width:100%}\n.tp-btn{display:flex;flex-direction:column;justify-content:center;align-items:center;padding:13px 10px;gap:10px;flex:1;min-height:var(--tp-height,44px);background:var(--tp-bg,#0098EA);color:var(--tp-text,#fff);border:none;border-radius:var(--tp-radius,8px) 0 0 var(--tp-radius,8px);cursor:pointer;transition:filter .12s ease,transform .12s ease;font-family:var(--tp-font,inherit);font-style:normal;font-weight:500;font-size:20px;line-height:25px;text-align:center;position:relative}\n.tp-btn.with-menu{padding-left:calc(10px + (var(--tp-height,44px))/2)}\n.tp-btn.no-menu{border-radius:var(--tp-radius,8px)}\n.tp-btn-content{display:flex;flex-direction:row;align-items:center;padding:0;gap:5px;white-space:nowrap;margin-top:-4px}\n.tp-btn-content svg{margin-top:4px}\n.tp-btn:hover:not(:disabled){filter:brightness(0.92)}\n.tp-btn:active:not(:disabled){filter:brightness(0.85);transform:translateY(1px)}\n.tp-btn:disabled{cursor:not-allowed;opacity:.85}\n.tp-btn.loading{animation:none}\n\n.tp-arrow{display:flex;align-items:center;justify-content:center;padding:13px 10px;min-width:calc(var(--tp-height,44px));min-height:var(--tp-height,44px);background:var(--tp-bg,#0098EA);color:var(--tp-text,#fff);border:none;border-left:1px solid rgba(255,255,255,.2);border-radius:0 var(--tp-radius,8px) var(--tp-radius,8px) 0;cursor:pointer;transition:filter .12s ease,transform .12s ease;font-size:14px}\n.tp-arrow:hover:not(:disabled){filter:brightness(0.92)}\n.tp-arrow:active:not(:disabled){filter:brightness(0.85);transform:translateY(1px)}\n.tp-arrow:disabled{cursor:not-allowed;opacity:.85;transition:none;filter:none;transform:none}\n\n.tp-menu{position:absolute;right:0;top:calc(100% + 8px);width:256px;background:var(--tp-menu-bg);color:var(--tp-menu-text);border:1px solid var(--tp-menu-border);border-radius:var(--tp-menu-radius,16px);padding:8px;box-shadow:var(--tp-menu-shadow);z-index:1000;animation:tp-fade-in .15s ease}\n.tp-menu-arrow{position:absolute;top:-8px;right:20px;width:0;height:0;border-style:solid;border-width:0 8px 8px 8px;border-color:transparent transparent var(--tp-menu-bg) transparent;filter:drop-shadow(0 -1px 1px rgba(0,0,0,.08))}\n.tp-menu-address{padding:.5rem .75rem;font-size:.85rem;color:var(--tp-menu-muted);cursor:default;user-select:text}\n.tp-menu-item{display:flex;align-items:center;gap:8px;width:100%;height:40px;padding-left:12px;padding-right:12px;border:none;background:transparent;text-align:left;cursor:pointer;font-size:15px;font-weight:590;color:var(--tp-menu-text);transition:background-color .15s ease,transform .1s ease-in-out;border-radius:8px;margin:2px}\n.tp-menu-item:hover:not(:disabled){background:var(--tp-menu-hover)}\n.tp-menu-item:active{transform:scale(0.96)}\n.tp-menu-item.danger{color:#e74c3c}\n.tp-menu-item.danger:hover:not(:disabled){background:rgba(231,76,60,.12);color:#c0392b}\n.tp-menu-item:disabled{cursor:default;opacity:1;color:var(--tp-menu-muted)}\n.tp-menu-item:disabled:hover{background:transparent}\n.tp-menu-icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;color:currentColor}\n.tp-menu-item:disabled .tp-menu-icon{opacity:.5}\n\n.tp-spinner{border:2px solid rgba(255,255,255,.35);border-top-color:var(--tp-text,#fff);border-radius:50%;width:18px;height:18px;animation:tp-spin .6s linear infinite}\n`;\n\nlet stylesInjected = false;\n\nexport function injectStyles(): void {\n if (typeof document === \"undefined\" || stylesInjected) return;\n const style = document.createElement(\"style\");\n style.id = \"tonpay-button-styles\";\n style.textContent = buttonStyles;\n document.head.appendChild(style);\n stylesInjected = true;\n}\n\n","import * as React from \"react\";\nimport {\n useTonAddress,\n useTonConnectModal,\n useTonConnectUI,\n} from \"@tonconnect/ui-react\";\nimport type { GetMessageFn, PayInfo } from \"../types\";\n\nconst WALLET_CONNECTION_TIMEOUT = 5 * 60 * 1000;\nconst TX_VALID_DURATION = 5 * 60;\n\nexport function useTonPay() {\n const address = useTonAddress(true);\n const modal = useTonConnectModal();\n const [tonConnectUI] = useTonConnectUI();\n\n const waitForWalletConnection = React.useCallback((): Promise<string> => {\n return new Promise((resolve, reject) => {\n if (address) {\n resolve(address);\n return;\n }\n\n modal.open();\n\n const unsubscribe = tonConnectUI.onStatusChange((wallet) => {\n if (wallet?.account) {\n unsubscribe();\n unsubscribeModal();\n resolve(wallet.account.address);\n }\n });\n\n const unsubscribeModal = tonConnectUI.onModalStateChange((state) => {\n if (state.status === \"closed\") {\n unsubscribe();\n unsubscribeModal();\n reject(new Error(\"Wallet connection modal closed\"));\n }\n });\n\n setTimeout(() => {\n unsubscribe();\n unsubscribeModal();\n reject(new Error(\"Wallet connection timeout\"));\n }, WALLET_CONNECTION_TIMEOUT);\n });\n }, [address, modal, tonConnectUI]);\n\n const pay = React.useCallback(\n async <T extends object = object>(\n getMessage: GetMessageFn<T>\n ): Promise<PayInfo<T>> => {\n const walletAddress = await waitForWalletConnection();\n const validUntil = Math.floor(Date.now() / 1e3) + TX_VALID_DURATION;\n const messageResult = await getMessage(walletAddress);\n\n const txResult = await tonConnectUI.sendTransaction({\n messages: [messageResult.message],\n validUntil,\n from: walletAddress,\n });\n\n return { ...messageResult, txResult };\n },\n [waitForWalletConnection, tonConnectUI]\n );\n\n return { pay, address };\n}\n","import * as React from \"react\";\nimport { useTonAddress } from \"@tonconnect/ui-react\";\nimport type {\n SignlessConfig,\n SignlessState,\n SignlessContextValue,\n SignlessSetupParams,\n SignlessUnlockParams,\n SignlessPayloadParams,\n SignlessSignedPayload,\n} from \"./types\";\nimport {\n generateKeyPair,\n signMessage,\n encryptPrivateKey,\n decryptPrivateKey,\n isWebAuthnSupported,\n createWebAuthnCredential,\n getWebAuthnCredential,\n type WebAuthnCredentialInfo,\n} from \"./crypto\";\nimport { SignlessStorage } from \"./storage\";\n\nconst DEFAULT_CONFIG: SignlessConfig = {\n enabled: false,\n authMethod: \"none\",\n autoLockTimeout: 5 * 60 * 1000,\n storageKey: \"tonpay_signless_vault\",\n};\n\nconst DEFAULT_STATE: SignlessState = {\n status: \"disabled\",\n isEnabled: false,\n isSetup: false,\n isUnlocked: false,\n authMethod: \"none\",\n publicKey: null,\n walletAddress: null,\n};\n\nconst SignlessContext = React.createContext<SignlessContextValue | null>(null);\n\ninterface SignlessProviderProps {\n children: React.ReactNode;\n config?: Partial<SignlessConfig>;\n}\n\nexport function SignlessProvider({ children, config }: SignlessProviderProps) {\n const walletAddress = useTonAddress(true);\n const [state, setState] = React.useState<SignlessState>(DEFAULT_STATE);\n const [currentConfig, setCurrentConfig] = React.useState<SignlessConfig>({\n ...DEFAULT_CONFIG,\n ...config,\n });\n\n const storageRef = React.useRef(\n new SignlessStorage(currentConfig.storageKey)\n );\n const privateKeyRef = React.useRef<Uint8Array | null>(null);\n const lockTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null\n );\n const webauthnCredentialRef = React.useRef<WebAuthnCredentialInfo | null>(\n null\n );\n\n const [isBiometricAvailable, setIsBiometricAvailable] = React.useState(false);\n\n React.useEffect(() => {\n async function checkBiometric() {\n if (!isWebAuthnSupported()) {\n setIsBiometricAvailable(false);\n return;\n }\n try {\n const available =\n await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();\n setIsBiometricAvailable(available);\n } catch {\n setIsBiometricAvailable(false);\n }\n }\n checkBiometric();\n }, []);\n\n React.useEffect(() => {\n async function loadVaultState() {\n if (!walletAddress) {\n setState({ ...DEFAULT_STATE });\n return;\n }\n\n if (!currentConfig.enabled) {\n setState({\n ...DEFAULT_STATE,\n status: \"disabled\",\n walletAddress,\n });\n return;\n }\n\n const vaultData = await storageRef.current.loadVault(walletAddress);\n\n if (!vaultData) {\n setState({\n ...DEFAULT_STATE,\n status: \"not_setup\",\n isEnabled: true,\n walletAddress,\n });\n return;\n }\n\n webauthnCredentialRef.current = vaultData.webauthnCredential || null;\n\n setState({\n status: \"locked\",\n isEnabled: true,\n isSetup: true,\n isUnlocked: false,\n authMethod: vaultData.authMethod,\n publicKey: vaultData.vault.publicKey,\n walletAddress,\n });\n }\n\n loadVaultState();\n }, [walletAddress, currentConfig.enabled]);\n\n const resetLockTimeout = React.useCallback(() => {\n if (lockTimeoutRef.current) {\n clearTimeout(lockTimeoutRef.current);\n }\n\n if (currentConfig.autoLockTimeout && currentConfig.autoLockTimeout > 0) {\n lockTimeoutRef.current = setTimeout(() => {\n if (privateKeyRef.current) {\n privateKeyRef.current.fill(0);\n privateKeyRef.current = null;\n }\n setState((prev) => ({\n ...prev,\n status: \"locked\",\n isUnlocked: false,\n }));\n }, currentConfig.autoLockTimeout);\n }\n }, [currentConfig.autoLockTimeout]);\n\n const setup = React.useCallback(\n async (params: SignlessSetupParams) => {\n if (!walletAddress) {\n throw new Error(\"Wallet not connected\");\n }\n\n setState((prev) => ({ ...prev, status: \"setting_up\" }));\n\n try {\n const keyPair = await generateKeyPair();\n let webauthnCredential: WebAuthnCredentialInfo | undefined;\n\n if (params.authMethod === \"biometric\") {\n webauthnCredential = await createWebAuthnCredential(walletAddress);\n webauthnCredentialRef.current = webauthnCredential;\n\n const signature = await getWebAuthnCredential(webauthnCredential);\n const signatureBytes = new Uint8Array(signature);\n const biometricPin = Array.from(signatureBytes.slice(0, 32))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n const vault = await encryptPrivateKey(\n keyPair.privateKey,\n keyPair.publicKey,\n biometricPin\n );\n\n await storageRef.current.saveVault(\n walletAddress,\n vault,\n \"biometric\",\n webauthnCredential\n );\n\n privateKeyRef.current = keyPair.privateKey;\n } else if (params.authMethod === \"pin\") {\n if (!params.pin) {\n throw new Error(\"PIN is required for PIN authentication\");\n }\n\n const vault = await encryptPrivateKey(\n keyPair.privateKey,\n keyPair.publicKey,\n params.pin\n );\n\n await storageRef.current.saveVault(walletAddress, vault, \"pin\");\n\n privateKeyRef.current = keyPair.privateKey;\n } else {\n throw new Error(\"Invalid authentication method\");\n }\n\n setState({\n status: \"unlocked\",\n isEnabled: true,\n isSetup: true,\n isUnlocked: true,\n authMethod: params.authMethod,\n publicKey: arrayBufferToBase64(keyPair.publicKey.buffer),\n walletAddress,\n });\n\n resetLockTimeout();\n } catch (error) {\n setState((prev) => ({\n ...prev,\n status: prev.isSetup ? \"locked\" : \"not_setup\",\n }));\n throw error;\n }\n },\n [walletAddress, resetLockTimeout]\n );\n\n const unlock = React.useCallback(\n async (params: SignlessUnlockParams) => {\n if (!walletAddress) {\n throw new Error(\"Wallet not connected\");\n }\n\n const vaultData = await storageRef.current.loadVault(walletAddress);\n if (!vaultData) {\n throw new Error(\"No signless vault found\");\n }\n\n try {\n let pin: string;\n\n if (vaultData.authMethod === \"biometric\") {\n if (!vaultData.webauthnCredential) {\n throw new Error(\"WebAuthn credential not found\");\n }\n\n const signature = await getWebAuthnCredential(\n vaultData.webauthnCredential\n );\n const signatureBytes = new Uint8Array(signature);\n pin = Array.from(signatureBytes.slice(0, 32))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n } else if (vaultData.authMethod === \"pin\") {\n if (!params.pin) {\n throw new Error(\"PIN is required\");\n }\n pin = params.pin;\n } else {\n throw new Error(\"Invalid authentication method\");\n }\n\n const privateKey = await decryptPrivateKey(vaultData.vault, pin);\n privateKeyRef.current = privateKey;\n\n setState((prev) => ({\n ...prev,\n status: \"unlocked\",\n isUnlocked: true,\n }));\n\n resetLockTimeout();\n } catch (error) {\n throw new Error(\"Failed to unlock vault\");\n }\n },\n [walletAddress, resetLockTimeout]\n );\n\n const lock = React.useCallback(() => {\n if (lockTimeoutRef.current) {\n clearTimeout(lockTimeoutRef.current);\n }\n\n if (privateKeyRef.current) {\n privateKeyRef.current.fill(0);\n privateKeyRef.current = null;\n }\n\n setState((prev) => ({\n ...prev,\n status: \"locked\",\n isUnlocked: false,\n }));\n }, []);\n\n const reset = React.useCallback(async () => {\n if (!walletAddress) return;\n\n if (lockTimeoutRef.current) {\n clearTimeout(lockTimeoutRef.current);\n }\n\n if (privateKeyRef.current) {\n privateKeyRef.current.fill(0);\n privateKeyRef.current = null;\n }\n\n webauthnCredentialRef.current = null;\n\n await storageRef.current.deleteVault(walletAddress);\n\n setState({\n ...DEFAULT_STATE,\n status: currentConfig.enabled ? \"not_setup\" : \"disabled\",\n isEnabled: currentConfig.enabled,\n walletAddress,\n });\n }, [walletAddress, currentConfig.enabled]);\n\n const signPayload = React.useCallback(\n async (params: SignlessPayloadParams): Promise<SignlessSignedPayload> => {\n if (!privateKeyRef.current) {\n throw new Error(\"Signless is locked. Please unlock first.\");\n }\n\n if (!state.publicKey) {\n throw new Error(\"Public key not available\");\n }\n\n resetLockTimeout();\n\n const reference = params.reference || generateReference();\n const validUntil = params.validUntil || Math.floor(Date.now() / 1000) + 300;\n\n const payloadData = {\n recipient: params.recipient,\n amount: params.amount,\n token: params.token || \"TON\",\n payload: params.payload || \"\",\n reference,\n validUntil,\n };\n\n const encoder = new TextEncoder();\n const payloadBytes = encoder.encode(JSON.stringify(payloadData));\n\n const signature = await signMessage(privateKeyRef.current, payloadBytes);\n\n return {\n payload: payloadBytes,\n signature,\n publicKey: state.publicKey,\n reference,\n validUntil,\n };\n },\n [state.publicKey, resetLockTimeout]\n );\n\n const updateConfig = React.useCallback(\n (newConfig: Partial<SignlessConfig>) => {\n setCurrentConfig((prev) => ({ ...prev, ...newConfig }));\n },\n []\n );\n\n React.useEffect(() => {\n return () => {\n if (lockTimeoutRef.current) {\n clearTimeout(lockTimeoutRef.current);\n }\n if (privateKeyRef.current) {\n privateKeyRef.current.fill(0);\n privateKeyRef.current = null;\n }\n };\n }, []);\n\n const contextValue: SignlessContextValue = {\n state,\n config: currentConfig,\n setup,\n unlock,\n lock,\n reset,\n signPayload,\n updateConfig,\n isBiometricAvailable,\n };\n\n return (\n <SignlessContext.Provider value={contextValue}>\n {children}\n </SignlessContext.Provider>\n );\n}\n\nexport function useSignless(): SignlessContextValue {\n const context = React.useContext(SignlessContext);\n if (!context) {\n throw new Error(\"useSignless must be used within a SignlessProvider\");\n }\n return context;\n}\n\nfunction generateReference(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nfunction arrayBufferToBase64(buffer: ArrayBuffer | SharedArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n\n","const ALGORITHM = \"Ed25519\";\n\nexport interface KeyPair {\n publicKey: Uint8Array;\n privateKey: Uint8Array;\n}\n\nfunction arrayBufferToUint8Array(buffer: ArrayBuffer): Uint8Array {\n return new Uint8Array(buffer);\n}\n\nfunction uint8ArrayToHex(arr: Uint8Array): string {\n return Array.from(arr)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nfunction hexToUint8Array(hex: string): Uint8Array {\n const matches = hex.match(/.{1,2}/g);\n if (!matches) return new Uint8Array(0);\n return new Uint8Array(matches.map((byte) => parseInt(byte, 16)));\n}\n\nexport async function generateKeyPair(): Promise<KeyPair> {\n const keyPair = await crypto.subtle.generateKey(ALGORITHM, true, [\n \"sign\",\n \"verify\",\n ]);\n\n const privateKeyBuffer = await crypto.subtle.exportKey(\n \"pkcs8\",\n keyPair.privateKey\n );\n const publicKeyBuffer = await crypto.subtle.exportKey(\n \"spki\",\n keyPair.publicKey\n );\n\n return {\n publicKey: arrayBufferToUint8Array(publicKeyBuffer),\n privateKey: arrayBufferToUint8Array(privateKeyBuffer),\n };\n}\n\nexport async function signMessage(\n privateKey: Uint8Array,\n message: Uint8Array\n): Promise<Uint8Array> {\n const importedKey = await crypto.subtle.importKey(\n \"pkcs8\",\n privateKey as unknown as BufferSource,\n ALGORITHM,\n false,\n [\"sign\"]\n );\n\n const signature = await crypto.subtle.sign(ALGORITHM, importedKey, message as unknown as BufferSource);\n return arrayBufferToUint8Array(signature);\n}\n\nexport async function verifySignlessSignature(\n publicKey: Uint8Array,\n message: Uint8Array,\n signature: Uint8Array\n): Promise<boolean> {\n const importedKey = await crypto.subtle.importKey(\n \"spki\",\n publicKey as unknown as BufferSource,\n ALGORITHM,\n false,\n [\"verify\"]\n );\n\n return crypto.subtle.verify(ALGORITHM, importedKey, signature as unknown as BufferSource, message as unknown as BufferSource);\n}\n\nexport { uint8ArrayToHex, hexToUint8Array };\n\n\n","const PBKDF2_ITERATIONS = 100_000;\nconst SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst KEY_LENGTH = 256;\n\nexport interface EncryptedKeyVault {\n salt: string;\n iv: string;\n encryptedBlob: string;\n publicKey: string;\n version: number;\n}\n\nfunction arrayBufferToBase64(buffer: ArrayBuffer | SharedArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\nfunction base64ToArrayBuffer(base64: string): ArrayBuffer {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\nexport function generateSalt(): Uint8Array {\n return crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n}\n\nexport function generateIv(): Uint8Array {\n return crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n}\n\nexport async function deriveKeyFromPin(\n pin: string,\n salt: Uint8Array\n): Promise<CryptoKey> {\n const encoder = new TextEncoder();\n const pinData = encoder.encode(pin);\n\n const baseKey = await crypto.subtle.importKey(\n \"raw\",\n pinData as unknown as BufferSource,\n \"PBKDF2\",\n false,\n [\"deriveKey\"]\n );\n\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: salt as unknown as BufferSource,\n iterations: PBKDF2_ITERATIONS,\n hash: \"SHA-256\",\n },\n baseKey,\n { name: \"AES-GCM\", length: KEY_LENGTH },\n false,\n [\"encrypt\", \"decrypt\"]\n );\n}\n\nexport async function encryptPrivateKey(\n privateKey: Uint8Array,\n publicKey: Uint8Array,\n pin: string\n): Promise<EncryptedKeyVault> {\n const salt = generateSalt();\n const iv = generateIv();\n const derivedKey = await deriveKeyFromPin(pin, salt);\n\n const encryptedBuffer = await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv: iv as unknown as BufferSource },\n derivedKey,\n privateKey as unknown as BufferSource\n );\n\n return {\n salt: arrayBufferToBase64(salt.buffer),\n iv: arrayBufferToBase64(iv.buffer),\n encryptedBlob: arrayBufferToBase64(encryptedBuffer),\n publicKey: arrayBufferToBase64(publicKey.buffer),\n version: 1,\n };\n}\n\nexport async function decryptPrivateKey(\n vault: EncryptedKeyVault,\n pin: string\n): Promise<Uint8Array> {\n const salt = new Uint8Array(base64ToArrayBuffer(vault.salt));\n const iv = new Uint8Array(base64ToArrayBuffer(vault.iv));\n const encryptedBlob = base64ToArrayBuffer(vault.encryptedBlob);\n\n const derivedKey = await deriveKeyFromPin(pin, salt);\n\n try {\n const decryptedBuffer = await crypto.subtle.decrypt(\n { name: \"AES-GCM\", iv: iv as unknown as BufferSource },\n derivedKey,\n encryptedBlob\n );\n return new Uint8Array(decryptedBuffer);\n } catch {\n throw new Error(\"Invalid PIN or corrupted vault\");\n }\n}\n\n\n","const WEBAUTHN_RP_NAME = \"TON Pay\";\nconst WEBAUTHN_RP_ID_FALLBACK = \"tonpay.io\";\nconst STATIC_CHALLENGE = new Uint8Array([\n 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,\n 0x0e, 0x0f, 0x10,\n]);\n\nexport interface WebAuthnCredentialInfo {\n credentialId: string;\n publicKey: string;\n transports?: AuthenticatorTransport[];\n}\n\nfunction arrayBufferToBase64Url(buffer: ArrayBuffer | SharedArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\");\n}\n\nfunction base64UrlToArrayBuffer(base64Url: string): ArrayBuffer {\n const base64 = base64Url.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padding = \"=\".repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(base64 + padding);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\nexport function isWebAuthnSupported(): boolean {\n return (\n typeof window !== \"undefined\" &&\n !!window.PublicKeyCredential &&\n typeof window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable ===\n \"function\"\n );\n}\n\nexport async function isPlatformAuthenticatorAvailable(): Promise<boolean> {\n if (!isWebAuthnSupported()) return false;\n try {\n return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();\n } catch {\n return false;\n }\n}\n\nfunction getRpId(): string {\n if (typeof window === \"undefined\") return WEBAUTHN_RP_ID_FALLBACK;\n return window.location.hostname || WEBAUTHN_RP_ID_FALLBACK;\n}\n\nexport async function createWebAuthnCredential(\n walletAddress: string\n): Promise<WebAuthnCredentialInfo> {\n if (!isWebAuthnSupported()) {\n throw new Error(\"WebAuthn is not supported in this browser\");\n }\n\n const userId = new TextEncoder().encode(walletAddress);\n\n const createOptions: PublicKeyCredentialCreationOptions = {\n challenge: STATIC_CHALLENGE as unknown as BufferSource,\n rp: {\n name: WEBAUTHN_RP_NAME,\n id: getRpId(),\n },\n user: {\n id: userId,\n name: `TON Pay - ${walletAddress.slice(0, 8)}...`,\n displayName: \"TON Pay Signless\",\n },\n pubKeyCredParams: [\n { type: \"public-key\", alg: -7 },\n { type: \"public-key\", alg: -257 },\n ],\n timeout: 60000,\n authenticatorSelection: {\n authenticatorAttachment: \"platform\",\n userVerification: \"required\",\n residentKey: \"preferred\",\n },\n attestation: \"none\",\n };\n\n const credential = (await navigator.credentials.create({\n publicKey: createOptions,\n })) as PublicKeyCredential;\n\n if (!credential) {\n throw new Error(\"Failed to create WebAuthn credential\");\n }\n\n const response = credential.response as AuthenticatorAttestationResponse;\n\n return {\n credentialId: arrayBufferToBase64Url(credential.rawId),\n publicKey: arrayBufferToBase64Url(response.getPublicKey?.() ?? new ArrayBuffer(0)),\n transports: response.getTransports?.() as AuthenticatorTransport[] | undefined,\n };\n}\n\nexport async function getWebAuthnCredential(\n credentialInfo: WebAuthnCredentialInfo\n): Promise<ArrayBuffer> {\n if (!isWebAuthnSupported()) {\n throw new Error(\"WebAuthn is not supported in this browser\");\n }\n\n const credentialId = base64UrlToArrayBuffer(credentialInfo.credentialId);\n\n const getOptions: PublicKeyCredentialRequestOptions = {\n challenge: STATIC_CHALLENGE as unknown as BufferSource,\n rpId: getRpId(),\n timeout: 60000,\n userVerification: \"required\",\n allowCredentials: [\n {\n type: \"public-key\",\n id: credentialId,\n transports: credentialInfo.transports,\n },\n ],\n };\n\n const assertion = (await navigator.credentials.get({\n publicKey: getOptions,\n })) as PublicKeyCredential;\n\n if (!assertion) {\n throw new Error(\"WebAuthn authentication failed\");\n }\n\n const response = assertion.response as AuthenticatorAssertionResponse;\n return response.signature;\n}\n\nexport async function deriveKeyFromWebAuthn(\n credentialInfo: WebAuthnCredentialInfo,\n salt: Uint8Array\n): Promise<CryptoKey> {\n const signature = await getWebAuthnCredential(credentialInfo);\n const signatureBytes = new Uint8Array(signature);\n\n const baseKey = await crypto.subtle.importKey(\n \"raw\",\n signatureBytes as unknown as BufferSource,\n \"PBKDF2\",\n false,\n [\"deriveKey\"]\n );\n\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: salt as unknown as BufferSource,\n iterations: 100_000,\n hash: \"SHA-256\",\n },\n baseKey,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"]\n );\n}\n\n\n","import type { SignlessVaultData, SignlessAuthMethod } from \"./types\";\nimport type { EncryptedKeyVault, WebAuthnCredentialInfo } from \"./crypto\";\n\nconst DEFAULT_STORAGE_KEY = \"tonpay_signless_vault\";\n\nexport class SignlessStorage {\n private storageKey: string;\n\n constructor(storageKey: string = DEFAULT_STORAGE_KEY) {\n this.storageKey = storageKey;\n }\n\n private getStorage(): Storage | null {\n if (typeof window === \"undefined\") return null;\n return window.localStorage;\n }\n\n async saveVault(\n walletAddress: string,\n vault: EncryptedKeyVault,\n authMethod: SignlessAuthMethod,\n webauthnCredential?: WebAuthnCredentialInfo\n ): Promise<void> {\n const storage = this.getStorage();\n if (!storage) return;\n\n const data: SignlessVaultData = {\n vault,\n authMethod,\n walletAddress,\n webauthnCredential,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n const key = this.getStorageKeyForWallet(walletAddress);\n storage.setItem(key, JSON.stringify(data));\n }\n\n async loadVault(walletAddress: string): Promise<SignlessVaultData | null> {\n const storage = this.getStorage();\n if (!storage) return null;\n\n const key = this.getStorageKeyForWallet(walletAddress);\n const data = storage.getItem(key);\n\n if (!data) return null;\n\n try {\n return JSON.parse(data) as SignlessVaultData;\n } catch {\n return null;\n }\n }\n\n async deleteVault(walletAddress: string): Promise<void> {\n const storage = this.getStorage();\n if (!storage) return;\n\n const key = this.getStorageKeyForWallet(walletAddress);\n storage.removeItem(key);\n }\n\n async hasVault(walletAddress: string): Promise<boolean> {\n const vault = await this.loadVault(walletAddress);\n return vault !== null;\n }\n\n async updateVaultTimestamp(walletAddress: string): Promise<void> {\n const storage = this.getStorage();\n if (!storage) return;\n\n const vault = await this.loadVault(walletAddress);\n if (!vault) return;\n\n vault.updatedAt = Date.now();\n const key = this.getStorageKeyForWallet(walletAddress);\n storage.setItem(key, JSON.stringify(vault));\n }\n\n async getAllWalletsWithVaults(): Promise<string[]> {\n const storage = this.getStorage();\n if (!storage) return [];\n\n const wallets: string[] = [];\n const prefix = `${this.storageKey}_`;\n\n for (let i = 0; i < storage.length; i++) {\n const key = storage.key(i);\n if (key?.startsWith(prefix)) {\n const walletAddress = key.slice(prefix.length);\n wallets.push(walletAddress);\n }\n }\n\n return wallets;\n }\n\n private getStorageKeyForWallet(walletAddress: string): string {\n return `${this.storageKey}_${walletAddress}`;\n }\n}\n\nexport const signlessStorage = new SignlessStorage();\n\n\n","import * as React from \"react\";\nimport { useTonPay } from \"../../hooks/useTonPay\";\nimport { useSignless } from \"../context\";\nimport type {\n SignlessSetupParams,\n SignlessUnlockParams,\n SignlessPayloadParams,\n SignlessSignedPayload,\n SignlessState,\n SignlessConfig,\n} from \"../types\";\nimport type { GetMessageFn, PayInfo } from \"../../types\";\n\nexport interface UseTonPaySignlessResult {\n pay: <T extends object = object>(\n getMessage: GetMessageFn<T>\n ) => Promise<PayInfo<T>>;\n paySignless: (\n params: SignlessPayloadParams\n ) => Promise<SignlessSignedPayload>;\n address: string;\n signless: {\n state: SignlessState;\n config: SignlessConfig;\n setup: (params: SignlessSetupParams) => Promise<void>;\n unlock: (params: SignlessUnlockParams) => Promise<void>;\n lock: () => void;\n reset: () => Promise<void>;\n updateConfig: (config: Partial<SignlessConfig>) => void;\n isBiometricAvailable: boolean;\n isEnabled: boolean;\n isSetup: boolean;\n isUnlocked: boolean;\n requiresUnlock: boolean;\n };\n}\n\nexport function useTonPaySignless(): UseTonPaySignlessResult {\n const { pay, address } = useTonPay();\n const signlessContext = useSignless();\n\n const {\n state,\n config,\n setup,\n unlock,\n lock,\n reset,\n signPayload,\n updateConfig,\n isBiometricAvailable,\n } = signlessContext;\n\n const paySignless = React.useCallback(\n async (params: SignlessPayloadParams): Promise<SignlessSignedPayload> => {\n if (!config.enabled) {\n throw new Error(\"Signless is not enabled\");\n }\n\n if (!state.isSetup) {\n throw new Error(\"Signless is not set up. Please complete setup first.\");\n }\n\n if (!state.isUnlocked) {\n throw new Error(\"Signless is locked. Please unlock first.\");\n }\n\n return signPayload(params);\n },\n [config.enabled, state.isSetup, state.isUnlocked, signPayload]\n );\n\n const requiresUnlock = React.useMemo(() => {\n return config.enabled && state.isSetup && !state.isUnlocked;\n }, [config.enabled, state.isSetup, state.isUnlocked]);\n\n return {\n pay,\n paySignless,\n address,\n signless: {\n state,\n config,\n setup,\n unlock,\n lock,\n reset,\n updateConfig,\n isBiometricAvailable,\n isEnabled: config.enabled,\n isSetup: state.isSetup,\n isUnlocked: state.isUnlocked,\n requiresUnlock,\n },\n };\n}\n\n\n","import * as React from \"react\";\nimport { useSignless } from \"../context\";\n\nexport type SignlessModalType = \"setup\" | \"unlock\" | null;\n\nexport interface UseSignlessModalResult {\n modalType: SignlessModalType;\n isOpen: boolean;\n openSetup: () => void;\n openUnlock: () => void;\n close: () => void;\n onSetupComplete: () => void;\n onUnlockComplete: () => void;\n}\n\nexport function useSignlessModal(): UseSignlessModalResult {\n const { state, config } = useSignless();\n const [modalType, setModalType] = React.useState<SignlessModalType>(null);\n\n const openSetup = React.useCallback(() => {\n if (!config.enabled) {\n console.warn(\"Signless is not enabled\");\n return;\n }\n setModalType(\"setup\");\n }, [config.enabled]);\n\n const openUnlock = React.useCallback(() => {\n if (!config.enabled) {\n console.warn(\"Signless is not enabled\");\n return;\n }\n if (!state.isSetup) {\n console.warn(\"Signless is not set up\");\n return;\n }\n setModalType(\"unlock\");\n }, [config.enabled, state.isSetup]);\n\n const close = React.useCallback(() => {\n setModalType(null);\n }, []);\n\n const onSetupComplete = React.useCallback(() => {\n setModalType(null);\n }, []);\n\n const onUnlockComplete = React.useCallback(() => {\n setModalType(null);\n }, []);\n\n return {\n modalType,\n isOpen: modalType !== null,\n openSetup,\n openUnlock,\n close,\n onSetupComplete,\n onUnlockComplete,\n };\n}\n\n\n","import * as React from \"react\";\nimport type { PinInputProps } from \"../types\";\nimport { pinInputStyles } from \"./styles\";\n\nconst PIN_LENGTH = 6;\n\nexport const PinInput: React.FC<PinInputProps> = ({\n length = PIN_LENGTH,\n onComplete,\n onCancel,\n title = \"Enter PIN\",\n subtitle,\n error,\n isLoading = false,\n showBiometric = false,\n onBiometricPress,\n}) => {\n const [pin, setPin] = React.useState<string>(\"\");\n const [shake, setShake] = React.useState(false);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n if (error) {\n setShake(true);\n setPin(\"\");\n const timer = setTimeout(() => setShake(false), 500);\n return () => clearTimeout(timer);\n }\n }, [error]);\n\n React.useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value.replace(/\\D/g, \"\").slice(0, length);\n setPin(value);\n\n if (value.length === length) {\n onComplete(value);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Escape\" && onCancel) {\n onCancel();\n }\n };\n\n const handleDotClick = () => {\n inputRef.current?.focus();\n };\n\n const handleKeyPress = (digit: string) => {\n if (pin.length >= length || isLoading) return;\n\n const newPin = pin + digit;\n setPin(newPin);\n\n if (newPin.length === length) {\n onComplete(newPin);\n }\n };\n\n const handleBackspace = () => {\n if (isLoading) return;\n setPin((prev) => prev.slice(0, -1));\n };\n\n return (\n <div style={pinInputStyles.container}>\n <style>{keyframes}</style>\n\n <div style={pinInputStyles.header}>\n <h2 style={pinInputStyles.title}>{title}</h2>\n {subtitle && <p style={pinInputStyles.subtitle}>{subtitle}</p>}\n </div>\n\n <input\n ref={inputRef}\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n value={pin}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n maxLength={length}\n autoComplete=\"off\"\n style={pinInputStyles.hiddenInput}\n disabled={isLoading}\n />\n\n <div\n style={{\n ...pinInputStyles.dotsContainer,\n ...(shake ? pinInputStyles.dotsContainerShake : {}),\n }}\n onClick={handleDotClick}\n >\n {Array.from({ length }, (_, i) => (\n <div\n key={i}\n style={{\n ...pinInputStyles.dot,\n ...(i < pin.length ? pinInputStyles.dotFilled : {}),\n ...(isLoading ? pinInputStyles.dotLoading : {}),\n }}\n />\n ))}\n </div>\n\n {error && <p style={pinInputStyles.error}>{error}</p>}\n\n <div style={pinInputStyles.keypad}>\n {[1, 2, 3, 4, 5, 6, 7, 8, 9].map((digit) => (\n <button\n key={digit}\n type=\"button\"\n style={pinInputStyles.keypadButton}\n onClick={() => handleKeyPress(String(digit))}\n disabled={isLoading}\n onMouseEnter={(e) => {\n (e.target as HTMLButtonElement).style.backgroundColor =\n \"rgba(255, 255, 255, 0.1)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLButtonElement).style.backgroundColor =\n \"transparent\";\n }}\n >\n {digit}\n </button>\n ))}\n\n <div style={pinInputStyles.keypadButtonEmpty}>\n {showBiometric && onBiometricPress && (\n <button\n type=\"button\"\n style={pinInputStyles.biometricButton}\n onClick={onBiometricPress}\n disabled={isLoading}\n aria-label=\"Use biometric authentication\"\n >\n <BiometricIcon />\n </button>\n )}\n </div>\n\n <button\n type=\"button\"\n style={pinInputStyles.keypadButton}\n onClick={() => handleKeyPress(\"0\")}\n disabled={isLoading}\n onMouseEnter={(e) => {\n (e.target as HTMLButtonElement).style.backgroundColor =\n \"rgba(255, 255, 255, 0.1)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLButtonElement).style.backgroundColor =\n \"transparent\";\n }}\n >\n 0\n </button>\n\n <button\n type=\"button\"\n style={pinInputStyles.backspaceButton}\n onClick={handleBackspace}\n disabled={isLoading || pin.length === 0}\n aria-label=\"Backspace\"\n >\n <BackspaceIcon />\n </button>\n </div>\n\n {onCancel && (\n <button\n type=\"button\"\n style={pinInputStyles.cancelButton}\n onClick={onCancel}\n disabled={isLoading}\n >\n Cancel\n </button>\n )}\n </div>\n );\n};\n\nconst BiometricIcon: React.FC = () => (\n <svg\n width=\"28\"\n height=\"28\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n 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\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n 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\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nconst BackspaceIcon: React.FC = () => (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n 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\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14 10L10 14M10 10L14 14\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nconst keyframes = `\n @keyframes tonpay-pin-shake {\n 0%, 100% { transform: translateX(0); }\n 10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }\n 20%, 40%, 60%, 80% { transform: translateX(4px); }\n }\n @keyframes tonpay-pin-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n`;\n\nexport default PinInput;\n\n\n","import type { CSSProperties } from \"react\";\n\nexport const pinInputStyles: Record<string, CSSProperties> = {\n container: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n padding: \"24px\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n color: \"#ffffff\",\n minWidth: \"280px\",\n },\n header: {\n textAlign: \"center\" as const,\n marginBottom: \"32px\",\n },\n title: {\n fontSize: \"20px\",\n fontWeight: 600,\n margin: \"0 0 8px 0\",\n color: \"#ffffff\",\n },\n subtitle: {\n fontSize: \"14px\",\n color: \"rgba(255, 255, 255, 0.6)\",\n margin: 0,\n },\n hiddenInput: {\n position: \"absolute\" as const,\n opacity: 0,\n pointerEvents: \"none\" as const,\n },\n dotsContainer: {\n display: \"flex\",\n gap: \"16px\",\n marginBottom: \"32px\",\n cursor: \"pointer\",\n },\n dotsContainerShake: {\n animation: \"tonpay-pin-shake 0.5s ease-in-out\",\n },\n dot: {\n width: \"14px\",\n height: \"14px\",\n borderRadius: \"50%\",\n backgroundColor: \"rgba(255, 255, 255, 0.2)\",\n border: \"2px solid rgba(255, 255, 255, 0.3)\",\n transition: \"all 0.15s ease\",\n },\n dotFilled: {\n backgroundColor: \"#0098EA\",\n borderColor: \"#0098EA\",\n transform: \"scale(1.1)\",\n },\n dotLoading: {\n animation: \"tonpay-pin-pulse 1s ease-in-out infinite\",\n },\n error: {\n fontSize: \"14px\",\n color: \"#FF5252\",\n margin: \"-16px 0 24px 0\",\n textAlign: \"center\" as const,\n },\n keypad: {\n display: \"grid\",\n gridTemplateColumns: \"repeat(3, 1fr)\",\n gap: \"8px\",\n width: \"100%\",\n maxWidth: \"260px\",\n },\n keypadButton: {\n width: \"72px\",\n height: \"56px\",\n fontSize: \"24px\",\n fontWeight: 500,\n color: \"#ffffff\",\n backgroundColor: \"transparent\",\n border: \"none\",\n borderRadius: \"12px\",\n cursor: \"pointer\",\n transition: \"background-color 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n keypadButtonEmpty: {\n width: \"72px\",\n height: \"56px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n biometricButton: {\n width: \"56px\",\n height: \"56px\",\n fontSize: \"24px\",\n color: \"#0098EA\",\n backgroundColor: \"transparent\",\n border: \"none\",\n borderRadius: \"12px\",\n cursor: \"pointer\",\n transition: \"background-color 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n backspaceButton: {\n width: \"72px\",\n height: \"56px\",\n fontSize: \"24px\",\n color: \"rgba(255, 255, 255, 0.6)\",\n backgroundColor: \"transparent\",\n border: \"none\",\n borderRadius: \"12px\",\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n cancelButton: {\n marginTop: \"24px\",\n padding: \"12px 32px\",\n fontSize: \"16px\",\n fontWeight: 500,\n color: \"rgba(255, 255, 255, 0.6)\",\n backgroundColor: \"transparent\",\n border: \"none\",\n borderRadius: \"8px\",\n cursor: \"pointer\",\n transition: \"color 0.15s ease\",\n },\n};\n\nexport const setupModalStyles: Record<string, CSSProperties> = {\n container: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n padding: \"24px\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n color: \"#ffffff\",\n },\n header: {\n textAlign: \"center\" as const,\n marginBottom: \"24px\",\n },\n title: {\n fontSize: \"22px\",\n fontWeight: 600,\n margin: \"0 0 8px 0\",\n color: \"#ffffff\",\n },\n subtitle: {\n fontSize: \"14px\",\n color: \"rgba(255, 255, 255, 0.6)\",\n margin: 0,\n lineHeight: 1.5,\n maxWidth: \"280px\",\n },\n methodSelector: {\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"12px\",\n width: \"100%\",\n marginBottom: \"24px\",\n },\n methodButton: {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"16px\",\n padding: \"16px\",\n backgroundColor: \"rgba(255, 255, 255, 0.05)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: \"12px\",\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n textAlign: \"left\" as const,\n width: \"100%\",\n },\n methodButtonSelected: {\n backgroundColor: \"rgba(0, 152, 234, 0.15)\",\n borderColor: \"#0098EA\",\n },\n methodIcon: {\n width: \"48px\",\n height: \"48px\",\n borderRadius: \"12px\",\n backgroundColor: \"rgba(255, 255, 255, 0.1)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#0098EA\",\n flexShrink: 0,\n },\n methodContent: {\n flex: 1,\n minWidth: 0,\n },\n methodTitle: {\n fontSize: \"16px\",\n fontWeight: 600,\n color: \"#ffffff\",\n margin: \"0 0 4px 0\",\n },\n methodDescription: {\n fontSize: \"13px\",\n color: \"rgba(255, 255, 255, 0.5)\",\n margin: 0,\n lineHeight: 1.4,\n },\n continueButton: {\n width: \"100%\",\n padding: \"14px 24px\",\n fontSize: \"16px\",\n fontWeight: 600,\n color: \"#ffffff\",\n backgroundColor: \"#0098EA\",\n border: \"none\",\n borderRadius: \"12px\",\n cursor: \"pointer\",\n transition: \"opacity 0.15s ease\",\n },\n continueButtonDisabled: {\n opacity: 0.5,\n cursor: \"not-allowed\" as const,\n },\n stepIndicator: {\n display: \"flex\",\n gap: \"8px\",\n marginBottom: \"24px\",\n },\n stepDot: {\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"rgba(255, 255, 255, 0.2)\",\n },\n stepDotActive: {\n backgroundColor: \"#0098EA\",\n },\n};\n\nexport const unlockModalStyles: Record<string, CSSProperties> = {\n container: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n padding: \"24px\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n color: \"#ffffff\",\n },\n biometricPrompt: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n padding: \"32px\",\n textAlign: \"center\" as const,\n },\n biometricIcon: {\n width: \"80px\",\n height: \"80px\",\n borderRadius: \"20px\",\n backgroundColor: \"rgba(0, 152, 234, 0.15)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#0098EA\",\n marginBottom: \"24px\",\n },\n biometricTitle: {\n fontSize: \"20px\",\n fontWeight: 600,\n margin: \"0 0 8px 0\",\n color: \"#ffffff\",\n },\n biometricSubtitle: {\n fontSize: \"14px\",\n color: \"rgba(255, 255, 255, 0.6)\",\n margin: \"0 0 24px 0\",\n },\n usePinButton: {\n padding: \"12px 24px\",\n fontSize: \"14px\",\n fontWeight: 500,\n color: \"#0098EA\",\n backgroundColor: \"transparent\",\n border: \"none\",\n cursor: \"pointer\",\n transition: \"opacity 0.15s ease\",\n },\n};\n\n\n","import * as React from \"react\";\nimport type { SignlessSetupModalProps, SignlessAuthMethod } from \"../types\";\nimport { useSignless } from \"../context\";\nimport { PinInput } from \"./PinInput\";\nimport { setupModalStyles } from \"./styles\";\n\ntype SetupStep = \"select_method\" | \"create_pin\" | \"confirm_pin\" | \"biometric\";\n\nexport const SignlessSetupModal: React.FC<SignlessSetupModalProps> = ({\n isOpen,\n onClose,\n onComplete,\n showBiometric = true,\n}) => {\n const { setup, isBiometricAvailable, state } = useSignless();\n const [step, setStep] = React.useState<SetupStep>(\"select_method\");\n const [selectedMethod, setSelectedMethod] =\n React.useState<SignlessAuthMethod | null>(null);\n const [pin, setPin] = React.useState(\"\");\n const [error, setError] = React.useState<string | null>(null);\n const [isLoading, setIsLoading] = React.useState(false);\n\n React.useEffect(() => {\n if (isOpen) {\n setStep(\"select_method\");\n setSelectedMethod(null);\n setPin(\"\");\n setError(null);\n setIsLoading(false);\n }\n }, [isOpen]);\n\n const handleMethodSelect = (method: SignlessAuthMethod) => {\n setSelectedMethod(method);\n };\n\n const handleContinue = async () => {\n if (!selectedMethod) return;\n\n if (selectedMethod === \"biometric\") {\n setIsLoading(true);\n setError(null);\n\n try {\n await setup({ authMethod: \"biometric\" });\n onComplete();\n onClose();\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Biometric setup failed\"\n );\n } finally {\n setIsLoading(false);\n }\n } else if (selectedMethod === \"pin\") {\n setStep(\"create_pin\");\n }\n };\n\n const handlePinCreate = (newPin: string) => {\n setPin(newPin);\n setError(null);\n setStep(\"confirm_pin\");\n };\n\n const handlePinConfirm = async (confirmPin: string) => {\n if (confirmPin !== pin) {\n setError(\"PINs do not match. Please try again.\");\n setStep(\"create_pin\");\n setPin(\"\");\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await setup({ authMethod: \"pin\", pin });\n onComplete();\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Setup failed\");\n setStep(\"create_pin\");\n setPin(\"\");\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleBack = () => {\n if (step === \"confirm_pin\") {\n setStep(\"create_pin\");\n setError(null);\n } else if (step === \"create_pin\") {\n setStep(\"select_method\");\n setPin(\"\");\n setError(null);\n }\n };\n\n if (!isOpen) return null;\n\n const renderStepIndicator = () => {\n const steps = selectedMethod === \"pin\" ? 3 : 2;\n const currentStep =\n step === \"select_method\" ? 1 : step === \"create_pin\" ? 2 : 3;\n\n return (\n <div style={setupModalStyles.stepIndicator}>\n {Array.from({ length: steps }, (_, i) => (\n <div\n key={i}\n style={{\n ...setupModalStyles.stepDot,\n ...(i < currentStep ? setupModalStyles.stepDotActive : {}),\n }}\n />\n ))}\n </div>\n );\n };\n\n const renderMethodSelection = () => (\n <>\n <div style={setupModalStyles.header}>\n <h2 style={setupModalStyles.title}>Setup Signless</h2>\n <p style={setupModalStyles.subtitle}>\n Enable fast payments without wallet confirmations. Choose your\n preferred authentication method.\n </p>\n </div>\n\n {renderStepIndicator()}\n\n <div style={setupModalStyles.methodSelector}>\n {showBiometric && isBiometricAvailable && (\n <button\n type=\"button\"\n style={{\n ...setupModalStyles.methodButton,\n ...(selectedMethod === \"biometric\"\n ? setupModalStyles.methodButtonSelected\n : {}),\n }}\n onClick={() => handleMethodSelect(\"biometric\")}\n >\n <div style={setupModalStyles.methodIcon}>\n <FaceIdIcon />\n </div>\n <div style={setupModalStyles.methodContent}>\n <h3 style={setupModalStyles.methodTitle}>Face ID / Touch ID</h3>\n <p style={setupModalStyles.methodDescription}>\n Use biometric authentication for quick and secure access\n </p>\n </div>\n </button>\n )}\n\n <button\n type=\"button\"\n style={{\n ...setupModalStyles.methodButton,\n ...(selectedMethod === \"pin\"\n ? setupModalStyles.methodButtonSelected\n : {}),\n }}\n onClick={() => handleMethodSelect(\"pin\")}\n >\n <div style={setupModalStyles.methodIcon}>\n <PinIcon />\n </div>\n <div style={setupModalStyles.methodContent}>\n <h3 style={setupModalStyles.methodTitle}>PIN Code</h3>\n <p style={setupModalStyles.methodDescription}>\n Create a 6-digit PIN for payment authorization\n </p>\n </div>\n </button>\n </div>\n\n {error && (\n <p style={{ color: \"#FF5252\", fontSize: \"14px\", marginBottom: \"16px\" }}>\n {error}\n </p>\n )}\n\n <button\n type=\"button\"\n style={{\n ...setupModalStyles.continueButton,\n ...(!selectedMethod ? setupModalStyles.continueButtonDisabled : {}),\n }}\n onClick={handleContinue}\n disabled={!selectedMethod || isLoading}\n >\n {isLoading ? \"Setting up...\" : \"Continue\"}\n </button>\n </>\n );\n\n const renderPinCreation = () => (\n <>\n {renderStepIndicator()}\n <PinInput\n title=\"Create PIN\"\n subtitle=\"Enter a 6-digit PIN to secure your signless payments\"\n onComplete={handlePinCreate}\n onCancel={handleBack}\n error={error}\n isLoading={isLoading}\n />\n </>\n );\n\n const renderPinConfirmation = () => (\n <>\n {renderStepIndicator()}\n <PinInput\n title=\"Confirm PIN\"\n subtitle=\"Re-enter your PIN to confirm\"\n onComplete={handlePinConfirm}\n onCancel={handleBack}\n error={error}\n isLoading={isLoading}\n />\n </>\n );\n\n return (\n <div style={setupModalStyles.container}>\n {step === \"select_method\" && renderMethodSelection()}\n {step === \"create_pin\" && renderPinCreation()}\n {step === \"confirm_pin\" && renderPinConfirmation()}\n </div>\n );\n};\n\nconst FaceIdIcon: React.FC = () => (\n <svg\n width=\"28\"\n height=\"28\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n 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\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n 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\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nconst PinIcon: React.FC = () => (\n <svg\n width=\"28\"\n height=\"28\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <rect\n x=\"3\"\n y=\"6\"\n width=\"18\"\n height=\"12\"\n rx=\"2\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <circle cx=\"7\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"17\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n);\n\nexport default SignlessSetupModal;\n\n\n","import * as React from \"react\";\nimport type { SignlessUnlockModalProps } from \"../types\";\nimport { useSignless } from \"../context\";\nimport { PinInput } from \"./PinInput\";\nimport { unlockModalStyles } from \"./styles\";\n\ntype UnlockView = \"biometric\" | \"pin\";\n\nexport const SignlessUnlockModal: React.FC<SignlessUnlockModalProps> = ({\n isOpen,\n onClose,\n onUnlock,\n showBiometric = true,\n}) => {\n const { unlock, state, isBiometricAvailable } = useSignless();\n const [view, setView] = React.useState<UnlockView>(\"biometric\");\n const [error, setError] = React.useState<string | null>(null);\n const [isLoading, setIsLoading] = React.useState(false);\n\n const shouldShowBiometric =\n showBiometric &&\n isBiometricAvailable &&\n state.authMethod === \"biometric\";\n\n React.useEffect(() => {\n if (isOpen) {\n setError(null);\n setIsLoading(false);\n setView(shouldShowBiometric ? \"biometric\" : \"pin\");\n }\n }, [isOpen, shouldShowBiometric]);\n\n React.useEffect(() => {\n if (isOpen && view === \"biometric\" && shouldShowBiometric) {\n handleBiometricAuth();\n }\n }, [isOpen, view]);\n\n const handleBiometricAuth = async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n await unlock({});\n onUnlock();\n onClose();\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : \"Biometric authentication failed\"\n );\n setView(\"pin\");\n } finally {\n setIsLoading(false);\n }\n };\n\n const handlePinSubmit = async (pin: string) => {\n setIsLoading(true);\n setError(null);\n\n try {\n await unlock({ pin });\n onUnlock();\n onClose();\n } catch (err) {\n setError(\"Invalid PIN. Please try again.\");\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleUsePinInstead = () => {\n setView(\"pin\");\n setError(null);\n };\n\n if (!isOpen) return null;\n\n const renderBiometricPrompt = () => (\n <div style={unlockModalStyles.biometricPrompt}>\n <div style={unlockModalStyles.biometricIcon}>\n <BiometricLargeIcon />\n </div>\n <h2 style={unlockModalStyles.biometricTitle}>Unlock Signless</h2>\n <p style={unlockModalStyles.biometricSubtitle}>\n {isLoading\n ? \"Authenticating...\"\n : \"Use Face ID or Touch ID to continue\"}\n </p>\n\n {error && (\n <p style={{ color: \"#FF5252\", fontSize: \"14px\", marginBottom: \"16px\" }}>\n {error}\n </p>\n )}\n\n {!isLoading && (\n <>\n <button\n type=\"button\"\n style={{\n padding: \"14px 32px\",\n fontSize: \"16px\",\n fontWeight: 600,\n color: \"#ffffff\",\n backgroundColor: \"#0098EA\",\n border: \"none\",\n borderRadius: \"12px\",\n cursor: \"pointer\",\n marginBottom: \"16px\",\n }}\n onClick={handleBiometricAuth}\n >\n Try Again\n </button>\n\n {state.authMethod === \"biometric\" && (\n <button\n type=\"button\"\n style={unlockModalStyles.usePinButton}\n onClick={handleUsePinInstead}\n >\n Use PIN instead\n </button>\n )}\n </>\n )}\n </div>\n );\n\n const renderPinInput = () => (\n <PinInput\n title=\"Enter PIN\"\n subtitle=\"Enter your PIN to unlock signless payments\"\n onComplete={handlePinSubmit}\n onCancel={onClose}\n error={error}\n isLoading={isLoading}\n showBiometric={shouldShowBiometric}\n onBiometricPress={() => {\n setView(\"biometric\");\n setError(null);\n }}\n />\n );\n\n return (\n <div style={unlockModalStyles.container}>\n {view === \"biometric\" && shouldShowBiometric\n ? renderBiometricPrompt()\n : renderPinInput()}\n </div>\n );\n};\n\nconst BiometricLargeIcon: React.FC = () => (\n <svg\n width=\"48\"\n height=\"48\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n 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\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n 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\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport default SignlessUnlockModal;\n\n\n"]}