recur-tw 0.9.4 → 0.9.5
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.cjs +8 -2
- package/dist/index.js +8 -2
- package/dist/recur.umd.js +11 -5
- package/dist/server.cjs +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1232,6 +1232,8 @@ var init_payment_form = __esm({
|
|
|
1232
1232
|
background: white;
|
|
1233
1233
|
border-radius: 12px;
|
|
1234
1234
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
1235
|
+
/* Prevent double-tap zoom on iOS */
|
|
1236
|
+
touch-action: manipulation;
|
|
1235
1237
|
}
|
|
1236
1238
|
|
|
1237
1239
|
.form-header {
|
|
@@ -1527,7 +1529,7 @@ var init_payment_form = __esm({
|
|
|
1527
1529
|
.recur-form-input {
|
|
1528
1530
|
width: 100%;
|
|
1529
1531
|
padding: 10px 12px;
|
|
1530
|
-
font-size:
|
|
1532
|
+
font-size: 16px; /* 16px prevents iOS Safari auto-zoom on focus */
|
|
1531
1533
|
border: 1px solid #d1d5db;
|
|
1532
1534
|
border-radius: 6px;
|
|
1533
1535
|
transition: border-color 0.2s;
|
|
@@ -1594,6 +1596,8 @@ var init_payment_form = __esm({
|
|
|
1594
1596
|
width: 100%;
|
|
1595
1597
|
max-width: 100%;
|
|
1596
1598
|
box-sizing: border-box;
|
|
1599
|
+
/* Help reduce iOS zoom issues */
|
|
1600
|
+
touch-action: manipulation;
|
|
1597
1601
|
}
|
|
1598
1602
|
|
|
1599
1603
|
.recur-card-row {
|
|
@@ -1607,6 +1611,8 @@ var init_payment_form = __esm({
|
|
|
1607
1611
|
/* Container needs relative positioning for skeleton overlay */
|
|
1608
1612
|
.recur-card-field-container {
|
|
1609
1613
|
position: relative;
|
|
1614
|
+
/* Help reduce iOS zoom issues */
|
|
1615
|
+
touch-action: manipulation;
|
|
1610
1616
|
}
|
|
1611
1617
|
|
|
1612
1618
|
/* Loading skeleton for card fields - shown until PAYUNi iframe loads */
|
|
@@ -2619,7 +2625,7 @@ function toCamelCase(obj) {
|
|
|
2619
2625
|
|
|
2620
2626
|
// package.json
|
|
2621
2627
|
var package_default = {
|
|
2622
|
-
version: "0.9.
|
|
2628
|
+
version: "0.9.5"};
|
|
2623
2629
|
var SDK_VERSION = package_default.version;
|
|
2624
2630
|
var SDK_TYPE = "react";
|
|
2625
2631
|
var RecurContext = React.createContext(null);
|
package/dist/index.js
CHANGED
|
@@ -1226,6 +1226,8 @@ var init_payment_form = __esm({
|
|
|
1226
1226
|
background: white;
|
|
1227
1227
|
border-radius: 12px;
|
|
1228
1228
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
1229
|
+
/* Prevent double-tap zoom on iOS */
|
|
1230
|
+
touch-action: manipulation;
|
|
1229
1231
|
}
|
|
1230
1232
|
|
|
1231
1233
|
.form-header {
|
|
@@ -1521,7 +1523,7 @@ var init_payment_form = __esm({
|
|
|
1521
1523
|
.recur-form-input {
|
|
1522
1524
|
width: 100%;
|
|
1523
1525
|
padding: 10px 12px;
|
|
1524
|
-
font-size:
|
|
1526
|
+
font-size: 16px; /* 16px prevents iOS Safari auto-zoom on focus */
|
|
1525
1527
|
border: 1px solid #d1d5db;
|
|
1526
1528
|
border-radius: 6px;
|
|
1527
1529
|
transition: border-color 0.2s;
|
|
@@ -1588,6 +1590,8 @@ var init_payment_form = __esm({
|
|
|
1588
1590
|
width: 100%;
|
|
1589
1591
|
max-width: 100%;
|
|
1590
1592
|
box-sizing: border-box;
|
|
1593
|
+
/* Help reduce iOS zoom issues */
|
|
1594
|
+
touch-action: manipulation;
|
|
1591
1595
|
}
|
|
1592
1596
|
|
|
1593
1597
|
.recur-card-row {
|
|
@@ -1601,6 +1605,8 @@ var init_payment_form = __esm({
|
|
|
1601
1605
|
/* Container needs relative positioning for skeleton overlay */
|
|
1602
1606
|
.recur-card-field-container {
|
|
1603
1607
|
position: relative;
|
|
1608
|
+
/* Help reduce iOS zoom issues */
|
|
1609
|
+
touch-action: manipulation;
|
|
1604
1610
|
}
|
|
1605
1611
|
|
|
1606
1612
|
/* Loading skeleton for card fields - shown until PAYUNi iframe loads */
|
|
@@ -2613,7 +2619,7 @@ function toCamelCase(obj) {
|
|
|
2613
2619
|
|
|
2614
2620
|
// package.json
|
|
2615
2621
|
var package_default = {
|
|
2616
|
-
version: "0.9.
|
|
2622
|
+
version: "0.9.5"};
|
|
2617
2623
|
var SDK_VERSION = package_default.version;
|
|
2618
2624
|
var SDK_TYPE = "react";
|
|
2619
2625
|
var RecurContext = createContext(null);
|
package/dist/recur.umd.js
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
|
|
41
41
|
<div class="recur-sdk__spinner"></div>
|
|
42
42
|
${this.message?`<p class="recur-sdk__loading-text">${this.message}</p>`:""}
|
|
43
|
-
`}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",z)});var oe={};v(oe,{RecurSuccessMessage:()
|
|
43
|
+
`}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",z)});var oe={};v(oe,{RecurSuccessMessage:()=>H});var H,ne=w(()=>{"use strict";H=class extends HTMLElement{static get observedAttributes(){return["title","message","icon"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get successTitle(){return this.getAttribute("title")||"Subscription Complete!"}get successMessage(){return this.getAttribute("message")||"Thank you for subscribing. Your payment has been processed successfully."}get showIcon(){return this.getAttribute("icon")!=="false"}render(){this.shadowRoot.innerHTML=`
|
|
44
44
|
<style>
|
|
45
45
|
:host {
|
|
46
46
|
display: block;
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
<p class="recur-sdk__success-message">${this.successMessage}</p>
|
|
122
122
|
<slot></slot>
|
|
123
123
|
</div>
|
|
124
|
-
`}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message"
|
|
124
|
+
`}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message",H)});var ae={};v(ae,{RecurErrorDisplay:()=>$});var $,ce=w(()=>{"use strict";$=class extends HTMLElement{static get observedAttributes(){return["error","dismissible"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get error(){return this.getAttribute("error")||""}get isDismissible(){return this.getAttribute("dismissible")==="true"}handleDismiss(){this.dispatchEvent(new CustomEvent("dismiss",{bubbles:!0,composed:!0})),this.remove()}render(){if(!this.error){this.shadowRoot.innerHTML="";return}this.shadowRoot.innerHTML=`
|
|
125
125
|
<style>
|
|
126
126
|
:host {
|
|
127
127
|
display: block;
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
</button>
|
|
212
212
|
`:""}
|
|
213
213
|
</div>
|
|
214
|
-
`,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display"
|
|
214
|
+
`,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display",$)});var le={};v(le,{RecurSkeletonLoader:()=>K});var K,de=w(()=>{"use strict";K=class extends HTMLElement{static get observedAttributes(){return["type"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get type(){let e=this.getAttribute("type");return e==="list"||e==="card"?e:"payment-form"}renderPaymentFormSkeleton(){return`
|
|
215
215
|
<div class="skeleton-field">
|
|
216
216
|
<div class="skeleton-label"></div>
|
|
217
217
|
<div class="skeleton-input"></div>
|
|
@@ -805,6 +805,8 @@
|
|
|
805
805
|
background: white;
|
|
806
806
|
border-radius: 12px;
|
|
807
807
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
808
|
+
/* Prevent double-tap zoom on iOS */
|
|
809
|
+
touch-action: manipulation;
|
|
808
810
|
}
|
|
809
811
|
|
|
810
812
|
.form-header {
|
|
@@ -1037,7 +1039,7 @@
|
|
|
1037
1039
|
.recur-form-input {
|
|
1038
1040
|
width: 100%;
|
|
1039
1041
|
padding: 10px 12px;
|
|
1040
|
-
font-size:
|
|
1042
|
+
font-size: 16px; /* 16px prevents iOS Safari auto-zoom on focus */
|
|
1041
1043
|
border: 1px solid #d1d5db;
|
|
1042
1044
|
border-radius: 6px;
|
|
1043
1045
|
transition: border-color 0.2s;
|
|
@@ -1097,6 +1099,8 @@
|
|
|
1097
1099
|
width: 100%;
|
|
1098
1100
|
max-width: 100%;
|
|
1099
1101
|
box-sizing: border-box;
|
|
1102
|
+
/* Help reduce iOS zoom issues */
|
|
1103
|
+
touch-action: manipulation;
|
|
1100
1104
|
}
|
|
1101
1105
|
|
|
1102
1106
|
.recur-card-row {
|
|
@@ -1110,6 +1114,8 @@
|
|
|
1110
1114
|
/* Container needs relative positioning for skeleton overlay */
|
|
1111
1115
|
.recur-card-field-container {
|
|
1112
1116
|
position: relative;
|
|
1117
|
+
/* Help reduce iOS zoom issues */
|
|
1118
|
+
touch-action: manipulation;
|
|
1113
1119
|
}
|
|
1114
1120
|
|
|
1115
1121
|
/* Loading skeleton for card fields - shown until PAYUNi iframe loads */
|
|
@@ -1452,7 +1458,7 @@
|
|
|
1452
1458
|
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
|
|
1453
1459
|
<circle cx="12" cy="7" r="4"/>
|
|
1454
1460
|
</svg>
|
|
1455
|
-
`}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"),s=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let i={};r&&(i.customerId=r),s&&(i.returnUrl=s);let n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!n.ok){let m=await n.json().catch(()=>({}));throw new Error(m.error?.message||m.message||`HTTP ${n.status}: Failed to create portal session`)}let o=await n.json(),d=o.url||o.portalUrl;if(!d)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(d)}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",F)});var je={};v(je,{RecurCheckout:()=>M,RecurElements:()=>T,createElements:()=>Q,default:()=>Oe,init:()=>Se});async function _e(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(ie(),se)),Promise.resolve().then(()=>(ne(),oe)),Promise.resolve().then(()=>(ce(),ae)),Promise.resolve().then(()=>(de(),le)),Promise.resolve().then(()=>(me(),ue)),Promise.resolve().then(()=>(he(),pe)),Promise.resolve().then(()=>(ge(),fe)),Promise.resolve().then(()=>(ye(),be)),Promise.resolve().then(()=>(ve(),ke))]);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"&&_e();function ze(a){return a.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function g(a){if(a==null)return a;if(Array.isArray(a))return a.map(e=>g(e));if(a instanceof Date)return a;if(typeof a=="object"){let e={};for(let[t,r]of Object.entries(a)){let s=ze(t);e[s]=g(r)}return e}return a}var we={name:"recur-tw",version:"0.9.
|
|
1461
|
+
`}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"),s=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let i={};r&&(i.customerId=r),s&&(i.returnUrl=s);let n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!n.ok){let m=await n.json().catch(()=>({}));throw new Error(m.error?.message||m.message||`HTTP ${n.status}: Failed to create portal session`)}let o=await n.json(),d=o.url||o.portalUrl;if(!d)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(d)}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",F)});var je={};v(je,{RecurCheckout:()=>M,RecurElements:()=>T,createElements:()=>Q,default:()=>Oe,init:()=>Se});async function _e(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(ie(),se)),Promise.resolve().then(()=>(ne(),oe)),Promise.resolve().then(()=>(ce(),ae)),Promise.resolve().then(()=>(de(),le)),Promise.resolve().then(()=>(me(),ue)),Promise.resolve().then(()=>(he(),pe)),Promise.resolve().then(()=>(ge(),fe)),Promise.resolve().then(()=>(ye(),be)),Promise.resolve().then(()=>(ve(),ke))]);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"&&_e();function ze(a){return a.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function g(a){if(a==null)return a;if(Array.isArray(a))return a.map(e=>g(e));if(a instanceof Date)return a;if(typeof a=="object"){let e={};for(let[t,r]of Object.entries(a)){let s=ze(t);e[s]=g(r)}return e}return a}var we={name:"recur-tw",version:"0.9.5",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 examples -p 8080 -o"},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","./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"}};var $e=we.version,Ke="vanilla",q=class{constructor(e){c(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":Ke,"X-Recur-SDK-Version":$e,"X-Recur-Source":typeof window<"u"?window.location.origin:"server"}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,s=e.productId||e.planId,i=e.productSlug;if(!s&&!i)throw new Error("Either productId or productSlug is required");let n={customerName:t,customerEmail:r};s&&(n.productId=s),i&&(n.productSlug=i);let o=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(n)});if(!o.ok){let m=await o.json().catch(()=>({}));throw{code:m.error||"CHECKOUT_FAILED",message:m.message||"Failed to initiate checkout",details:m}}let d=await o.json();return g(d)}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 s=await r.json();return g(s)}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var V=class{constructor(e,t){c(this,"config");c(this,"options");c(this,"container");c(this,"checkoutId",null);c(this,"sdkToken",null);c(this,"sdkTimestamp",null);c(this,"creditToken",null);c(this,"sdkEnv","S");c(this,"payuniSDK",null);c(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.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(),s=g(r);this.checkoutId=s.checkout.id,this.sdkToken=s.sdkToken,this.sdkTimestamp=s.sdkTimestamp||null,this.creditToken=s.creditToken||null,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
|
|
1456
1462
|
<div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
|
|
1457
1463
|
<div class="recur-checkout-header" style="margin-bottom: 24px;">
|
|
1458
1464
|
<h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
|
package/dist/server.cjs
CHANGED
package/dist/server.js
CHANGED