recur-tw 0.13.1 → 0.13.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/checkout.js CHANGED
@@ -1,4 +1,4 @@
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})},_=(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 U=e=>_(f({},"__esModule",{value:!0}),e);var T={};R(T,{default:()=>I});var a={embedUrl:"https://embed.recur.tw",apiUrl:"https://api.recur.tw"},h=null,p=null;function m(){if(document.getElementById("recur-checkout-styles"))return;let e=document.createElement("style");e.id="recur-checkout-styles",e.textContent=`
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})},_=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of E(t))!C.call(e,o)&&o!==r&&f(e,o,{get:()=>t[o],enumerable:!(n=v(t,o))||n.enumerable});return e};var U=e=>_(f({},"__esModule",{value:!0}),e);var T={};R(T,{default:()=>I});var s={embedUrl:"https://embed.recur.tw",apiUrl:"https://api.recur.tw"},h=null,p=null;function m(){if(document.getElementById("recur-checkout-styles"))return;let e=document.createElement("style");e.id="recur-checkout-styles",e.textContent=`
2
2
  .recur-checkout-dialog {
3
3
  border: none;
4
4
  border-radius: 12px;
@@ -37,6 +37,14 @@
37
37
  }
38
38
  }
39
39
 
40
+ .recur-checkout-dialog__content {
41
+ display: flex;
42
+ flex-direction: column;
43
+ width: 100%;
44
+ height: 100%;
45
+ outline: none;
46
+ }
47
+
40
48
  .recur-checkout-dialog__header {
41
49
  display: flex;
42
50
  justify-content: flex-end;
@@ -122,5 +130,5 @@
122
130
  opacity: 0.7;
123
131
  pointer-events: none;
124
132
  }
125
- `,document.head.appendChild(e)}function S(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 n=e.getAttribute("href");if(n){let s=new URL(n,window.location.origin).searchParams.get("key");if(s)return s}}catch{}let r=document.querySelector("script[data-recur-key]");if(r)return r.getAttribute("data-recur-key");let o=window.RecurConfig;return o?.publishableKey?o.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(`${a.apiUrl}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t,"X-Recur-Embed-Domain":a.embedUrl,"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")}let n=await o.json();return{id:n.checkout.id,publishableKey:t,clientSecret:n.checkout.client_secret}}function y(e,t){u(),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=()=>{u(),t?.(),d("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),h=r,p=i,r.showModal(),document.body.style.overflow="hidden",r.addEventListener("cancel",s=>{s.preventDefault(),u(),t?.(),d("recur:close",{})}),window.addEventListener("message",k)}function u(){h&&(h.close(),h.remove(),h=null),p=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":u(),d("recur:success",r);break;case"RECUR_PAYMENT_ERROR":d("recur:error",r);break;case"RECUR_PAYMENT_CANCEL":u(),d("recur:close",{});break;case"RECUR_RESIZE":p&&r?.height&&(p.style.height=`${Math.min(r.height+56,window.innerHeight*.9)}px`);break}}function d(e,t){window.dispatchEvent(new CustomEvent(e,{detail:t}))}async function A(e,t){e.preventDefault();let r=t.getAttribute("href");if(!r){console.error("[Recur] Missing href on recur-button");return}let o=S(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 s=t.textContent;t.textContent="...";try{let c=await b(i,n),l=new URL(`${a.embedUrl}/checkout`);l.searchParams.set("id",c.id),l.searchParams.set("key",c.publishableKey),l.searchParams.set("client_secret",c.clientSecret),i.theme&&l.searchParams.set("theme",i.theme),y(l.toString(),()=>{let x=i.successUrl})}catch(c){console.error("[Recur] Checkout error:",c),d("recur:error",{message:c instanceof Error?c.message:"Unknown error"})}finally{t.setAttribute("data-loading","false"),t.textContent=s}}function g(){document.querySelectorAll(".recur-button").forEach(t=>{t.hasAttribute("data-recur-initialized")||(t.setAttribute("data-recur-initialized","true"),t.addEventListener("click",r=>A(r,t)))})}function L(){let e=window.location.hostname;(e==="localhost"||e==="127.0.0.1"||e.includes(".local"))&&(a.embedUrl=`${window.location.protocol}//${e}:3002`,a.apiUrl=`${window.location.protocol}//${e}:3000/api`)}var w={config(e){Object.assign(a,e)},async popup(e){let t=await b(e,e.key),r=new URL(`${a.embedUrl}/checkout`);r.searchParams.set("id",t.id),r.searchParams.set("key",t.publishableKey),r.searchParams.set("client_secret",t.clientSecret),e.theme&&r.searchParams.set("theme",e.theme),y(r.toString())},close(){u()},init(){g()}};function M(){L(),m(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",g):g(),new MutationObserver(t=>{for(let r of t)r.addedNodes.length>0&&g()}).observe(document.body,{childList:!0,subtree:!0})}window.Recur=w;M();var I=w;return U(T);})();
133
+ `,document.head.appendChild(e)}function A(e){try{let r=new URL(e,window.location.origin).pathname.split("/"),n=r.indexOf("buy");if(n===-1||n>=r.length-1)return null;let o=r[n+1];return o?o.startsWith("prod_")?{productId:o}:{productSlug:o}:null}catch{return null}}function S(e){let t=e.getAttribute("data-key");if(t)return t;try{let o=e.getAttribute("href");if(o){let c=new URL(o,window.location.origin).searchParams.get("key");if(c)return c}}catch{}let r=document.querySelector("script[data-recur-key]");if(r)return r.getAttribute("data-recur-key");let n=window.RecurConfig;return n?.publishableKey?n.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 n=await fetch(`${s.apiUrl}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t,"X-Recur-Embed-Domain":s.embedUrl,"X-Recur-SDK-Type":"checkout.js","X-Recur-Source":window.location.origin},body:JSON.stringify(r)});if(!n.ok){let i=await n.json().catch(()=>({}));throw new Error(i.error?.message||i.error||"Failed to create checkout")}let o=await n.json();return{id:o.checkout.id,publishableKey:t,clientSecret:o.checkout.client_secret}}function y(e,t){u(),m();let r=document.createElement("dialog");r.className="recur-checkout-dialog";let n=document.createElement("div");n.className="recur-checkout-dialog__content",n.setAttribute("tabindex","-1"),n.setAttribute("autofocus","");let o=document.createElement("div");o.className="recur-checkout-dialog__header";let i=document.createElement("button");i.className="recur-checkout-dialog__close",i.innerHTML="×",i.type="button",i.setAttribute("aria-label","Close"),i.onclick=()=>{u(),t?.(),d("recur:close",{})},o.appendChild(i);let c=document.createElement("iframe");c.className="recur-checkout-dialog__iframe",c.src=e,c.setAttribute("allow","payment"),c.setAttribute("title","Recur Checkout"),n.appendChild(o),n.appendChild(c),r.appendChild(n),document.body.appendChild(r),h=r,p=c,r.showModal(),document.body.style.overflow="hidden",r.addEventListener("cancel",a=>{a.preventDefault(),u(),t?.(),d("recur:close",{})}),window.addEventListener("message",k)}function u(){h&&(h.close(),h.remove(),h=null),p=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":u(),d("recur:success",r);break;case"RECUR_PAYMENT_ERROR":d("recur:error",r);break;case"RECUR_PAYMENT_CANCEL":u(),d("recur:close",{});break;case"RECUR_RESIZE":p&&r?.height&&(p.style.height=`${Math.min(r.height+56,window.innerHeight*.9)}px`);break}}function d(e,t){window.dispatchEvent(new CustomEvent(e,{detail:t}))}async function P(e,t){e.preventDefault();let r=t.getAttribute("href");if(!r){console.error("[Recur] Missing href on recur-button");return}let n=A(r);if(!n){console.error("[Recur] Invalid product URL:",r);return}let o=S(t);if(!o){console.error("[Recur] Missing publishable key. Add data-key attribute or set RecurConfig.publishableKey");return}let i={productId:n.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 c=t.textContent;t.textContent="...";try{let a=await b(i,o),l=new URL(`${s.embedUrl}/checkout`);l.searchParams.set("id",a.id),l.searchParams.set("key",a.publishableKey),l.searchParams.set("client_secret",a.clientSecret),i.theme&&l.searchParams.set("theme",i.theme),y(l.toString(),()=>{let x=i.successUrl})}catch(a){console.error("[Recur] Checkout error:",a),d("recur:error",{message:a instanceof Error?a.message:"Unknown error"})}finally{t.setAttribute("data-loading","false"),t.textContent=c}}function g(){document.querySelectorAll(".recur-button").forEach(t=>{t.hasAttribute("data-recur-initialized")||(t.setAttribute("data-recur-initialized","true"),t.addEventListener("click",r=>P(r,t)))})}function L(){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),r.searchParams.set("client_secret",t.clientSecret),e.theme&&r.searchParams.set("theme",e.theme),y(r.toString())},close(){u()},init(){g()}};function M(){L(),m(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",g):g(),new MutationObserver(t=>{for(let r of t)r.addedNodes.length>0&&g()}).observe(document.body,{childList:!0,subtree:!0})}window.Recur=w;M();var I=w;return U(T);})();
126
134
  /* Recur Checkout - https://recur.tw */
