recur-tw 0.9.13 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/checkout.js +126 -0
- package/dist/recur.umd.js +1 -1
- package/dist/widget.js +132 -0
- package/package.json +4 -2
package/dist/checkout.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";var RecurCheckoutScript=(()=>{var f=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var R=(e,t)=>{for(var r in t)f(e,r,{get:t[r],enumerable:!0})},U=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of E(t))!C.call(e,n)&&n!==r&&f(e,n,{get:()=>t[n],enumerable:!(o=v(t,n))||o.enumerable});return e};var _=e=>U(f({},"__esModule",{value:!0}),e);var T={};R(T,{default:()=>I});var s={embedUrl:"https://embed.recur.tw",apiUrl:"https://api.recur.tw"},d=null,g=null;function m(){if(document.getElementById("recur-checkout-styles"))return;let e=document.createElement("style");e.id="recur-checkout-styles",e.textContent=`
|
|
2
|
+
.recur-checkout-dialog {
|
|
3
|
+
border: none;
|
|
4
|
+
border-radius: 12px;
|
|
5
|
+
padding: 0;
|
|
6
|
+
width: 90%;
|
|
7
|
+
max-width: 480px;
|
|
8
|
+
max-height: 90vh;
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
background: white;
|
|
11
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
12
|
+
position: fixed;
|
|
13
|
+
inset: 0;
|
|
14
|
+
margin: auto;
|
|
15
|
+
height: fit-content;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.recur-checkout-dialog::backdrop {
|
|
19
|
+
background: rgba(0, 0, 0, 0.6);
|
|
20
|
+
backdrop-filter: blur(4px);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.recur-checkout-dialog[open] {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
animation: recur-dialog-open 0.2s ease-out;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@keyframes recur-dialog-open {
|
|
30
|
+
from {
|
|
31
|
+
opacity: 0;
|
|
32
|
+
transform: scale(0.95);
|
|
33
|
+
}
|
|
34
|
+
to {
|
|
35
|
+
opacity: 1;
|
|
36
|
+
transform: scale(1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.recur-checkout-dialog__header {
|
|
41
|
+
display: flex;
|
|
42
|
+
justify-content: flex-end;
|
|
43
|
+
padding: 12px 12px 0 12px;
|
|
44
|
+
background: white;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.recur-checkout-dialog__close {
|
|
48
|
+
width: 32px;
|
|
49
|
+
height: 32px;
|
|
50
|
+
border: none;
|
|
51
|
+
background: rgba(0, 0, 0, 0.05);
|
|
52
|
+
border-radius: 50%;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
font-size: 18px;
|
|
55
|
+
color: #666;
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
transition: background 0.2s;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.recur-checkout-dialog__close:hover {
|
|
63
|
+
background: rgba(0, 0, 0, 0.1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.recur-checkout-dialog__iframe {
|
|
67
|
+
width: 100%;
|
|
68
|
+
height: 600px;
|
|
69
|
+
max-height: calc(90vh - 56px);
|
|
70
|
+
border: none;
|
|
71
|
+
display: block;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.recur-checkout-dialog__loading {
|
|
75
|
+
display: flex;
|
|
76
|
+
align-items: center;
|
|
77
|
+
justify-content: center;
|
|
78
|
+
height: 400px;
|
|
79
|
+
color: #666;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.recur-checkout-dialog__spinner {
|
|
83
|
+
width: 32px;
|
|
84
|
+
height: 32px;
|
|
85
|
+
border: 3px solid #e5e7eb;
|
|
86
|
+
border-top-color: #3b82f6;
|
|
87
|
+
border-radius: 50%;
|
|
88
|
+
animation: recur-spin 0.8s linear infinite;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@keyframes recur-spin {
|
|
92
|
+
to { transform: rotate(360deg); }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Button styling (optional, can be overridden) */
|
|
96
|
+
.recur-button {
|
|
97
|
+
display: inline-flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
padding: 12px 24px;
|
|
101
|
+
font-size: 16px;
|
|
102
|
+
font-weight: 600;
|
|
103
|
+
color: white;
|
|
104
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
105
|
+
border: none;
|
|
106
|
+
border-radius: 8px;
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
text-decoration: none;
|
|
109
|
+
transition: opacity 0.2s, transform 0.2s;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.recur-button:hover {
|
|
113
|
+
opacity: 0.9;
|
|
114
|
+
transform: translateY(-1px);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.recur-button:active {
|
|
118
|
+
transform: translateY(0);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.recur-button[data-loading="true"] {
|
|
122
|
+
opacity: 0.7;
|
|
123
|
+
pointer-events: none;
|
|
124
|
+
}
|
|
125
|
+
`,document.head.appendChild(e)}function A(e){try{let r=new URL(e,window.location.origin).pathname.split("/"),o=r.indexOf("buy");if(o===-1||o>=r.length-1)return null;let n=r[o+1];return n?n.startsWith("prod_")?{productId:n}:{productSlug:n}:null}catch{return null}}function P(e){let t=e.getAttribute("data-key");if(t)return t;try{let o=e.getAttribute("href");if(o){let i=new URL(o,window.location.origin).searchParams.get("key");if(i)return i}}catch{}let r=document.querySelector("script[data-recur-key]");return r?r.getAttribute("data-recur-key"):window.RecurConfig?.publishableKey?window.RecurConfig.publishableKey:null}async function b(e,t){let r={};e.productId&&(r.productId=e.productId),e.email&&(r.customerEmail=e.email),e.name&&(r.customerName=e.name);let o=await fetch(`${s.apiUrl}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t,"X-Recur-SDK-Type":"checkout.js","X-Recur-Source":window.location.origin},body:JSON.stringify(r)});if(!o.ok){let i=await o.json().catch(()=>({}));throw new Error(i.error?.message||i.error||"Failed to create checkout")}return{id:(await o.json()).checkout.id,publishableKey:t}}function y(e,t){c(),m();let r=document.createElement("dialog");r.className="recur-checkout-dialog";let o=document.createElement("div");o.className="recur-checkout-dialog__header";let n=document.createElement("button");n.className="recur-checkout-dialog__close",n.innerHTML="×",n.type="button",n.setAttribute("aria-label","Close"),n.onclick=()=>{c(),t?.(),a("recur:close",{})},o.appendChild(n);let i=document.createElement("iframe");i.className="recur-checkout-dialog__iframe",i.src=e,i.setAttribute("allow","payment"),i.setAttribute("title","Recur Checkout"),r.appendChild(o),r.appendChild(i),document.body.appendChild(r),d=r,g=i,r.showModal(),document.body.style.overflow="hidden",r.addEventListener("cancel",p=>{p.preventDefault(),c(),t?.(),a("recur:close",{})}),window.addEventListener("message",k)}function c(){d&&(d.close(),d.remove(),d=null),g=null,document.body.style.overflow="",window.removeEventListener("message",k)}function k(e){if(!e.origin.includes("recur.tw")&&!e.origin.includes("localhost"))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_PAYMENT_SUCCESS":c(),a("recur:success",r);break;case"RECUR_PAYMENT_ERROR":a("recur:error",r);break;case"RECUR_PAYMENT_CANCEL":c(),a("recur:close",{});break;case"RECUR_RESIZE":g&&r?.height&&(g.style.height=`${Math.min(r.height+56,window.innerHeight*.9)}px`);break}}function a(e,t){window.dispatchEvent(new CustomEvent(e,{detail:t}))}async function L(e,t){e.preventDefault();let r=t.getAttribute("href");if(!r){console.error("[Recur] Missing href on recur-button");return}let o=A(r);if(!o){console.error("[Recur] Invalid product URL:",r);return}let n=P(t);if(!n){console.error("[Recur] Missing publishable key. Add data-key attribute or set RecurConfig.publishableKey");return}let i={productId:o.productId||"",email:t.getAttribute("data-email")||void 0,name:t.getAttribute("data-name")||void 0,successUrl:t.getAttribute("data-success-url")||void 0,theme:t.getAttribute("data-theme")||void 0};t.setAttribute("data-loading","true");let p=t.textContent;t.textContent="...";try{let u=await b(i,n),l=new URL(`${s.embedUrl}/checkout`);l.searchParams.set("id",u.id),l.searchParams.set("key",u.publishableKey),i.theme&&l.searchParams.set("theme",i.theme),y(l.toString(),()=>{let x=i.successUrl})}catch(u){console.error("[Recur] Checkout error:",u),a("recur:error",{message:u.message})}finally{t.setAttribute("data-loading","false"),t.textContent=p}}function h(){document.querySelectorAll(".recur-button").forEach(t=>{t.hasAttribute("data-recur-initialized")||(t.setAttribute("data-recur-initialized","true"),t.addEventListener("click",r=>L(r,t)))})}function S(){let e=window.location.hostname;(e==="localhost"||e==="127.0.0.1"||e.includes(".local"))&&(s.embedUrl=`${window.location.protocol}//${e}:3002`,s.apiUrl=`${window.location.protocol}//${e}:3000/api`)}var w={config(e){Object.assign(s,e)},async popup(e){let t=await b(e,e.key),r=new URL(`${s.embedUrl}/checkout`);r.searchParams.set("id",t.id),r.searchParams.set("key",t.publishableKey),e.theme&&r.searchParams.set("theme",e.theme),y(r.toString())},close(){c()},init(){h()}};function M(){S(),m(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",h):h(),new MutationObserver(t=>{for(let r of t)r.addedNodes.length>0&&h()}).observe(document.body,{childList:!0,subtree:!0})}window.Recur=w;M();var I=w;return _(T);})();
|
|
126
|
+
/* Recur Checkout - https://recur.tw */
|
package/dist/recur.umd.js
CHANGED
|
@@ -1944,7 +1944,7 @@
|
|
|
1944
1944
|
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
|
|
1945
1945
|
<circle cx="12" cy="7" r="4"/>
|
|
1946
1946
|
</svg>
|
|
1947
|
-
`}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}redirectToPortal(t){let r=this.getAttribute("target");this.dispatchEvent(new CustomEvent("portal-redirect",{detail:{url:t},bubbles:!0,composed:!0})),r==="_blank"?window.open(t,"_blank","noopener,noreferrer"):window.location.href=t}async fetchAndRedirect(t){let r=this.getAttribute("customer-id"),o=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let i={};r&&(i.customerId=r),o&&(i.returnUrl=o);let s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!s.ok){let d=await s.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${s.status}: Failed to create portal session`)}let a=await s.json(),c=a.url||a.portalUrl;if(!c)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(c)}catch(i){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(i.message||"Failed to create portal session")}}dispatchError(t){console.error("[recur-portal]",t),this.dispatchEvent(new CustomEvent("portal-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-portal")&&customElements.define("recur-portal",ue)});var zt={};C(zt,{RecurCheckout:()=>Z,RecurElements:()=>N,createElements:()=>Se,default:()=>Nt,init:()=>mt});async function Dt(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(De(),Re)),Promise.resolve().then(()=>(Me(),Pe)),Promise.resolve().then(()=>(Ue(),Le)),Promise.resolve().then(()=>(Be(),He)),Promise.resolve().then(()=>(Ze(),Ge)),Promise.resolve().then(()=>(et(),Qe)),Promise.resolve().then(()=>(nt(),st)),Promise.resolve().then(()=>(ct(),at)),Promise.resolve().then(()=>(dt(),lt))]);let e=["recur-loading-spinner","recur-success-message","recur-error-display","recur-skeleton-loader","recur-payment-form-skeleton","recur-toast","recur-toast-container","recur-payment-form","recur-checkout","recur-portal"].filter(t=>!customElements.get(t));e.length>0&&console.warn("[Recur SDK] The following components are not registered:",e)}typeof window<"u"&&Dt();function Pt(n){return n.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function w(n){if(n==null)return n;if(Array.isArray(n))return n.map(e=>w(e));if(n instanceof Date)return n;if(typeof n=="object"){let e={};for(let[t,r]of Object.entries(n)){let o=Pt(t);e[o]=w(r)}return e}return n}var ut={name:"recur-tw",version:"0.9.13",description:"React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",type:"module",private:!1,author:"Recur",license:"Elastic-2.0",keywords:["react","vanilla-js","subscription","checkout","payment","payuni","recurring-billing","taiwan","\u7E41\u9AD4\u4E2D\u6587","sdk","embedded-checkout"],homepage:"https://recur.tw/",bugs:{email:"support@recur.tw"},scripts:{build:"tsup",dev:"tsup --watch",lint:"eslint .","lint:fix":"eslint . --fix","type-check":"tsc --noEmit",examples:"npx http-server
|
|
1947
|
+
`}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}redirectToPortal(t){let r=this.getAttribute("target");this.dispatchEvent(new CustomEvent("portal-redirect",{detail:{url:t},bubbles:!0,composed:!0})),r==="_blank"?window.open(t,"_blank","noopener,noreferrer"):window.location.href=t}async fetchAndRedirect(t){let r=this.getAttribute("customer-id"),o=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let i={};r&&(i.customerId=r),o&&(i.returnUrl=o);let s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!s.ok){let d=await s.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${s.status}: Failed to create portal session`)}let a=await s.json(),c=a.url||a.portalUrl;if(!c)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(c)}catch(i){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(i.message||"Failed to create portal session")}}dispatchError(t){console.error("[recur-portal]",t),this.dispatchEvent(new CustomEvent("portal-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-portal")&&customElements.define("recur-portal",ue)});var zt={};C(zt,{RecurCheckout:()=>Z,RecurElements:()=>N,createElements:()=>Se,default:()=>Nt,init:()=>mt});async function Dt(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(De(),Re)),Promise.resolve().then(()=>(Me(),Pe)),Promise.resolve().then(()=>(Ue(),Le)),Promise.resolve().then(()=>(Be(),He)),Promise.resolve().then(()=>(Ze(),Ge)),Promise.resolve().then(()=>(et(),Qe)),Promise.resolve().then(()=>(nt(),st)),Promise.resolve().then(()=>(ct(),at)),Promise.resolve().then(()=>(dt(),lt))]);let e=["recur-loading-spinner","recur-success-message","recur-error-display","recur-skeleton-loader","recur-payment-form-skeleton","recur-toast","recur-toast-container","recur-payment-form","recur-checkout","recur-portal"].filter(t=>!customElements.get(t));e.length>0&&console.warn("[Recur SDK] The following components are not registered:",e)}typeof window<"u"&&Dt();function Pt(n){return n.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function w(n){if(n==null)return n;if(Array.isArray(n))return n.map(e=>w(e));if(n instanceof Date)return n;if(typeof n=="object"){let e={};for(let[t,r]of Object.entries(n)){let o=Pt(t);e[o]=w(r)}return e}return n}var ut={name:"recur-tw",version:"0.9.13",description:"React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",type:"module",private:!1,author:"Recur",license:"Elastic-2.0",keywords:["react","vanilla-js","subscription","checkout","payment","payuni","recurring-billing","taiwan","\u7E41\u9AD4\u4E2D\u6587","sdk","embedded-checkout"],homepage:"https://recur.tw/",bugs:{email:"support@recur.tw"},scripts:{build:"tsup",dev:"tsup --watch",lint:"eslint .","lint:fix":"eslint . --fix","type-check":"tsc --noEmit",examples:"npx http-server . -p 8080 -o /examples/"},main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs"},"./server":{types:"./dist/server.d.ts",import:"./dist/server.js",require:"./dist/server.cjs"},"./vanilla":"./dist/recur.umd.js","./checkout":"./dist/checkout.js","./widget":"./dist/widget.js","./package.json":"./package.json"},unpkg:"./dist/recur.umd.js",jsdelivr:"./dist/recur.umd.js",files:["dist","README.md","AGENTS.md","LICENSE"],sideEffects:["src/components/**/*.ts","src/components/**/*.js"],peerDependencies:{react:">=18.0.0","react-dom":">=18.0.0"},peerDependenciesMeta:{react:{optional:!0},"react-dom":{optional:!0}},devDependencies:{"@eslint/js":"^9.39.1","@types/node":"^20.19.9","@types/react":"^19.1.9","@types/react-dom":"^19.1.7","@workspace/typescript-config":"workspace:*",autoprefixer:"^10.4.22",eslint:"^9","eslint-plugin-react":"^7.37.5","eslint-plugin-react-hooks":"^7.0.1",postcss:"^8.5.6",react:"^19.2.1","react-dom":"^19.2.1",tailwindcss:"^4.1.11",tsup:"^8.3.5",typescript:"^5.9.2","typescript-eslint":"^8.47.0"},dependencies:{"lit-html":"^3.3.1"}};var Lt=ut.version,Ut="vanilla",pe=class{constructor(e){l(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:"https://api.recur.tw",...e}}getHeaders(){return{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey,"X-Recur-SDK-Type":Ut,"X-Recur-SDK-Version":Lt,"X-Recur-Source":typeof window<"u"?window.location.origin:"server"}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,o=e.productId||e.planId,i=e.productSlug;if(!o&&!i)throw new Error("Either productId or productSlug is required");let s={customerName:t,customerEmail:r};o&&(s.productId=o),i&&(s.productSlug=i);let a=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(s)});if(!a.ok){let d=await a.json().catch(()=>({}));throw{code:d.error||"CHECKOUT_FAILED",message:d.message||"Failed to initiate checkout",details:d}}let c=await a.json();return w(c)}async fetchProducts(e){let t=new URL(`${this.config.baseUrl}/v1/products`);e?.type&&t.searchParams.set("type",e.type);let r=await fetch(t.toString(),{method:"GET",headers:this.getHeaders()});if(!r.ok){let i=await r.json().catch(()=>({}));throw{code:i.error||"FETCH_PRODUCTS_FAILED",message:i.message||"Failed to fetch products",details:i}}let o=await r.json();return w(o)}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var he=class{constructor(e,t){l(this,"config");l(this,"options");l(this,"container");l(this,"checkoutId",null);l(this,"sdkToken",null);l(this,"sdkTimestamp",null);l(this,"creditToken",null);l(this,"sdkEnv","S");l(this,"payuniSDK",null);l(this,"isFormValid",!1);if(this.config=e,this.options=t,typeof t.container=="string"){let r=document.querySelector(t.container);if(!r)throw new Error(`Container not found: ${t.container}`);this.container=r}else this.container=t.container}async render(){try{await this.initCheckout(),this.renderHTML(),await this.loadPayUniSDK(),await this.initPayUniSDK(),this.setupFormSubmit()}catch(e){this.handleError(e)}}getBaseUrl(){if(this.config.baseUrl)return this.config.baseUrl;if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}async initCheckout(){let e=this.getBaseUrl(),t=await fetch(`${e}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({productId:this.options.productId||this.options.planId,customerEmail:this.options.customerEmail,customerName:this.options.customerName})});if(!t.ok){let i=await t.json().catch(()=>({}));throw new Error(i.error||"Failed to initialize checkout")}let r=await t.json(),o=w(r);this.checkoutId=o.checkout.id,this.sdkToken=o.sdkToken,this.sdkTimestamp=o.sdkTimestamp||null,this.creditToken=o.creditToken||null,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
|
|
1948
1948
|
<div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
|
|
1949
1949
|
<div class="recur-checkout-header" style="margin-bottom: 24px;">
|
|
1950
1950
|
<h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
|
package/dist/widget.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";var RecurWidgetScript=(()=>{var g=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var v=(e,t)=>{for(var o in t)g(e,o,{get:t[o],enumerable:!0})},C=(e,t,o,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of x(t))!y.call(e,n)&&n!==o&&g(e,n,{get:()=>t[n],enumerable:!(i=w(t,n))||i.enumerable});return e};var E=e=>C(g({},"__esModule",{value:!0}),e);var L={};v(L,{default:()=>S});var d={text:"\u8A02\u95B1\u652F\u6301",color:"#667eea",textColor:"#ffffff",position:"right",xMargin:18,yMargin:18,embedUrl:"https://embed.recur.tw",apiUrl:"https://api.recur.tw"},r=null,a=null,l=null,u=null;function k(){let e=document.querySelectorAll("script[data-product]"),t=e[e.length-1];if(!t)return console.error("[Recur Widget] Missing data-product attribute on script tag"),null;let o=t.getAttribute("data-key"),i=t.getAttribute("data-product");return o?i?{key:o,product:i,text:t.getAttribute("data-text")||d.text,color:t.getAttribute("data-color")||d.color,textColor:t.getAttribute("data-text-color")||d.textColor,position:t.getAttribute("data-position")||d.position,xMargin:parseInt(t.getAttribute("data-x-margin")||String(d.xMargin),10),yMargin:parseInt(t.getAttribute("data-y-margin")||String(d.yMargin),10),embedUrl:t.getAttribute("data-embed-url")||d.embedUrl,apiUrl:t.getAttribute("data-api-url")||d.apiUrl}:(console.error("[Recur Widget] Missing data-product attribute on script tag"),null):(console.error("[Recur Widget] Missing data-key attribute on script tag"),null)}function M(){if(!r)return;let e=window.location.hostname;(e==="localhost"||e==="127.0.0.1"||e.includes(".local"))&&(r.embedUrl=`${window.location.protocol}//${e}:3002`,r.apiUrl=`${window.location.protocol}//${e}:3000/api`)}function _(){if(!r||document.getElementById("recur-widget-styles"))return;let e=document.createElement("style");e.id="recur-widget-styles",e.textContent=`
|
|
2
|
+
.recur-widget-button {
|
|
3
|
+
position: fixed;
|
|
4
|
+
bottom: ${r.yMargin}px;
|
|
5
|
+
${r.position}: ${r.xMargin}px;
|
|
6
|
+
z-index: 9999;
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
gap: 8px;
|
|
10
|
+
padding: 12px 20px;
|
|
11
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
12
|
+
font-size: 15px;
|
|
13
|
+
font-weight: 600;
|
|
14
|
+
color: ${r.textColor};
|
|
15
|
+
background: ${r.color};
|
|
16
|
+
border: none;
|
|
17
|
+
border-radius: 50px;
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
|
|
20
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.recur-widget-button:hover {
|
|
24
|
+
transform: translateY(-2px);
|
|
25
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.recur-widget-button:active {
|
|
29
|
+
transform: translateY(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.recur-widget-button[data-loading="true"] {
|
|
33
|
+
opacity: 0.8;
|
|
34
|
+
pointer-events: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.recur-widget-button__icon {
|
|
38
|
+
width: 20px;
|
|
39
|
+
height: 20px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.recur-widget-dialog {
|
|
43
|
+
border: none;
|
|
44
|
+
border-radius: 12px;
|
|
45
|
+
padding: 0;
|
|
46
|
+
width: 90%;
|
|
47
|
+
max-width: 480px;
|
|
48
|
+
max-height: 90vh;
|
|
49
|
+
overflow: hidden;
|
|
50
|
+
background: white;
|
|
51
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
52
|
+
position: fixed;
|
|
53
|
+
inset: 0;
|
|
54
|
+
margin: auto;
|
|
55
|
+
height: fit-content;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.recur-widget-dialog::backdrop {
|
|
59
|
+
background: rgba(0, 0, 0, 0.6);
|
|
60
|
+
backdrop-filter: blur(4px);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.recur-widget-dialog[open] {
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
animation: recur-widget-dialog-open 0.2s ease-out;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@keyframes recur-widget-dialog-open {
|
|
70
|
+
from {
|
|
71
|
+
opacity: 0;
|
|
72
|
+
transform: scale(0.95);
|
|
73
|
+
}
|
|
74
|
+
to {
|
|
75
|
+
opacity: 1;
|
|
76
|
+
transform: scale(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.recur-widget-dialog__header {
|
|
81
|
+
display: flex;
|
|
82
|
+
justify-content: flex-end;
|
|
83
|
+
padding: 12px 12px 0 12px;
|
|
84
|
+
background: white;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.recur-widget-dialog__close {
|
|
88
|
+
width: 32px;
|
|
89
|
+
height: 32px;
|
|
90
|
+
border: none;
|
|
91
|
+
background: rgba(0, 0, 0, 0.05);
|
|
92
|
+
border-radius: 50%;
|
|
93
|
+
cursor: pointer;
|
|
94
|
+
font-size: 18px;
|
|
95
|
+
color: #666;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
transition: background 0.2s;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.recur-widget-dialog__close:hover {
|
|
103
|
+
background: rgba(0, 0, 0, 0.1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.recur-widget-dialog__iframe {
|
|
107
|
+
width: 100%;
|
|
108
|
+
height: 600px;
|
|
109
|
+
max-height: calc(90vh - 56px);
|
|
110
|
+
border: none;
|
|
111
|
+
display: block;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Mobile adjustments */
|
|
115
|
+
@media (max-width: 480px) {
|
|
116
|
+
.recur-widget-button {
|
|
117
|
+
padding: 10px 16px;
|
|
118
|
+
font-size: 14px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.recur-widget-dialog {
|
|
122
|
+
width: 95%;
|
|
123
|
+
max-height: 95vh;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
`,document.head.appendChild(e)}function R(){if(!r||a)return;let e=document.createElement("button");e.className="recur-widget-button",e.setAttribute("aria-label",r.text),e.innerHTML=`
|
|
127
|
+
<svg class="recur-widget-button__icon" viewBox="0 0 24 24" fill="currentColor">
|
|
128
|
+
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
|
|
129
|
+
</svg>
|
|
130
|
+
<span>${r.text}</span>
|
|
131
|
+
`,e.addEventListener("click",f),document.body.appendChild(e),a=e}async function A(){if(!r)throw new Error("Widget not configured");let e=await fetch(`${r.apiUrl}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":r.key,"X-Recur-SDK-Type":"widget.js","X-Recur-Source":window.location.origin},body:JSON.stringify({productId:r.product})});if(!e.ok){let o=await e.json().catch(()=>({}));throw new Error(o.error?.message||o.error||"Failed to create checkout")}return{id:(await e.json()).checkout.id}}function U(e){if(!r)return;c();let t=document.createElement("dialog");t.className="recur-widget-dialog";let o=document.createElement("div");o.className="recur-widget-dialog__header";let i=document.createElement("button");i.className="recur-widget-dialog__close",i.innerHTML="×",i.type="button",i.setAttribute("aria-label","Close"),i.onclick=()=>{c(),s("recur:close",{})},o.appendChild(i);let n=document.createElement("iframe");n.className="recur-widget-dialog__iframe",n.src=e,n.setAttribute("allow","payment"),n.setAttribute("title","Recur Checkout"),t.appendChild(o),t.appendChild(n),document.body.appendChild(t),l=t,u=n,t.showModal(),document.body.style.overflow="hidden",t.addEventListener("cancel",b=>{b.preventDefault(),c(),s("recur:close",{})}),window.addEventListener("message",m)}function c(){l&&(l.close(),l.remove(),l=null),u=null,document.body.style.overflow="",window.removeEventListener("message",m)}function m(e){if(!e.origin.includes("recur.tw")&&!e.origin.includes("localhost"))return;let{type:t,data:o}=e.data||{};switch(t){case"RECUR_PAYMENT_SUCCESS":c(),s("recur:success",o);break;case"RECUR_PAYMENT_ERROR":s("recur:error",o);break;case"RECUR_PAYMENT_CANCEL":c(),s("recur:close",{});break;case"RECUR_RESIZE":u&&o?.height&&(u.style.height=`${Math.min(o.height+56,window.innerHeight*.9)}px`);break}}function s(e,t){window.dispatchEvent(new CustomEvent(e,{detail:t}))}async function f(){if(!(!r||!a)){a.setAttribute("data-loading","true");try{let e=await A(),t=new URL(`${r.embedUrl}/checkout`);t.searchParams.set("id",e.id),t.searchParams.set("key",r.key),U(t.toString())}catch(e){console.error("[Recur Widget] Error:",e),s("recur:error",{message:e.message})}finally{a.setAttribute("data-loading","false")}}}var h={open(){f()},close(){c()},show(){a&&(a.style.display="flex")},hide(){a&&(a.style.display="none")},destroy(){c(),a&&(a.remove(),a=null);let e=document.getElementById("recur-widget-styles");e&&e.remove()}};function p(){r=k(),r&&(M(),_(),R())}window.RecurWidget=h;document.readyState==="loading"?document.addEventListener("DOMContentLoaded",p):p();var S=h;return E(L);})();
|
|
132
|
+
/* Recur Widget - https://recur.tw */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "recur-tw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"lint": "eslint .",
|
|
30
30
|
"lint:fix": "eslint . --fix",
|
|
31
31
|
"type-check": "tsc --noEmit",
|
|
32
|
-
"examples": "npx http-server
|
|
32
|
+
"examples": "npx http-server . -p 8080 -o /examples/"
|
|
33
33
|
},
|
|
34
34
|
"main": "./dist/index.js",
|
|
35
35
|
"module": "./dist/index.js",
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
"require": "./dist/server.cjs"
|
|
47
47
|
},
|
|
48
48
|
"./vanilla": "./dist/recur.umd.js",
|
|
49
|
+
"./checkout": "./dist/checkout.js",
|
|
50
|
+
"./widget": "./dist/widget.js",
|
|
49
51
|
"./package.json": "./package.json"
|
|
50
52
|
},
|
|
51
53
|
"unpkg": "./dist/recur.umd.js",
|