package/dist/index.cjs CHANGED
@@ -1052,6 +1052,124 @@ var init_payment_form_light = __esm({
1052
1052
  }
1053
1053
  });
1054
1054
 
1055
+ // src/utils/checkout-display.ts
1056
+ function formatZhe(basisPoints) {
1057
+ const zhe = (1e4 - basisPoints) / 1e3;
1058
+ if (Number.isInteger(zhe)) return `${zhe} \u6298`;
1059
+ const zhe10 = zhe * 10;
1060
+ if (Number.isInteger(zhe10)) return `${zhe10} \u6298`;
1061
+ return `${(zhe * 10).toFixed(2)} \u6298`;
1062
+ }
1063
+ function getIntervalText(interval, count) {
1064
+ if (!interval) return "";
1065
+ const countText = count && count > 1 ? count.toString() : "";
1066
+ switch (interval.toUpperCase()) {
1067
+ case "MONTH":
1068
+ return `${countText}\u6708`;
1069
+ case "YEAR":
1070
+ return `${countText}\u5E74`;
1071
+ case "WEEK":
1072
+ return `${countText}\u9031`;
1073
+ case "DAY":
1074
+ return `${countText}\u5929`;
1075
+ default:
1076
+ return "";
1077
+ }
1078
+ }
1079
+ function formatPrice(amount) {
1080
+ return `NT$ ${amount.toLocaleString("zh-TW")}`;
1081
+ }
1082
+ function getCheckoutDiscountDisplay(input) {
1083
+ const {
1084
+ discountType,
1085
+ couponDiscountValue,
1086
+ discountAmount,
1087
+ duration,
1088
+ durationMonths,
1089
+ productPrice,
1090
+ productInterval,
1091
+ productIntervalCount,
1092
+ bonusMonths,
1093
+ bonusTrialDays
1094
+ } = input;
1095
+ const intervalText = getIntervalText(productInterval, productIntervalCount);
1096
+ const originalPriceText = intervalText ? `${formatPrice(productPrice)}/${intervalText}` : formatPrice(productPrice);
1097
+ const bonusSuffix = buildBonusSuffix(bonusMonths, bonusTrialDays);
1098
+ if (discountAmount === 0 && (bonusMonths || bonusTrialDays)) {
1099
+ return {
1100
+ line1: buildPureBonusLine(bonusMonths, bonusTrialDays),
1101
+ line2: null
1102
+ };
1103
+ }
1104
+ if (discountAmount === 0) {
1105
+ return { line1: "", line2: null };
1106
+ }
1107
+ const afterLine = `\u4E4B\u5F8C ${originalPriceText}`;
1108
+ if (discountType === "FIRST_PERIOD_PRICE") {
1109
+ const firstPeriodPrice = couponDiscountValue;
1110
+ const priceText = firstPeriodPrice === 0 ? "\u514D\u8CBB" : `\u7279\u50F9 ${formatPrice(firstPeriodPrice)}`;
1111
+ const line1 = bonusSuffix ? `\u9996\u671F${priceText}\uFF0C${bonusSuffix}` : `\u9996\u671F${priceText}`;
1112
+ return { line1, line2: afterLine };
1113
+ }
1114
+ if (discountType === "FIXED_AMOUNT") {
1115
+ return buildStandardDiscount({
1116
+ discountText: `\u6298 ${formatPrice(couponDiscountValue)}`,
1117
+ duration,
1118
+ durationMonths,
1119
+ bonusSuffix,
1120
+ afterLine
1121
+ });
1122
+ }
1123
+ if (discountType === "PERCENTAGE") {
1124
+ return buildStandardDiscount({
1125
+ discountText: `\u4EAB ${formatZhe(couponDiscountValue)}`,
1126
+ duration,
1127
+ durationMonths,
1128
+ bonusSuffix,
1129
+ afterLine
1130
+ });
1131
+ }
1132
+ return { line1: "", line2: null };
1133
+ }
1134
+ function buildStandardDiscount(opts) {
1135
+ const { discountText, duration, durationMonths, bonusSuffix, afterLine } = opts;
1136
+ switch (duration) {
1137
+ case "ONCE": {
1138
+ const base = `\u9996\u671F${discountText}`;
1139
+ const line1 = bonusSuffix ? `${base}\uFF0C${bonusSuffix}` : base;
1140
+ return { line1, line2: afterLine };
1141
+ }
1142
+ case "REPEATING": {
1143
+ const periods = durationMonths ?? 0;
1144
+ const line1 = `\u524D ${periods} \u671F\u6BCF\u671F${discountText}`;
1145
+ return { line1, line2: afterLine };
1146
+ }
1147
+ case "FOREVER": {
1148
+ const line1 = `\u6BCF\u671F${discountText}`;
1149
+ return { line1, line2: null };
1150
+ }
1151
+ default:
1152
+ return { line1: "", line2: null };
1153
+ }
1154
+ }
1155
+ function buildBonusSuffix(bonusMonths, bonusTrialDays) {
1156
+ const parts = [];
1157
+ if (bonusMonths) parts.push(`\u52A0\u9001 ${bonusMonths} \u500B\u6708`);
1158
+ if (bonusTrialDays) parts.push(`\u5EF6\u9577 ${bonusTrialDays} \u5929\u8A66\u7528`);
1159
+ if (parts.length === 0) return null;
1160
+ return `\u4E26${parts.join("\u53CA")}`;
1161
+ }
1162
+ function buildPureBonusLine(bonusMonths, bonusTrialDays) {
1163
+ const parts = [];
1164
+ if (bonusMonths) parts.push(`\u52A0\u9001 ${bonusMonths} \u500B\u6708`);
1165
+ if (bonusTrialDays) parts.push(`\u5EF6\u9577\u8A66\u7528 ${bonusTrialDays} \u5929`);
1166
+ return parts.join("\u53CA");
1167
+ }
1168
+ var init_checkout_display = __esm({
1169
+ "src/utils/checkout-display.ts"() {
1170
+ }
1171
+ });
1172
+
1055
1173
  // src/components/payment-form.ts
1056
1174
  var payment_form_exports = {};
1057
1175
  __export(payment_form_exports, {
@@ -1062,6 +1180,7 @@ var init_payment_form = __esm({
1062
1180
  "src/components/payment-form.ts"() {
1063
1181
  init_payment_form_shadow();
1064
1182
  init_payment_form_light();
1183
+ init_checkout_display();
1065
1184
  icons = {
1066
1185
  lock: litHtml.html`
1067
1186
  <svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -1365,73 +1484,26 @@ var init_payment_form = __esm({
1365
1484
  </div>
1366
1485
  `;
1367
1486
  }
1368
- // Helper to get interval text in Chinese
1369
- getIntervalText(interval, count) {
1370
- if (!interval) return "";
1371
- const countText = count && count > 1 ? count.toString() : "";
1372
- switch (interval.toUpperCase()) {
1373
- case "MONTH":
1374
- return `${countText}\u6708`;
1375
- case "YEAR":
1376
- return `${countText}\u5E74`;
1377
- case "WEEK":
1378
- return `${countText}\u9031`;
1379
- case "DAY":
1380
- return `${countText}\u5929`;
1381
- default:
1382
- return "";
1383
- }
1384
- }
1385
- // Get discount description based on type and duration
1386
- getDiscountDescription() {
1487
+ // Get unified discount display using shared function
1488
+ getDiscountDisplay() {
1387
1489
  if (!this._appliedCoupon) return null;
1388
- const { discountType, duration, durationMonths, productPrice, productInterval, productIntervalCount } = this._appliedCoupon;
1389
- const intervalText = this.getIntervalText(productInterval, productIntervalCount);
1390
- const originalPriceText = productPrice && intervalText ? `NT$ ${productPrice.toLocaleString()}/${intervalText}` : productPrice ? `NT$ ${productPrice.toLocaleString()}` : "";
1391
1490
  const amount = parseInt(this.getAttribute("amount") || "0", 10);
1392
- const finalAmount = amount - this._appliedCoupon.discountAmount;
1393
- if (discountType === "FIRST_PERIOD_PRICE") {
1394
- if (originalPriceText) {
1395
- return `\u9996\u671F\u53EA\u9700 NT$ ${finalAmount.toLocaleString()}\uFF0C\u4E4B\u5F8C ${originalPriceText}`;
1396
- }
1397
- return `\u9996\u671F\u53EA\u9700 NT$ ${finalAmount.toLocaleString()}`;
1398
- }
1399
- if (duration) {
1400
- switch (duration) {
1401
- case "ONCE":
1402
- if (originalPriceText) {
1403
- return `\u9996\u671F\u6298\u6263\uFF0C\u4E4B\u5F8C ${originalPriceText}`;
1404
- }
1405
- return "\u50C5\u9650\u9996\u671F";
1406
- case "REPEATING":
1407
- if (durationMonths) {
1408
- return `\u524D ${durationMonths} \u671F\u4EAB\u512A\u60E0\uFF0C\u4E4B\u5F8C\u6062\u5FA9\u539F\u50F9`;
1409
- }
1410
- return null;
1411
- case "FOREVER":
1412
- return "\u7D42\u8EAB\u512A\u60E0";
1413
- default:
1414
- return null;
1415
- }
1416
- }
1417
- return null;
1418
- }
1419
- // Get bonus description
1420
- getBonusDescription() {
1421
- if (!this._appliedCoupon) return null;
1422
- const parts = [];
1423
- if (this._appliedCoupon.bonusTrialDays) {
1424
- parts.push(`\u5EF6\u9577\u8A66\u7528 ${this._appliedCoupon.bonusTrialDays} \u5929`);
1425
- }
1426
- if (this._appliedCoupon.bonusMonths) {
1427
- parts.push(`\u52A0\u9001 ${this._appliedCoupon.bonusMonths} \u500B\u6708`);
1428
- }
1429
- return parts.length > 0 ? parts.join("\u3001") : null;
1491
+ return getCheckoutDiscountDisplay({
1492
+ discountType: this._appliedCoupon.discountType,
1493
+ couponDiscountValue: this._appliedCoupon.couponDiscountValue,
1494
+ discountAmount: this._appliedCoupon.discountAmount,
1495
+ duration: this._appliedCoupon.duration || "ONCE",
1496
+ durationMonths: this._appliedCoupon.durationMonths,
1497
+ productPrice: this._appliedCoupon.productPrice ?? amount,
1498
+ productInterval: this._appliedCoupon.productInterval,
1499
+ productIntervalCount: this._appliedCoupon.productIntervalCount,
1500
+ bonusMonths: this._appliedCoupon.bonusMonths,
1501
+ bonusTrialDays: this._appliedCoupon.bonusTrialDays
1502
+ });
1430
1503
  }
1431
1504
  renderCoupon() {
1432
1505
  if (this._appliedCoupon) {
1433
- const discountDescription = this.getDiscountDescription();
1434
- const bonusDescription = this.getBonusDescription();
1506
+ const display = this.getDiscountDisplay();
1435
1507
  return litHtml.html`
1436
1508
  <div class="recur-coupon__applied-wrapper">
1437
1509
  <div class="recur-coupon__applied">
@@ -1452,18 +1524,17 @@ var init_payment_form = __esm({
1452
1524
  ${this._couponLoading ? icons.spinner : icons.close}
1453
1525
  </button>
1454
1526
  </div>
1455
- <span class="recur-coupon__applied-amount">
1456
- -NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
1457
- </span>
1527
+ ${this._appliedCoupon.discountAmount > 0 ? litHtml.html`
1528
+ <span class="recur-coupon__applied-amount">
1529
+ -NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
1530
+ </span>
1531
+ ` : litHtml.nothing}
1458
1532
  </div>
1459
- ${discountDescription ? litHtml.html`
1460
- <p class="recur-coupon__description">${discountDescription}</p>
1533
+ ${display?.line1 ? litHtml.html`
1534
+ <p class="recur-coupon__description">${display.line1}</p>
1461
1535
  ` : litHtml.nothing}
1462
- ${bonusDescription ? litHtml.html`
1463
- <div class="recur-coupon__bonus">
1464
- <span>✨</span>
1465
- <span>${bonusDescription}</span>
1466
- </div>
1536
+ ${display?.line2 ? litHtml.html`
1537
+ <p class="recur-coupon__description">${display.line2}</p>
1467
1538
  ` : litHtml.nothing}
1468
1539
  </div>
1469
1540
  `;
@@ -1626,10 +1697,10 @@ var init_payment_form = __esm({
1626
1697
  getCouponAppliedHTML() {
1627
1698
  const coupon = this._appliedCoupon;
1628
1699
  const nameHTML = coupon.couponName ? `<span class="recur-coupon__applied-name">${coupon.couponName}</span><span class="recur-coupon__applied-code">(${coupon.code})</span>` : `<span class="recur-coupon__applied-name">${coupon.code}</span>`;
1629
- const discountDescription = this.getDiscountDescription();
1630
- const bonusDescription = this.getBonusDescription();
1631
- const descriptionHTML = discountDescription ? `<p class="recur-coupon__description">${discountDescription}</p>` : "";
1632
- const bonusHTML = bonusDescription ? `<div class="recur-coupon__bonus"><span>\u2728</span><span>${bonusDescription}</span></div>` : "";
1700
+ const display = this.getDiscountDisplay();
1701
+ const amountHTML = coupon.discountAmount > 0 ? `<span class="recur-coupon__applied-amount">-NT$ ${coupon.discountAmount.toLocaleString()}</span>` : "";
1702
+ const line1HTML = display?.line1 ? `<p class="recur-coupon__description">${display.line1}</p>` : "";
1703
+ const line2HTML = display?.line2 ? `<p class="recur-coupon__description">${display.line2}</p>` : "";
1633
1704
  return `
1634
1705
  <div class="recur-coupon__applied-wrapper">
1635
1706
  <div class="recur-coupon__applied">
@@ -1642,10 +1713,10 @@ var init_payment_form = __esm({
1642
1713
  ${this._couponLoading ? '<span class="recur-coupon__spinner"></span>' : '<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>'}
1643
1714
  </button>
1644
1715
  </div>
1645
- <span class="recur-coupon__applied-amount">-NT$ ${coupon.discountAmount.toLocaleString()}</span>
1716
+ ${amountHTML}
1646
1717
  </div>
1647
- ${descriptionHTML}
1648
- ${bonusHTML}
1718
+ ${line1HTML}
1719
+ ${line2HTML}
1649
1720
  </div>
1650
1721
  `;
1651
1722
  }
@@ -1717,6 +1788,7 @@ var init_payment_form = __esm({
1717
1788
  couponName: data.discount.coupon_name,
1718
1789
  discountType: data.discount.discount_type,
1719
1790
  discountAmount: data.discount.discount_amount,
1791
+ couponDiscountValue: data.discount.coupon_discount_value ?? data.discount.discount_amount,
1720
1792
  duration: data.discount.duration,
1721
1793
  durationMonths: data.discount.duration_months,
1722
1794
  bonusTrialDays: data.discount.bonus_trial_days,
@@ -2742,7 +2814,7 @@ function toCamelCase(obj) {
2742
2814
 
2743
2815
  // package.json
2744
2816
  var package_default = {
2745
- version: "0.13.1"};
2817
+ version: "0.13.2"};
2746
2818
  var SDK_VERSION = package_default.version;
2747
2819
  var SDK_TYPE = "react";
2748
2820
  var RecurContext = React.createContext(null);
@@ -2961,6 +3033,8 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
2961
3033
  dialog.className = "recur-sdk__dialog";
2962
3034
  dialogContent = document.createElement("div");
2963
3035
  dialogContent.className = "recur-sdk__dialog-content";
3036
+ dialogContent.setAttribute("tabindex", "-1");
3037
+ dialogContent.setAttribute("autofocus", "");
2964
3038
  dialogContent.style.cssText = `
2965
3039
  max-width: 500px;
2966
3040
  width: 100%;
@@ -2971,6 +3045,7 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
2971
3045
  border-radius: 12px;
2972
3046
  background: white;
2973
3047
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
3048
+ outline: none;
2974
3049
  `;
2975
3050
  const closeButton = document.createElement("button");
2976
3051
  closeButton.className = "recur-sdk__close-button";
@@ -3090,7 +3165,8 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
3090
3165
  tokenExpired: checkoutResult.sdkTokenExpiresAt,
3091
3166
  creditToken: "",
3092
3167
  // No longer needed - creditHash stored in database
3093
- environment: checkoutResult.livemode ? "PRODUCTION" : "SANDBOX"
3168
+ environment: "SANDBOX"
3169
+ // Will be determined by organization settings
3094
3170
  };
3095
3171
  console.log("[Recur SDK] SDK token extracted:", {
3096
3172
  sdkToken: tokenResult.sdkToken.substring(0, 20) + "...",
package/dist/index.d.cts CHANGED
@@ -357,11 +357,6 @@ interface CheckoutResult {
357
357
  * Used internally for subscription credit binding
358
358
  */
359
359
  sdkTimestamp?: number;
360
- /**
361
- * Whether the checkout is in live mode (production)
362
- * false = sandbox, true = production
363
- */
364
- livemode: boolean;
365
360
  }
366
361
  /**
367
362
  * Payment failure codes from payment provider
@@ -934,9 +929,7 @@ declare class RecurPaymentForm extends HTMLElement {
934
929
  private isTestMode;
935
930
  private renderTestCardHints;
936
931
  private renderOrderSummary;
937
- private getIntervalText;
938
- private getDiscountDescription;
939
- private getBonusDescription;
932
+ private getDiscountDisplay;
940
933
  private renderCoupon;
941
934
  private showCouponInput;
942
935
  private cancelCouponInput;
@@ -962,6 +955,7 @@ declare class RecurPaymentForm extends HTMLElement {
962
955
  couponName: string;
963
956
  discountType: string;
964
957
  discountAmount: number;
958
+ couponDiscountValue: number;
965
959
  duration?: string;
966
960
  durationMonths?: number;
967
961
  bonusTrialDays?: number;
package/dist/index.d.ts CHANGED
@@ -357,11 +357,6 @@ interface CheckoutResult {
357
357
  * Used internally for subscription credit binding
358
358
  */
359
359
  sdkTimestamp?: number;
360
- /**
361
- * Whether the checkout is in live mode (production)
362
- * false = sandbox, true = production
363
- */
364
- livemode: boolean;
365
360
  }
366
361
  /**
367
362
  * Payment failure codes from payment provider
@@ -934,9 +929,7 @@ declare class RecurPaymentForm extends HTMLElement {
934
929
  private isTestMode;
935
930
  private renderTestCardHints;
936
931
  private renderOrderSummary;
937
- private getIntervalText;
938
- private getDiscountDescription;
939
- private getBonusDescription;
932
+ private getDiscountDisplay;
940
933
  private renderCoupon;
941
934
  private showCouponInput;
942
935
  private cancelCouponInput;
@@ -962,6 +955,7 @@ declare class RecurPaymentForm extends HTMLElement {
962
955
  couponName: string;
963
956
  discountType: string;
964
957
  discountAmount: number;
958
+ couponDiscountValue: number;
965
959
  duration?: string;
966
960
  durationMonths?: number;
967
961
  bonusTrialDays?: number;