recur-tw 0.9.11 → 0.9.12

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 CHANGED
@@ -657,11 +657,11 @@ var init_payment_form_skeleton2 = __esm({
657
657
  <h3 class="section-title">訂單摘要</h3>
658
658
  <div class="order-summary">
659
659
  <div class="order-row">
660
- <span class="order-label">訂閱方案</span>
661
- <div class="skeleton skeleton-order-value"></div>
660
+ <span class="order-label">方案</span>
661
+ <div class="skeleton skeleton-order-value" style="width: 120px;"></div>
662
662
  </div>
663
663
  <div class="order-row">
664
- <span class="order-label">計費週期</span>
664
+ <span class="order-label">小計</span>
665
665
  <div class="skeleton skeleton-order-value"></div>
666
666
  </div>
667
667
  <div class="coupon-section">
@@ -1035,7 +1035,7 @@ var init_payment_form_shadow = __esm({
1035
1035
  var payment_form_light_default;
1036
1036
  var init_payment_form_light = __esm({
1037
1037
  "src/components/styles/payment-form-light.css"() {
1038
- payment_form_light_default = "/**\n * Payment Form - Light DOM Styles\n * These styles are applied to slotted content in the Light DOM\n * Using BEM naming convention with 'recur-' prefix for isolation\n */\n\n/* ============================================\n * Order Summary Styles\n * ============================================ */\n.recur-order-summary {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n padding: 16px;\n}\n\n.recur-order-summary__row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.recur-order-summary__row--total {\n margin-bottom: 0;\n padding-top: 12px;\n border-top: 1px solid #e2e8f0;\n}\n\n.recur-order-summary__label {\n font-size: 14px;\n color: #4a5568;\n}\n\n.recur-order-summary__value {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: #2d3748;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n.recur-order-summary__total {\n font-size: 18px;\n line-height: 26px;\n font-weight: 700;\n color: #1a202c;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n/* ============================================\n * Coupon Section Styles\n * ============================================ */\n.recur-coupon {\n padding: 12px 0;\n border-top: 1px solid #e2e8f0;\n margin-top: 12px;\n min-height: 36px;\n display: flex;\n align-items: center;\n}\n\n.recur-coupon__trigger {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n height: 36px;\n background: none;\n border: none;\n padding: 0;\n font-size: 14px;\n line-height: 1;\n color: #718096;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.recur-coupon__trigger:hover {\n color: #4a5568;\n}\n\n.recur-coupon__trigger-icon {\n width: 16px;\n height: 16px;\n}\n\n.recur-coupon__input-row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__input {\n flex: 1;\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n text-transform: uppercase;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n outline: none;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.recur-coupon__input::placeholder {\n text-transform: none;\n}\n\n.recur-coupon__input:focus {\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.recur-coupon__btn {\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s, opacity 0.2s;\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.recur-coupon__btn--apply {\n background: #18181b;\n color: white;\n border: none;\n min-width: 52px;\n}\n\n.recur-coupon__btn--apply .recur-coupon__spinner {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__btn--apply:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-coupon__btn--apply:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.recur-coupon__btn--cancel {\n background: transparent;\n color: #718096;\n border: 1px solid #d1d5db;\n}\n\n.recur-coupon__btn--cancel:hover {\n background: #f7fafc;\n}\n\n.recur-coupon__error {\n width: 100%;\n margin-top: 8px;\n font-size: 13px;\n color: #dc2626;\n}\n\n.recur-coupon__applied {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__applied-info {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n flex: 1;\n}\n\n.recur-coupon__applied-icon {\n width: 16px;\n height: 16px;\n color: #dc2626;\n flex-shrink: 0;\n}\n\n.recur-coupon__applied-name {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n}\n\n.recur-coupon__applied-code {\n font-size: 14px;\n color: #9ca3af;\n white-space: nowrap;\n margin-right: 2px;\n}\n\n.recur-coupon__applied-amount {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.recur-coupon__remove {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #9ca3af;\n border-radius: 4px;\n transition: color 0.2s, background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.recur-coupon__remove:hover {\n color: #6b7280;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.recur-coupon__remove-icon {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__spinner {\n width: 14px;\n height: 14px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n/* Discount Row */\n.recur-order-summary__row--discount {\n color: #16a34a;\n}\n\n.recur-order-summary__row--discount .recur-order-summary__value {\n color: #16a34a;\n font-weight: 500;\n}\n\n/* ============================================\n * Customer Info Styles\n * ============================================ */\n.recur-info-display {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 8px;\n}\n\n.recur-info-row {\n margin-bottom: 12px;\n}\n\n.recur-info-row:last-child {\n margin-bottom: 0;\n}\n\n.recur-info-label {\n display: block;\n font-size: 12px;\n line-height: 16px;\n color: #718096;\n margin-bottom: 2px;\n}\n\n.recur-info-value {\n display: block;\n font-size: 14px;\n line-height: 20px;\n min-height: 20px;\n color: #2d3748;\n font-weight: 500;\n word-break: break-all;\n}\n\n.recur-form-group {\n margin-bottom: 16px;\n}\n\n.recur-form-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-form-input {\n width: 100%;\n padding: 10px 12px;\n font-size: 16px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n transition: border-color 0.2s;\n box-sizing: border-box;\n}\n\n.recur-form-input:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.recur-form-input:hover:not(:focus) {\n border-color: #9ca3af;\n}\n\n/* ============================================\n * Card Fields Styles\n * ============================================ */\n.recur-card-field {\n margin-bottom: 16px;\n}\n\n.recur-card-field-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-payuni-iframe {\n height: 36px;\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n touch-action: manipulation;\n}\n\n.recur-card-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n column-gap: 16px;\n max-width: 100%;\n box-sizing: border-box;\n}\n\n.recur-card-field-container {\n position: relative;\n touch-action: manipulation;\n}\n\n.recur-card-skeleton {\n position: absolute;\n top: 0;\n left: 0;\n height: 36px;\n width: 100%;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n z-index: 1;\n pointer-events: none;\n}\n\n.recur-card-skeleton.hidden {\n display: none;\n}\n\n@keyframes recur-skeleton-loading {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ============================================\n * Submit Button Styles\n * ============================================ */\n.recur-submit-button {\n width: 100%;\n padding: 14px 20px;\n font-size: 16px;\n font-weight: 500;\n color: #ffffff;\n background: #18181b;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n box-sizing: border-box;\n}\n\n.recur-submit-button:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-submit-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.recur-submit-button.loading {\n cursor: wait;\n}\n\n.recur-loading-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n@keyframes recur-spin {\n to { transform: rotate(360deg); }\n}\n\n/* ============================================\n * Skeleton Loading Styles\n * ============================================ */\n.recur-skeleton {\n display: inline-block;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n}\n";
1038
+ payment_form_light_default = "/**\n * Payment Form - Light DOM Styles\n * These styles are applied to slotted content in the Light DOM\n * Using BEM naming convention with 'recur-' prefix for isolation\n */\n\n/* ============================================\n * Order Summary Styles\n * ============================================ */\n.recur-order-summary {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n padding: 16px;\n}\n\n.recur-order-summary__row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.recur-order-summary__row--total {\n margin-bottom: 0;\n padding-top: 12px;\n border-top: 1px solid #e2e8f0;\n}\n\n.recur-order-summary__label {\n font-size: 14px;\n color: #4a5568;\n}\n\n.recur-order-summary__value {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: #2d3748;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n.recur-order-summary__total {\n font-size: 18px;\n line-height: 26px;\n font-weight: 700;\n color: #1a202c;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n/* ============================================\n * Coupon Section Styles\n * ============================================ */\n.recur-coupon {\n padding: 12px 0;\n border-top: 1px solid #e2e8f0;\n margin-top: 12px;\n min-height: 36px;\n display: flex;\n align-items: center;\n}\n\n.recur-coupon__trigger {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n height: 36px;\n background: none;\n border: none;\n padding: 0;\n font-size: 14px;\n line-height: 1;\n color: #718096;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.recur-coupon__trigger:hover {\n color: #4a5568;\n}\n\n.recur-coupon__trigger-icon {\n width: 16px;\n height: 16px;\n}\n\n.recur-coupon__input-row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__input {\n flex: 1;\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n text-transform: uppercase;\n background-color: #ffffff;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n outline: none;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.recur-coupon__input::placeholder {\n text-transform: none;\n}\n\n.recur-coupon__input:hover:not(:focus) {\n border-color: #9ca3af;\n}\n\n.recur-coupon__input:focus {\n border-color: var(--ring, hsl(215 16% 47%));\n outline: 0;\n box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent);\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n.recur-coupon__btn {\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s, opacity 0.2s;\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.recur-coupon__btn--apply {\n background: #18181b;\n color: white;\n border: none;\n min-width: 52px;\n}\n\n.recur-coupon__btn--apply .recur-coupon__spinner {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__btn--apply:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-coupon__btn--apply:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.recur-coupon__btn--cancel {\n background: transparent;\n color: #718096;\n border: 1px solid #d1d5db;\n}\n\n.recur-coupon__btn--cancel:hover {\n background: #f7fafc;\n}\n\n.recur-coupon__error {\n width: 100%;\n margin-top: 8px;\n font-size: 13px;\n color: #dc2626;\n}\n\n.recur-coupon__applied {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__applied-info {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n flex: 1;\n}\n\n.recur-coupon__applied-icon {\n width: 16px;\n height: 16px;\n color: #dc2626;\n flex-shrink: 0;\n}\n\n.recur-coupon__applied-name {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n}\n\n.recur-coupon__applied-code {\n font-size: 14px;\n color: #9ca3af;\n white-space: nowrap;\n margin-right: 2px;\n}\n\n.recur-coupon__applied-amount {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.recur-coupon__remove {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #9ca3af;\n border-radius: 4px;\n transition: color 0.2s, background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.recur-coupon__remove:hover {\n color: #6b7280;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.recur-coupon__remove-icon {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__spinner {\n width: 14px;\n height: 14px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n/* Discount Row */\n.recur-order-summary__row--discount {\n color: #16a34a;\n}\n\n.recur-order-summary__row--discount .recur-order-summary__value {\n color: #16a34a;\n font-weight: 500;\n}\n\n/* ============================================\n * Customer Info Styles\n * ============================================ */\n.recur-info-display {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 8px;\n}\n\n.recur-info-row {\n margin-bottom: 12px;\n}\n\n.recur-info-row:last-child {\n margin-bottom: 0;\n}\n\n.recur-info-label {\n display: block;\n font-size: 12px;\n line-height: 16px;\n color: #718096;\n margin-bottom: 2px;\n}\n\n.recur-info-value {\n display: block;\n font-size: 14px;\n line-height: 20px;\n min-height: 20px;\n color: #2d3748;\n font-weight: 500;\n word-break: break-all;\n}\n\n.recur-form-group {\n margin-bottom: 16px;\n}\n\n.recur-form-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-form-input {\n width: 100%;\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n transition: border-color 0.2s;\n box-sizing: border-box;\n}\n\n.recur-form-input:focus {\n border-color: var(--ring, hsl(215 16% 47%));\n outline: 0;\n box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent);\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n.recur-form-input:hover:not(:focus) {\n border-color: #9ca3af;\n}\n\n/* ============================================\n * Card Fields Styles\n * ============================================ */\n.recur-card-field {\n margin-bottom: 16px;\n}\n\n.recur-card-field-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-payuni-iframe {\n height: 36px;\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n touch-action: manipulation;\n}\n\n.recur-card-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n column-gap: 16px;\n max-width: 100%;\n box-sizing: border-box;\n}\n\n.recur-card-field-container {\n position: relative;\n touch-action: manipulation;\n}\n\n.recur-card-skeleton {\n position: absolute;\n top: 0;\n left: 0;\n height: 36px;\n width: 100%;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n z-index: 1;\n pointer-events: none;\n}\n\n.recur-card-skeleton.hidden {\n display: none;\n}\n\n@keyframes recur-skeleton-loading {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ============================================\n * Submit Button Styles\n * ============================================ */\n.recur-submit-button {\n width: 100%;\n padding: 14px 20px;\n font-size: 16px;\n font-weight: 500;\n color: #ffffff;\n background: #18181b;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n box-sizing: border-box;\n}\n\n.recur-submit-button:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-submit-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.recur-submit-button.loading {\n cursor: wait;\n}\n\n.recur-loading-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n@keyframes recur-spin {\n to { transform: rotate(360deg); }\n}\n\n/* ============================================\n * Skeleton Loading Styles\n * ============================================ */\n.recur-skeleton {\n display: inline-block;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n}\n";
1039
1039
  }
1040
1040
  });
1041
1041
 
@@ -1224,19 +1224,12 @@ var init_payment_form = __esm({
1224
1224
  const amount = this.getAttribute("amount");
1225
1225
  const interval = this.getAttribute("interval");
1226
1226
  if (!productName || !amount) {
1227
- const isSubscription2 = !!interval;
1228
1227
  return litHtml.html`
1229
1228
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1230
1229
  <div class="recur-order-summary__row">
1231
- <span class="recur-order-summary__label">${isSubscription2 ? "\u8A02\u95B1\u65B9\u6848" : "\u5546\u54C1"}</span>
1232
- <span class="recur-order-summary__value recur-skeleton" style="width: 100px; height: 20px;"></span>
1230
+ <span class="recur-order-summary__label">方案</span>
1231
+ <span class="recur-order-summary__value recur-skeleton" style="width: 120px; height: 20px;"></span>
1233
1232
  </div>
1234
- ${isSubscription2 ? litHtml.html`
1235
- <div class="recur-order-summary__row">
1236
- <span class="recur-order-summary__label">計費週期</span>
1237
- <span class="recur-order-summary__value recur-skeleton" style="width: 40px; height: 20px;"></span>
1238
- </div>
1239
- ` : litHtml.nothing}
1240
1233
  <div class="recur-order-summary__row">
1241
1234
  <span class="recur-order-summary__label">小計</span>
1242
1235
  <span class="recur-order-summary__value recur-skeleton" style="width: 80px; height: 20px;"></span>
@@ -1261,21 +1254,14 @@ var init_payment_form = __esm({
1261
1254
  const originalAmount = Number(amount);
1262
1255
  const discountAmount = this._appliedCoupon?.discountAmount || 0;
1263
1256
  const finalAmount = originalAmount - discountAmount;
1264
- const isSubscription = !!periodText;
1257
+ const productDisplay = periodText ? `${productName} / \u6BCF${periodText}` : productName;
1265
1258
  return litHtml.html`
1266
1259
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1267
1260
  <div class="recur-order-summary__row">
1268
- <span class="recur-order-summary__label">${isSubscription ? "\u8A02\u95B1\u65B9\u6848" : "\u5546\u54C1"}</span>
1269
- <span class="recur-order-summary__value">${productName}</span>
1261
+ <span class="recur-order-summary__label">方案</span>
1262
+ <span class="recur-order-summary__value">${productDisplay}</span>
1270
1263
  </div>
1271
1264
 
1272
- ${isSubscription ? litHtml.html`
1273
- <div class="recur-order-summary__row">
1274
- <span class="recur-order-summary__label">計費週期</span>
1275
- <span class="recur-order-summary__value">每${periodText}</span>
1276
- </div>
1277
- ` : litHtml.nothing}
1278
-
1279
1265
  <!-- 小計 (Subtotal) - always show -->
1280
1266
  <div class="recur-order-summary__row">
1281
1267
  <span class="recur-order-summary__label">小計</span>
@@ -2560,7 +2546,7 @@ function toCamelCase(obj) {
2560
2546
 
2561
2547
  // package.json
2562
2548
  var package_default = {
2563
- version: "0.9.11"};
2549
+ version: "0.9.12"};
2564
2550
  var SDK_VERSION = package_default.version;
2565
2551
  var SDK_TYPE = "react";
2566
2552
  var RecurContext = React.createContext(null);
@@ -2896,7 +2882,6 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2896
2882
  paymentForm.setAttribute("interval", checkoutResult.product.interval);
2897
2883
  }
2898
2884
  const customStyles = `
2899
- /* PAYUNi SDK focus \u6A23\u5F0F - shadcn \u98A8\u683C */
2900
2885
  .form-input-focus {
2901
2886
  border-color: var(--ring, hsl(215 16% 47%)) !important;
2902
2887
  outline: 0 !important;
package/dist/index.js CHANGED
@@ -651,11 +651,11 @@ var init_payment_form_skeleton2 = __esm({
651
651
  <h3 class="section-title">訂單摘要</h3>
652
652
  <div class="order-summary">
653
653
  <div class="order-row">
654
- <span class="order-label">訂閱方案</span>
655
- <div class="skeleton skeleton-order-value"></div>
654
+ <span class="order-label">方案</span>
655
+ <div class="skeleton skeleton-order-value" style="width: 120px;"></div>
656
656
  </div>
657
657
  <div class="order-row">
658
- <span class="order-label">計費週期</span>
658
+ <span class="order-label">小計</span>
659
659
  <div class="skeleton skeleton-order-value"></div>
660
660
  </div>
661
661
  <div class="coupon-section">
@@ -1029,7 +1029,7 @@ var init_payment_form_shadow = __esm({
1029
1029
  var payment_form_light_default;
1030
1030
  var init_payment_form_light = __esm({
1031
1031
  "src/components/styles/payment-form-light.css"() {
1032
- payment_form_light_default = "/**\n * Payment Form - Light DOM Styles\n * These styles are applied to slotted content in the Light DOM\n * Using BEM naming convention with 'recur-' prefix for isolation\n */\n\n/* ============================================\n * Order Summary Styles\n * ============================================ */\n.recur-order-summary {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n padding: 16px;\n}\n\n.recur-order-summary__row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.recur-order-summary__row--total {\n margin-bottom: 0;\n padding-top: 12px;\n border-top: 1px solid #e2e8f0;\n}\n\n.recur-order-summary__label {\n font-size: 14px;\n color: #4a5568;\n}\n\n.recur-order-summary__value {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: #2d3748;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n.recur-order-summary__total {\n font-size: 18px;\n line-height: 26px;\n font-weight: 700;\n color: #1a202c;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n/* ============================================\n * Coupon Section Styles\n * ============================================ */\n.recur-coupon {\n padding: 12px 0;\n border-top: 1px solid #e2e8f0;\n margin-top: 12px;\n min-height: 36px;\n display: flex;\n align-items: center;\n}\n\n.recur-coupon__trigger {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n height: 36px;\n background: none;\n border: none;\n padding: 0;\n font-size: 14px;\n line-height: 1;\n color: #718096;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.recur-coupon__trigger:hover {\n color: #4a5568;\n}\n\n.recur-coupon__trigger-icon {\n width: 16px;\n height: 16px;\n}\n\n.recur-coupon__input-row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__input {\n flex: 1;\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n text-transform: uppercase;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n outline: none;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.recur-coupon__input::placeholder {\n text-transform: none;\n}\n\n.recur-coupon__input:focus {\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.recur-coupon__btn {\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s, opacity 0.2s;\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.recur-coupon__btn--apply {\n background: #18181b;\n color: white;\n border: none;\n min-width: 52px;\n}\n\n.recur-coupon__btn--apply .recur-coupon__spinner {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__btn--apply:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-coupon__btn--apply:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.recur-coupon__btn--cancel {\n background: transparent;\n color: #718096;\n border: 1px solid #d1d5db;\n}\n\n.recur-coupon__btn--cancel:hover {\n background: #f7fafc;\n}\n\n.recur-coupon__error {\n width: 100%;\n margin-top: 8px;\n font-size: 13px;\n color: #dc2626;\n}\n\n.recur-coupon__applied {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__applied-info {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n flex: 1;\n}\n\n.recur-coupon__applied-icon {\n width: 16px;\n height: 16px;\n color: #dc2626;\n flex-shrink: 0;\n}\n\n.recur-coupon__applied-name {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n}\n\n.recur-coupon__applied-code {\n font-size: 14px;\n color: #9ca3af;\n white-space: nowrap;\n margin-right: 2px;\n}\n\n.recur-coupon__applied-amount {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.recur-coupon__remove {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #9ca3af;\n border-radius: 4px;\n transition: color 0.2s, background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.recur-coupon__remove:hover {\n color: #6b7280;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.recur-coupon__remove-icon {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__spinner {\n width: 14px;\n height: 14px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n/* Discount Row */\n.recur-order-summary__row--discount {\n color: #16a34a;\n}\n\n.recur-order-summary__row--discount .recur-order-summary__value {\n color: #16a34a;\n font-weight: 500;\n}\n\n/* ============================================\n * Customer Info Styles\n * ============================================ */\n.recur-info-display {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 8px;\n}\n\n.recur-info-row {\n margin-bottom: 12px;\n}\n\n.recur-info-row:last-child {\n margin-bottom: 0;\n}\n\n.recur-info-label {\n display: block;\n font-size: 12px;\n line-height: 16px;\n color: #718096;\n margin-bottom: 2px;\n}\n\n.recur-info-value {\n display: block;\n font-size: 14px;\n line-height: 20px;\n min-height: 20px;\n color: #2d3748;\n font-weight: 500;\n word-break: break-all;\n}\n\n.recur-form-group {\n margin-bottom: 16px;\n}\n\n.recur-form-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-form-input {\n width: 100%;\n padding: 10px 12px;\n font-size: 16px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n transition: border-color 0.2s;\n box-sizing: border-box;\n}\n\n.recur-form-input:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.recur-form-input:hover:not(:focus) {\n border-color: #9ca3af;\n}\n\n/* ============================================\n * Card Fields Styles\n * ============================================ */\n.recur-card-field {\n margin-bottom: 16px;\n}\n\n.recur-card-field-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-payuni-iframe {\n height: 36px;\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n touch-action: manipulation;\n}\n\n.recur-card-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n column-gap: 16px;\n max-width: 100%;\n box-sizing: border-box;\n}\n\n.recur-card-field-container {\n position: relative;\n touch-action: manipulation;\n}\n\n.recur-card-skeleton {\n position: absolute;\n top: 0;\n left: 0;\n height: 36px;\n width: 100%;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n z-index: 1;\n pointer-events: none;\n}\n\n.recur-card-skeleton.hidden {\n display: none;\n}\n\n@keyframes recur-skeleton-loading {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ============================================\n * Submit Button Styles\n * ============================================ */\n.recur-submit-button {\n width: 100%;\n padding: 14px 20px;\n font-size: 16px;\n font-weight: 500;\n color: #ffffff;\n background: #18181b;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n box-sizing: border-box;\n}\n\n.recur-submit-button:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-submit-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.recur-submit-button.loading {\n cursor: wait;\n}\n\n.recur-loading-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n@keyframes recur-spin {\n to { transform: rotate(360deg); }\n}\n\n/* ============================================\n * Skeleton Loading Styles\n * ============================================ */\n.recur-skeleton {\n display: inline-block;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n}\n";
1032
+ payment_form_light_default = "/**\n * Payment Form - Light DOM Styles\n * These styles are applied to slotted content in the Light DOM\n * Using BEM naming convention with 'recur-' prefix for isolation\n */\n\n/* ============================================\n * Order Summary Styles\n * ============================================ */\n.recur-order-summary {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n padding: 16px;\n}\n\n.recur-order-summary__row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.recur-order-summary__row--total {\n margin-bottom: 0;\n padding-top: 12px;\n border-top: 1px solid #e2e8f0;\n}\n\n.recur-order-summary__label {\n font-size: 14px;\n color: #4a5568;\n}\n\n.recur-order-summary__value {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: #2d3748;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n.recur-order-summary__total {\n font-size: 18px;\n line-height: 26px;\n font-weight: 700;\n color: #1a202c;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n/* ============================================\n * Coupon Section Styles\n * ============================================ */\n.recur-coupon {\n padding: 12px 0;\n border-top: 1px solid #e2e8f0;\n margin-top: 12px;\n min-height: 36px;\n display: flex;\n align-items: center;\n}\n\n.recur-coupon__trigger {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n height: 36px;\n background: none;\n border: none;\n padding: 0;\n font-size: 14px;\n line-height: 1;\n color: #718096;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.recur-coupon__trigger:hover {\n color: #4a5568;\n}\n\n.recur-coupon__trigger-icon {\n width: 16px;\n height: 16px;\n}\n\n.recur-coupon__input-row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__input {\n flex: 1;\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n text-transform: uppercase;\n background-color: #ffffff;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n outline: none;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.recur-coupon__input::placeholder {\n text-transform: none;\n}\n\n.recur-coupon__input:hover:not(:focus) {\n border-color: #9ca3af;\n}\n\n.recur-coupon__input:focus {\n border-color: var(--ring, hsl(215 16% 47%));\n outline: 0;\n box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent);\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n.recur-coupon__btn {\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s, opacity 0.2s;\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.recur-coupon__btn--apply {\n background: #18181b;\n color: white;\n border: none;\n min-width: 52px;\n}\n\n.recur-coupon__btn--apply .recur-coupon__spinner {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__btn--apply:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-coupon__btn--apply:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.recur-coupon__btn--cancel {\n background: transparent;\n color: #718096;\n border: 1px solid #d1d5db;\n}\n\n.recur-coupon__btn--cancel:hover {\n background: #f7fafc;\n}\n\n.recur-coupon__error {\n width: 100%;\n margin-top: 8px;\n font-size: 13px;\n color: #dc2626;\n}\n\n.recur-coupon__applied {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__applied-info {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n flex: 1;\n}\n\n.recur-coupon__applied-icon {\n width: 16px;\n height: 16px;\n color: #dc2626;\n flex-shrink: 0;\n}\n\n.recur-coupon__applied-name {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n}\n\n.recur-coupon__applied-code {\n font-size: 14px;\n color: #9ca3af;\n white-space: nowrap;\n margin-right: 2px;\n}\n\n.recur-coupon__applied-amount {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.recur-coupon__remove {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #9ca3af;\n border-radius: 4px;\n transition: color 0.2s, background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.recur-coupon__remove:hover {\n color: #6b7280;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.recur-coupon__remove-icon {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__spinner {\n width: 14px;\n height: 14px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n/* Discount Row */\n.recur-order-summary__row--discount {\n color: #16a34a;\n}\n\n.recur-order-summary__row--discount .recur-order-summary__value {\n color: #16a34a;\n font-weight: 500;\n}\n\n/* ============================================\n * Customer Info Styles\n * ============================================ */\n.recur-info-display {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 8px;\n}\n\n.recur-info-row {\n margin-bottom: 12px;\n}\n\n.recur-info-row:last-child {\n margin-bottom: 0;\n}\n\n.recur-info-label {\n display: block;\n font-size: 12px;\n line-height: 16px;\n color: #718096;\n margin-bottom: 2px;\n}\n\n.recur-info-value {\n display: block;\n font-size: 14px;\n line-height: 20px;\n min-height: 20px;\n color: #2d3748;\n font-weight: 500;\n word-break: break-all;\n}\n\n.recur-form-group {\n margin-bottom: 16px;\n}\n\n.recur-form-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-form-input {\n width: 100%;\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n transition: border-color 0.2s;\n box-sizing: border-box;\n}\n\n.recur-form-input:focus {\n border-color: var(--ring, hsl(215 16% 47%));\n outline: 0;\n box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent);\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n.recur-form-input:hover:not(:focus) {\n border-color: #9ca3af;\n}\n\n/* ============================================\n * Card Fields Styles\n * ============================================ */\n.recur-card-field {\n margin-bottom: 16px;\n}\n\n.recur-card-field-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-payuni-iframe {\n height: 36px;\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n touch-action: manipulation;\n}\n\n.recur-card-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n column-gap: 16px;\n max-width: 100%;\n box-sizing: border-box;\n}\n\n.recur-card-field-container {\n position: relative;\n touch-action: manipulation;\n}\n\n.recur-card-skeleton {\n position: absolute;\n top: 0;\n left: 0;\n height: 36px;\n width: 100%;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n z-index: 1;\n pointer-events: none;\n}\n\n.recur-card-skeleton.hidden {\n display: none;\n}\n\n@keyframes recur-skeleton-loading {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ============================================\n * Submit Button Styles\n * ============================================ */\n.recur-submit-button {\n width: 100%;\n padding: 14px 20px;\n font-size: 16px;\n font-weight: 500;\n color: #ffffff;\n background: #18181b;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n box-sizing: border-box;\n}\n\n.recur-submit-button:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-submit-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.recur-submit-button.loading {\n cursor: wait;\n}\n\n.recur-loading-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n@keyframes recur-spin {\n to { transform: rotate(360deg); }\n}\n\n/* ============================================\n * Skeleton Loading Styles\n * ============================================ */\n.recur-skeleton {\n display: inline-block;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n}\n";
1033
1033
  }
1034
1034
  });
1035
1035
 
@@ -1218,19 +1218,12 @@ var init_payment_form = __esm({
1218
1218
  const amount = this.getAttribute("amount");
1219
1219
  const interval = this.getAttribute("interval");
1220
1220
  if (!productName || !amount) {
1221
- const isSubscription2 = !!interval;
1222
1221
  return html`
1223
1222
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1224
1223
  <div class="recur-order-summary__row">
1225
- <span class="recur-order-summary__label">${isSubscription2 ? "\u8A02\u95B1\u65B9\u6848" : "\u5546\u54C1"}</span>
1226
- <span class="recur-order-summary__value recur-skeleton" style="width: 100px; height: 20px;"></span>
1224
+ <span class="recur-order-summary__label">方案</span>
1225
+ <span class="recur-order-summary__value recur-skeleton" style="width: 120px; height: 20px;"></span>
1227
1226
  </div>
1228
- ${isSubscription2 ? html`
1229
- <div class="recur-order-summary__row">
1230
- <span class="recur-order-summary__label">計費週期</span>
1231
- <span class="recur-order-summary__value recur-skeleton" style="width: 40px; height: 20px;"></span>
1232
- </div>
1233
- ` : nothing}
1234
1227
  <div class="recur-order-summary__row">
1235
1228
  <span class="recur-order-summary__label">小計</span>
1236
1229
  <span class="recur-order-summary__value recur-skeleton" style="width: 80px; height: 20px;"></span>
@@ -1255,21 +1248,14 @@ var init_payment_form = __esm({
1255
1248
  const originalAmount = Number(amount);
1256
1249
  const discountAmount = this._appliedCoupon?.discountAmount || 0;
1257
1250
  const finalAmount = originalAmount - discountAmount;
1258
- const isSubscription = !!periodText;
1251
+ const productDisplay = periodText ? `${productName} / \u6BCF${periodText}` : productName;
1259
1252
  return html`
1260
1253
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1261
1254
  <div class="recur-order-summary__row">
1262
- <span class="recur-order-summary__label">${isSubscription ? "\u8A02\u95B1\u65B9\u6848" : "\u5546\u54C1"}</span>
1263
- <span class="recur-order-summary__value">${productName}</span>
1255
+ <span class="recur-order-summary__label">方案</span>
1256
+ <span class="recur-order-summary__value">${productDisplay}</span>
1264
1257
  </div>
1265
1258
 
1266
- ${isSubscription ? html`
1267
- <div class="recur-order-summary__row">
1268
- <span class="recur-order-summary__label">計費週期</span>
1269
- <span class="recur-order-summary__value">每${periodText}</span>
1270
- </div>
1271
- ` : nothing}
1272
-
1273
1259
  <!-- 小計 (Subtotal) - always show -->
1274
1260
  <div class="recur-order-summary__row">
1275
1261
  <span class="recur-order-summary__label">小計</span>
@@ -2554,7 +2540,7 @@ function toCamelCase(obj) {
2554
2540
 
2555
2541
  // package.json
2556
2542
  var package_default = {
2557
- version: "0.9.11"};
2543
+ version: "0.9.12"};
2558
2544
  var SDK_VERSION = package_default.version;
2559
2545
  var SDK_TYPE = "react";
2560
2546
  var RecurContext = createContext(null);
@@ -2890,7 +2876,6 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2890
2876
  paymentForm.setAttribute("interval", checkoutResult.product.interval);
2891
2877
  }
2892
2878
  const customStyles = `
2893
- /* PAYUNi SDK focus \u6A23\u5F0F - shadcn \u98A8\u683C */
2894
2879
  .form-input-focus {
2895
2880
  border-color: var(--ring, hsl(215 16% 47%)) !important;
2896
2881
  outline: 0 !important;
package/dist/recur.umd.js CHANGED
@@ -381,9 +381,9 @@
381
381
  </style>
382
382
 
383
383
  ${e}
384
- `}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",se)});function We(n,e){if(!_e(n)||!n.hasOwnProperty("raw"))throw Error("invalid template strings array");return Ne!==void 0?Ne.createHTML(e):e}function U(n,e,t=n,r){if(e===V)return e;let o=r!==void 0?t._$Co?.[r]:t._$Cl,i=q(e)?void 0:e._$litDirective$;return o?.constructor!==i&&(o?._$AO?.(!1),i===void 0?o=void 0:(o=new i(n),o._$AT(n,t,r)),r!==void 0?(t._$Co??(t._$Co=[]))[r]=o:t._$Cl=o),o!==void 0&&(e=U(n,o._$AS(n,e.values),o,r)),e}var L,ne,Ne,qe,I,Ve,Et,M,F,q,_e,Ct,be,j,ze,Oe,D,Ke,je,Ye,Ee,m,Ft,qt,V,b,Fe,P,St,Y,ye,W,H,ve,ke,we,xe,Tt,X,Ce=k(()=>{"use strict";L=globalThis,ne=L.trustedTypes,Ne=ne?ne.createPolicy("lit-html",{createHTML:n=>n}):void 0,qe="$lit$",I=`lit$${Math.random().toFixed(9).slice(2)}$`,Ve="?"+I,Et=`<${Ve}>`,M=L.document===void 0?{createTreeWalker:()=>({})}:document,F=()=>M.createComment(""),q=n=>n===null||typeof n!="object"&&typeof n!="function",_e=Array.isArray,Ct=n=>_e(n)||typeof n?.[Symbol.iterator]=="function",be=`[
384
+ `}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",se)});function We(n,e){if(!_e(n)||!n.hasOwnProperty("raw"))throw Error("invalid template strings array");return Ne!==void 0?Ne.createHTML(e):e}function U(n,e,t=n,r){if(e===V)return e;let o=r!==void 0?t._$Co?.[r]:t._$Cl,i=q(e)?void 0:e._$litDirective$;return o?.constructor!==i&&(o?._$AO?.(!1),i===void 0?o=void 0:(o=new i(n),o._$AT(n,t,r)),r!==void 0?(t._$Co??(t._$Co=[]))[r]=o:t._$Cl=o),o!==void 0&&(e=U(n,o._$AS(n,e.values),o,r)),e}var L,ne,Ne,qe,$,Ve,Et,M,F,q,_e,Ct,be,j,ze,Oe,D,Ke,je,Ye,Ee,h,Ft,qt,V,b,Fe,P,St,Y,ye,W,H,ve,ke,we,xe,Tt,X,Ce=k(()=>{"use strict";L=globalThis,ne=L.trustedTypes,Ne=ne?ne.createPolicy("lit-html",{createHTML:n=>n}):void 0,qe="$lit$",$=`lit$${Math.random().toFixed(9).slice(2)}$`,Ve="?"+$,Et=`<${Ve}>`,M=L.document===void 0?{createTreeWalker:()=>({})}:document,F=()=>M.createComment(""),q=n=>n===null||typeof n!="object"&&typeof n!="function",_e=Array.isArray,Ct=n=>_e(n)||typeof n?.[Symbol.iterator]=="function",be=`[
385
385
  \f\r]`,j=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,ze=/-->/g,Oe=/>/g,D=RegExp(`>|${be}(?:([^\\s"'>=/]+)(${be}*=${be}*(?:[^
386
- \f\r"'\`<>=]|("|')|))|$)`,"g"),Ke=/'/g,je=/"/g,Ye=/^(?:script|style|textarea|title)$/i,Ee=n=>(e,...t)=>({_$litType$:n,strings:e,values:t}),m=Ee(1),Ft=Ee(2),qt=Ee(3),V=Symbol.for("lit-noChange"),b=Symbol.for("lit-nothing"),Fe=new WeakMap,P=M.createTreeWalker(M,129);St=(n,e)=>{let t=n.length-1,r=[],o,i=e===2?"<svg>":e===3?"<math>":"",s=j;for(let a=0;a<t;a++){let c=n[a],d,p,h=-1,x=0;for(;x<c.length&&(s.lastIndex=x,p=s.exec(c),p!==null);)x=s.lastIndex,s===j?p[1]==="!--"?s=ze:p[1]!==void 0?s=Oe:p[2]!==void 0?(Ye.test(p[2])&&(o=RegExp("</"+p[2],"g")),s=D):p[3]!==void 0&&(s=D):s===D?p[0]===">"?(s=o??j,h=-1):p[1]===void 0?h=-2:(h=s.lastIndex-p[2].length,d=p[1],s=p[3]===void 0?D:p[3]==='"'?je:Ke):s===je||s===Ke?s=D:s===ze||s===Oe?s=j:(s=D,o=void 0);let u=s===D&&n[a+1].startsWith("/>")?" ":"";i+=s===j?c+Et:h>=0?(r.push(d),c.slice(0,h)+qe+c.slice(h)+I+u):c+I+(h===-2?a:u)}return[We(n,i+(n[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),r]},Y=class n{constructor({strings:e,_$litType$:t},r){let o;this.parts=[];let i=0,s=0,a=e.length-1,c=this.parts,[d,p]=St(e,t);if(this.el=n.createElement(d,r),P.currentNode=this.el.content,t===2||t===3){let h=this.el.content.firstChild;h.replaceWith(...h.childNodes)}for(;(o=P.nextNode())!==null&&c.length<a;){if(o.nodeType===1){if(o.hasAttributes())for(let h of o.getAttributeNames())if(h.endsWith(qe)){let x=p[s++],u=o.getAttribute(h).split(I),T=/([.?@])?(.*)/.exec(x);c.push({type:1,index:i,name:T[2],strings:u,ctor:T[1]==="."?ve:T[1]==="?"?ke:T[1]==="@"?we:H}),o.removeAttribute(h)}else h.startsWith(I)&&(c.push({type:6,index:i}),o.removeAttribute(h));if(Ye.test(o.tagName)){let h=o.textContent.split(I),x=h.length-1;if(x>0){o.textContent=ne?ne.emptyScript:"";for(let u=0;u<x;u++)o.append(h[u],F()),P.nextNode(),c.push({type:2,index:++i});o.append(h[x],F())}}}else if(o.nodeType===8)if(o.data===Ve)c.push({type:2,index:i});else{let h=-1;for(;(h=o.data.indexOf(I,h+1))!==-1;)c.push({type:7,index:i}),h+=I.length-1}i++}}static createElement(e,t){let r=M.createElement("template");return r.innerHTML=e,r}};ye=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:r}=this._$AD,o=(e?.creationScope??M).importNode(t,!0);P.currentNode=o;let i=P.nextNode(),s=0,a=0,c=r[0];for(;c!==void 0;){if(s===c.index){let d;c.type===2?d=new W(i,i.nextSibling,this,e):c.type===1?d=new c.ctor(i,c.name,c.strings,this,e):c.type===6&&(d=new xe(i,this,e)),this._$AV.push(d),c=r[++a]}s!==c?.index&&(i=P.nextNode(),s++)}return P.currentNode=M,o}p(e){let t=0;for(let r of this._$AV)r!==void 0&&(r.strings!==void 0?(r._$AI(e,r,t),t+=r.strings.length-2):r._$AI(e[t])),t++}},W=class n{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,r,o){this.type=2,this._$AH=b,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=o,this._$Cv=o?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=U(this,e,t),q(e)?e===b||e==null||e===""?(this._$AH!==b&&this._$AR(),this._$AH=b):e!==this._$AH&&e!==V&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Ct(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==b&&q(this._$AH)?this._$AA.nextSibling.data=e:this.T(M.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:r}=e,o=typeof r=="number"?this._$AC(e):(r.el===void 0&&(r.el=Y.createElement(We(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===o)this._$AH.p(t);else{let i=new ye(o,this),s=i.u(this.options);i.p(t),this.T(s),this._$AH=i}}_$AC(e){let t=Fe.get(e.strings);return t===void 0&&Fe.set(e.strings,t=new Y(e)),t}k(e){_e(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,r,o=0;for(let i of e)o===t.length?t.push(r=new n(this.O(F()),this.O(F()),this,this.options)):r=t[o],r._$AI(i),o++;o<t.length&&(this._$AR(r&&r._$AB.nextSibling,o),t.length=o)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let r=e.nextSibling;e.remove(),e=r}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},H=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,r,o,i){this.type=1,this._$AH=b,this._$AN=void 0,this.element=e,this.name=t,this._$AM=o,this.options=i,r.length>2||r[0]!==""||r[1]!==""?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=b}_$AI(e,t=this,r,o){let i=this.strings,s=!1;if(i===void 0)e=U(this,e,t,0),s=!q(e)||e!==this._$AH&&e!==V,s&&(this._$AH=e);else{let a=e,c,d;for(e=i[0],c=0;c<i.length-1;c++)d=U(this,a[r+c],t,c),d===V&&(d=this._$AH[c]),s||(s=!q(d)||d!==this._$AH[c]),d===b?e=b:e!==b&&(e+=(d??"")+i[c+1]),this._$AH[c]=d}s&&!o&&this.j(e)}j(e){e===b?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}},ve=class extends H{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===b?void 0:e}},ke=class extends H{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==b)}},we=class extends H{constructor(e,t,r,o,i){super(e,t,r,o,i),this.type=5}_$AI(e,t=this){if((e=U(this,e,t,0)??b)===V)return;let r=this._$AH,o=e===b&&r!==b||e.capture!==r.capture||e.once!==r.once||e.passive!==r.passive,i=e!==b&&(r===b||o);o&&this.element.removeEventListener(this.name,this,r),i&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}},xe=class{constructor(e,t,r){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=r}get _$AU(){return this._$AM._$AU}_$AI(e){U(this,e)}},Tt=L.litHtmlPolyfillSupport;Tt?.(Y,W),(L.litHtmlVersions??(L.litHtmlVersions=[])).push("3.3.1");X=(n,e,t)=>{let r=t?.renderBefore??e,o=r._$litPart$;if(o===void 0){let i=t?.renderBefore??null;r._$litPart$=o=new W(e.insertBefore(F(),i),i,void 0,t??{})}return o._$AI(n),o}});var Je,Xe=k(()=>{Je=`/**
386
+ \f\r"'\`<>=]|("|')|))|$)`,"g"),Ke=/'/g,je=/"/g,Ye=/^(?:script|style|textarea|title)$/i,Ee=n=>(e,...t)=>({_$litType$:n,strings:e,values:t}),h=Ee(1),Ft=Ee(2),qt=Ee(3),V=Symbol.for("lit-noChange"),b=Symbol.for("lit-nothing"),Fe=new WeakMap,P=M.createTreeWalker(M,129);St=(n,e)=>{let t=n.length-1,r=[],o,i=e===2?"<svg>":e===3?"<math>":"",s=j;for(let a=0;a<t;a++){let c=n[a],d,p,m=-1,x=0;for(;x<c.length&&(s.lastIndex=x,p=s.exec(c),p!==null);)x=s.lastIndex,s===j?p[1]==="!--"?s=ze:p[1]!==void 0?s=Oe:p[2]!==void 0?(Ye.test(p[2])&&(o=RegExp("</"+p[2],"g")),s=D):p[3]!==void 0&&(s=D):s===D?p[0]===">"?(s=o??j,m=-1):p[1]===void 0?m=-2:(m=s.lastIndex-p[2].length,d=p[1],s=p[3]===void 0?D:p[3]==='"'?je:Ke):s===je||s===Ke?s=D:s===ze||s===Oe?s=j:(s=D,o=void 0);let u=s===D&&n[a+1].startsWith("/>")?" ":"";i+=s===j?c+Et:m>=0?(r.push(d),c.slice(0,m)+qe+c.slice(m)+$+u):c+$+(m===-2?a:u)}return[We(n,i+(n[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),r]},Y=class n{constructor({strings:e,_$litType$:t},r){let o;this.parts=[];let i=0,s=0,a=e.length-1,c=this.parts,[d,p]=St(e,t);if(this.el=n.createElement(d,r),P.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes)}for(;(o=P.nextNode())!==null&&c.length<a;){if(o.nodeType===1){if(o.hasAttributes())for(let m of o.getAttributeNames())if(m.endsWith(qe)){let x=p[s++],u=o.getAttribute(m).split($),T=/([.?@])?(.*)/.exec(x);c.push({type:1,index:i,name:T[2],strings:u,ctor:T[1]==="."?ve:T[1]==="?"?ke:T[1]==="@"?we:H}),o.removeAttribute(m)}else m.startsWith($)&&(c.push({type:6,index:i}),o.removeAttribute(m));if(Ye.test(o.tagName)){let m=o.textContent.split($),x=m.length-1;if(x>0){o.textContent=ne?ne.emptyScript:"";for(let u=0;u<x;u++)o.append(m[u],F()),P.nextNode(),c.push({type:2,index:++i});o.append(m[x],F())}}}else if(o.nodeType===8)if(o.data===Ve)c.push({type:2,index:i});else{let m=-1;for(;(m=o.data.indexOf($,m+1))!==-1;)c.push({type:7,index:i}),m+=$.length-1}i++}}static createElement(e,t){let r=M.createElement("template");return r.innerHTML=e,r}};ye=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:r}=this._$AD,o=(e?.creationScope??M).importNode(t,!0);P.currentNode=o;let i=P.nextNode(),s=0,a=0,c=r[0];for(;c!==void 0;){if(s===c.index){let d;c.type===2?d=new W(i,i.nextSibling,this,e):c.type===1?d=new c.ctor(i,c.name,c.strings,this,e):c.type===6&&(d=new xe(i,this,e)),this._$AV.push(d),c=r[++a]}s!==c?.index&&(i=P.nextNode(),s++)}return P.currentNode=M,o}p(e){let t=0;for(let r of this._$AV)r!==void 0&&(r.strings!==void 0?(r._$AI(e,r,t),t+=r.strings.length-2):r._$AI(e[t])),t++}},W=class n{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,r,o){this.type=2,this._$AH=b,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=o,this._$Cv=o?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=U(this,e,t),q(e)?e===b||e==null||e===""?(this._$AH!==b&&this._$AR(),this._$AH=b):e!==this._$AH&&e!==V&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Ct(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==b&&q(this._$AH)?this._$AA.nextSibling.data=e:this.T(M.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:r}=e,o=typeof r=="number"?this._$AC(e):(r.el===void 0&&(r.el=Y.createElement(We(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===o)this._$AH.p(t);else{let i=new ye(o,this),s=i.u(this.options);i.p(t),this.T(s),this._$AH=i}}_$AC(e){let t=Fe.get(e.strings);return t===void 0&&Fe.set(e.strings,t=new Y(e)),t}k(e){_e(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,r,o=0;for(let i of e)o===t.length?t.push(r=new n(this.O(F()),this.O(F()),this,this.options)):r=t[o],r._$AI(i),o++;o<t.length&&(this._$AR(r&&r._$AB.nextSibling,o),t.length=o)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let r=e.nextSibling;e.remove(),e=r}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},H=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,r,o,i){this.type=1,this._$AH=b,this._$AN=void 0,this.element=e,this.name=t,this._$AM=o,this.options=i,r.length>2||r[0]!==""||r[1]!==""?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=b}_$AI(e,t=this,r,o){let i=this.strings,s=!1;if(i===void 0)e=U(this,e,t,0),s=!q(e)||e!==this._$AH&&e!==V,s&&(this._$AH=e);else{let a=e,c,d;for(e=i[0],c=0;c<i.length-1;c++)d=U(this,a[r+c],t,c),d===V&&(d=this._$AH[c]),s||(s=!q(d)||d!==this._$AH[c]),d===b?e=b:e!==b&&(e+=(d??"")+i[c+1]),this._$AH[c]=d}s&&!o&&this.j(e)}j(e){e===b?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}},ve=class extends H{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===b?void 0:e}},ke=class extends H{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==b)}},we=class extends H{constructor(e,t,r,o,i){super(e,t,r,o,i),this.type=5}_$AI(e,t=this){if((e=U(this,e,t,0)??b)===V)return;let r=this._$AH,o=e===b&&r!==b||e.capture!==r.capture||e.once!==r.once||e.passive!==r.passive,i=e!==b&&(r===b||o);o&&this.element.removeEventListener(this.name,this,r),i&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}},xe=class{constructor(e,t,r){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=r}get _$AU(){return this._$AM._$AU}_$AI(e){U(this,e)}},Tt=L.litHtmlPolyfillSupport;Tt?.(Y,W),(L.litHtmlVersions??(L.litHtmlVersions=[])).push("3.3.1");X=(n,e,t)=>{let r=t?.renderBefore??e,o=r._$litPart$;if(o===void 0){let i=t?.renderBefore??null;r._$litPart$=o=new W(e.insertBefore(F(),i),i,void 0,t??{})}return o._$AI(n),o}});var Je,Xe=k(()=>{Je=`/**
387
387
  * Payment Form Skeleton - Shadow DOM Styles
388
388
  * Loading skeleton that matches the structure of RecurPaymentForm
389
389
  */
@@ -594,24 +594,24 @@
594
594
  color: #4a5568;
595
595
  margin: 0;
596
596
  }
597
- `});var Ze={};C(Ze,{RecurPaymentFormSkeleton:()=>ae});var It,ae,Ge=k(()=>{"use strict";Ce();Xe();It=m`
597
+ `});var Ze={};C(Ze,{RecurPaymentFormSkeleton:()=>ae});var $t,ae,Ge=k(()=>{"use strict";Ce();Xe();$t=h`
598
598
  <svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
599
599
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
600
600
  </svg>
601
- `,ae=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}renderHeader(){return m`
601
+ `,ae=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}renderHeader(){return h`
602
602
  <div class="form-header">
603
603
  <h2 class="form-title">訂閱付款</h2>
604
604
  </div>
605
- `}renderOrderSummary(){return m`
605
+ `}renderOrderSummary(){return h`
606
606
  <div class="form-section">
607
607
  <h3 class="section-title">訂單摘要</h3>
608
608
  <div class="order-summary">
609
609
  <div class="order-row">
610
- <span class="order-label">訂閱方案</span>
611
- <div class="skeleton skeleton-order-value"></div>
610
+ <span class="order-label">方案</span>
611
+ <div class="skeleton skeleton-order-value" style="width: 120px;"></div>
612
612
  </div>
613
613
  <div class="order-row">
614
- <span class="order-label">計費週期</span>
614
+ <span class="order-label">小計</span>
615
615
  <div class="skeleton skeleton-order-value"></div>
616
616
  </div>
617
617
  <div class="coupon-section">
@@ -623,7 +623,7 @@
623
623
  </div>
624
624
  </div>
625
625
  </div>
626
- `}renderCustomerInfo(){return m`
626
+ `}renderCustomerInfo(){return h`
627
627
  <div class="form-section">
628
628
  <h3 class="section-title">聯絡資訊</h3>
629
629
  <div class="customer-info-display">
@@ -637,7 +637,7 @@
637
637
  </div>
638
638
  </div>
639
639
  </div>
640
- `}renderCardFields(){return m`
640
+ `}renderCardFields(){return h`
641
641
  <div class="form-section">
642
642
  <h3 class="section-title">信用卡資訊</h3>
643
643
  <div class="card-field">
@@ -655,12 +655,12 @@
655
655
  </div>
656
656
  </div>
657
657
  </div>
658
- `}renderSubmitButton(){return m`<div class="skeleton skeleton-button"></div>`}renderSecurityNote(){return m`
658
+ `}renderSubmitButton(){return h`<div class="skeleton skeleton-button"></div>`}renderSecurityNote(){return h`
659
659
  <div class="security-note">
660
- ${It}
660
+ ${$t}
661
661
  <p class="security-text">您的付款資訊經過加密保護</p>
662
662
  </div>
663
- `}render(){let e=m`
663
+ `}render(){let e=h`
664
664
  <style>${Je}</style>
665
665
 
666
666
  <div class="payment-form-wrapper">
@@ -993,6 +993,7 @@
993
993
  padding: 0 12px;
994
994
  font-size: 14px;
995
995
  text-transform: uppercase;
996
+ background-color: #ffffff;
996
997
  border: 1px solid #d1d5db;
997
998
  border-radius: 6px;
998
999
  outline: none;
@@ -1003,9 +1004,15 @@
1003
1004
  text-transform: none;
1004
1005
  }
1005
1006
 
1007
+ .recur-coupon__input:hover:not(:focus) {
1008
+ border-color: #9ca3af;
1009
+ }
1010
+
1006
1011
  .recur-coupon__input:focus {
1007
- border-color: #3b82f6;
1008
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
1012
+ border-color: var(--ring, hsl(215 16% 47%));
1013
+ outline: 0;
1014
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent);
1015
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
1009
1016
  }
1010
1017
 
1011
1018
  .recur-coupon__btn {
@@ -1201,8 +1208,9 @@
1201
1208
 
1202
1209
  .recur-form-input {
1203
1210
  width: 100%;
1204
- padding: 10px 12px;
1205
- font-size: 16px;
1211
+ height: 36px;
1212
+ padding: 0 12px;
1213
+ font-size: 14px;
1206
1214
  border: 1px solid #d1d5db;
1207
1215
  border-radius: 6px;
1208
1216
  transition: border-color 0.2s;
@@ -1210,9 +1218,10 @@
1210
1218
  }
1211
1219
 
1212
1220
  .recur-form-input:focus {
1213
- outline: none;
1214
- border-color: #3b82f6;
1215
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
1221
+ border-color: var(--ring, hsl(215 16% 47%));
1222
+ outline: 0;
1223
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent);
1224
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
1216
1225
  }
1217
1226
 
1218
1227
  .recur-form-input:hover:not(:focus) {
@@ -1335,23 +1344,23 @@
1335
1344
  animation: recur-skeleton-loading 1.5s ease-in-out infinite;
1336
1345
  border-radius: 4px;
1337
1346
  }
1338
- `});var st={};C(st,{RecurPaymentForm:()=>le});var B,le,nt=k(()=>{"use strict";Ce();tt();ot();B={lock:m`
1347
+ `});var st={};C(st,{RecurPaymentForm:()=>le});var B,le,nt=k(()=>{"use strict";Ce();tt();ot();B={lock:h`
1339
1348
  <svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1340
1349
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
1341
1350
  </svg>
1342
- `,tag:m`
1351
+ `,tag:h`
1343
1352
  <svg class="recur-coupon__trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1344
1353
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
1345
1354
  </svg>
1346
- `,tagApplied:m`
1355
+ `,tagApplied:h`
1347
1356
  <svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1348
1357
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
1349
1358
  </svg>
1350
- `,close:m`
1359
+ `,close:h`
1351
1360
  <svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1352
1361
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
1353
1362
  </svg>
1354
- `,spinner:m`<span class="recur-coupon__spinner"></span>`},le=class extends HTMLElement{constructor(){super();l(this,"containerId");l(this,"customStyles");l(this,"_isInitializing",!1);l(this,"_initializationAborted",!1);l(this,"_showCouponInput",!1);l(this,"_couponCode","");l(this,"_couponLoading",!1);l(this,"_couponError",null);l(this,"_appliedCoupon",null);this.containerId=this.getAttribute("container-id")||`recur-${Date.now()}`,this.customStyles=this.getAttribute("custom-styles")||"",this.attachShadow({mode:"open"})}connectedCallback(){this.render()}disconnectedCallback(){console.log("[PaymentForm] Component disconnected, cleaning up..."),this._initializationAborted=!0,this._paymentSession=null;let t=document.getElementById(`${this.containerId}-submit-btn`);if(t){let r=t.cloneNode(!0);t.parentNode?.replaceChild(r,t)}}static get observedAttributes(){return["custom-styles","customer-name","customer-email","product-name","amount","interval","checkout-id","publishable-key","api-base-url"]}attributeChangedCallback(t,r,o){r!==o&&(t==="custom-styles"?(this.customStyles=o||"",this.updateCustomStyles()):this.updateOrderSummaryDOM())}getShadowDOMStyles(){return rt}getLightDOMStyles(){return it}render(){this.renderShadowDOM(),this.renderLightDOM()}renderShadowDOM(){let t=m`
1363
+ `,spinner:h`<span class="recur-coupon__spinner"></span>`},le=class extends HTMLElement{constructor(){super();l(this,"containerId");l(this,"customStyles");l(this,"_isInitializing",!1);l(this,"_initializationAborted",!1);l(this,"_showCouponInput",!1);l(this,"_couponCode","");l(this,"_couponLoading",!1);l(this,"_couponError",null);l(this,"_appliedCoupon",null);this.containerId=this.getAttribute("container-id")||`recur-${Date.now()}`,this.customStyles=this.getAttribute("custom-styles")||"",this.attachShadow({mode:"open"})}connectedCallback(){this.render()}disconnectedCallback(){console.log("[PaymentForm] Component disconnected, cleaning up..."),this._initializationAborted=!0,this._paymentSession=null;let t=document.getElementById(`${this.containerId}-submit-btn`);if(t){let r=t.cloneNode(!0);t.parentNode?.replaceChild(r,t)}}static get observedAttributes(){return["custom-styles","customer-name","customer-email","product-name","amount","interval","checkout-id","publishable-key","api-base-url"]}attributeChangedCallback(t,r,o){r!==o&&(t==="custom-styles"?(this.customStyles=o||"",this.updateCustomStyles()):this.updateOrderSummaryDOM())}getShadowDOMStyles(){return rt}getLightDOMStyles(){return it}render(){this.renderShadowDOM(),this.renderLightDOM()}renderShadowDOM(){let t=h`
1355
1364
  <style>${this.getShadowDOMStyles()}</style>
1356
1365
 
1357
1366
  <div class="payment-form-wrapper">
@@ -1381,7 +1390,7 @@
1381
1390
  <p class="security-text">您的付款資訊經過加密保護</p>
1382
1391
  </div>
1383
1392
  </div>
1384
- `;X(t,this.shadowRoot)}renderLightDOM(){let t=m`
1393
+ `;X(t,this.shadowRoot)}renderLightDOM(){let t=h`
1385
1394
  <style id="${this.containerId}-styles">
1386
1395
  ${this.getLightDOMStyles()}
1387
1396
  ${this.getCustomStyles()}
@@ -1410,18 +1419,12 @@
1410
1419
  height: 36px !important;
1411
1420
  }
1412
1421
  ${this.customStyles}
1413
- `}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-styles`);t&&(t.textContent=this.getLightDOMStyles()+this.getCustomStyles())}renderOrderSummary(){let t=this.getAttribute("product-name"),r=this.getAttribute("amount"),o=this.getAttribute("interval");if(!t||!r){let h=!!o;return m`
1422
+ `}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-styles`);t&&(t.textContent=this.getLightDOMStyles()+this.getCustomStyles())}renderOrderSummary(){let t=this.getAttribute("product-name"),r=this.getAttribute("amount"),o=this.getAttribute("interval");if(!t||!r)return h`
1414
1423
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1415
1424
  <div class="recur-order-summary__row">
1416
- <span class="recur-order-summary__label">${h?"\u8A02\u95B1\u65B9\u6848":"\u5546\u54C1"}</span>
1417
- <span class="recur-order-summary__value recur-skeleton" style="width: 100px; height: 20px;"></span>
1425
+ <span class="recur-order-summary__label">方案</span>
1426
+ <span class="recur-order-summary__value recur-skeleton" style="width: 120px; height: 20px;"></span>
1418
1427
  </div>
1419
- ${h?m`
1420
- <div class="recur-order-summary__row">
1421
- <span class="recur-order-summary__label">計費週期</span>
1422
- <span class="recur-order-summary__value recur-skeleton" style="width: 40px; height: 20px;"></span>
1423
- </div>
1424
- `:b}
1425
1428
  <div class="recur-order-summary__row">
1426
1429
  <span class="recur-order-summary__label">小計</span>
1427
1430
  <span class="recur-order-summary__value recur-skeleton" style="width: 80px; height: 20px;"></span>
@@ -1434,20 +1437,13 @@
1434
1437
  <span class="recur-order-summary__total recur-skeleton" style="width: 100px; height: 26px;"></span>
1435
1438
  </div>
1436
1439
  </div>
1437
- `}let s=o?{day:"\u65E5",week:"\u9031",month:"\u6708",year:"\u5E74"}[o]||o:"",a=Number(r),c=this._appliedCoupon?.discountAmount||0,d=a-c,p=!!s;return m`
1440
+ `;let s=o?{day:"\u65E5",week:"\u9031",month:"\u6708",year:"\u5E74"}[o]||o:"",a=Number(r),c=this._appliedCoupon?.discountAmount||0,d=a-c,p=s?`${t} / \u6BCF${s}`:t;return h`
1438
1441
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1439
1442
  <div class="recur-order-summary__row">
1440
- <span class="recur-order-summary__label">${p?"\u8A02\u95B1\u65B9\u6848":"\u5546\u54C1"}</span>
1441
- <span class="recur-order-summary__value">${t}</span>
1443
+ <span class="recur-order-summary__label">方案</span>
1444
+ <span class="recur-order-summary__value">${p}</span>
1442
1445
  </div>
1443
1446
 
1444
- ${p?m`
1445
- <div class="recur-order-summary__row">
1446
- <span class="recur-order-summary__label">計費週期</span>
1447
- <span class="recur-order-summary__value">每${s}</span>
1448
- </div>
1449
- `:b}
1450
-
1451
1447
  <!-- 小計 (Subtotal) - always show -->
1452
1448
  <div class="recur-order-summary__row">
1453
1449
  <span class="recur-order-summary__label">小計</span>
@@ -1465,14 +1461,14 @@
1465
1461
  <span class="recur-order-summary__total">NT$ ${d.toLocaleString()}</span>
1466
1462
  </div>
1467
1463
  </div>
1468
- `}renderCoupon(){return this._appliedCoupon?m`
1464
+ `}renderCoupon(){return this._appliedCoupon?h`
1469
1465
  <div class="recur-coupon__applied">
1470
1466
  <div class="recur-coupon__applied-info">
1471
1467
  ${B.tagApplied}
1472
- ${this._appliedCoupon.couponName?m`
1468
+ ${this._appliedCoupon.couponName?h`
1473
1469
  <span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
1474
1470
  <span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
1475
- `:m`
1471
+ `:h`
1476
1472
  <span class="recur-coupon__applied-name">${this._appliedCoupon.code}</span>
1477
1473
  `}
1478
1474
  <button
@@ -1488,7 +1484,7 @@
1488
1484
  -NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
1489
1485
  </span>
1490
1486
  </div>
1491
- `:this._showCouponInput?m`
1487
+ `:this._showCouponInput?h`
1492
1488
  <div style="width: 100%;">
1493
1489
  <div class="recur-coupon__input-row">
1494
1490
  <input
@@ -1518,11 +1514,11 @@
1518
1514
  取消
1519
1515
  </button>
1520
1516
  </div>
1521
- ${this._couponError?m`
1517
+ ${this._couponError?h`
1522
1518
  <div class="recur-coupon__error">${this._couponError}</div>
1523
1519
  `:b}
1524
1520
  </div>
1525
- `:m`
1521
+ `:h`
1526
1522
  <button
1527
1523
  type="button"
1528
1524
  class="recur-coupon__trigger"
@@ -1579,9 +1575,9 @@
1579
1575
  </div>
1580
1576
  <span class="recur-coupon__applied-amount">-NT$ ${t.discountAmount.toLocaleString()}</span>
1581
1577
  </div>
1582
- `}bindCouponTriggerEvents(t){t.querySelector(".recur-coupon__trigger")?.addEventListener("click",()=>this.showCouponInput())}bindCouponInputEvents(t){let r=t.querySelector(".recur-coupon__input"),o=t.querySelector(".recur-coupon__btn--apply"),i=t.querySelector(".recur-coupon__btn--cancel");r?.addEventListener("input",s=>this.handleCouponInputChange(s)),r?.addEventListener("keydown",s=>this.handleCouponKeydown(s)),o?.addEventListener("click",()=>this.applyCoupon()),i?.addEventListener("click",()=>this.cancelCouponInput())}bindCouponAppliedEvents(t){t.querySelector(".recur-coupon__remove")?.addEventListener("click",()=>this.removeCoupon())}updateOrderSummaryDOM(){let t=document.getElementById(`${this.containerId}-order-summary`);if(!t)return;let r=Number(this.getAttribute("amount")||0),o=this._appliedCoupon?.discountAmount||0,i=r-o,a=t.querySelector(".recur-order-summary__row--total")?.querySelector(".recur-order-summary__total");a&&(a.textContent=`NT$ ${i.toLocaleString()}`),this.updateCouponSectionDOM()}async applyCoupon(){let t=this._couponCode.trim();if(!t){this._couponError="\u8ACB\u8F38\u5165\u512A\u60E0\u78BC",this.updateCouponSectionDOM();return}let r=this.getAttribute("checkout-id"),o=this.getAttribute("api-base-url")||"";if(!r){this._couponError="\u7121\u6CD5\u5957\u7528\u512A\u60E0\u78BC",this.updateCouponSectionDOM();return}this._couponLoading=!0,this._couponError=null,this.updateCouponSectionDOM();try{let i=await fetch(`${o}/v1/checkouts/${r}/coupon`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:t})}),s=await i.json();if(!i.ok){this._couponError=s.error?.message||"\u512A\u60E0\u78BC\u7121\u6548",this._couponLoading=!1,this.updateCouponSectionDOM();return}this._appliedCoupon={code:s.discount.code,couponName:s.discount.couponName,discountType:s.discount.discountType,discountAmount:s.discount.discountAmount,duration:s.discount.duration,durationMonths:s.discount.durationMonths,bonusTrialDays:s.discount.bonusTrialDays,bonusMonths:s.discount.bonusMonths},this._showCouponInput=!1,this._couponCode="",this._couponLoading=!1,this.updateOrderSummaryDOM(),this.dispatchEvent(new CustomEvent("coupon-applied",{detail:{coupon:this._appliedCoupon},bubbles:!0,composed:!0}))}catch{this._couponError="\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66",this._couponLoading=!1,this.updateCouponSectionDOM()}}async removeCoupon(){let t=this.getAttribute("checkout-id"),r=this.getAttribute("api-base-url")||"";if(t){this._couponLoading=!0,this.updateCouponSectionDOM();try{let o=await fetch(`${r}/v1/checkouts/${t}/coupon`,{method:"DELETE"});if(!o.ok){let s=await o.json();this._couponError=s.error?.message||"\u79FB\u9664\u5931\u6557",this._couponLoading=!1,this.updateCouponSectionDOM();return}let i=this._appliedCoupon;this._appliedCoupon=null,this._couponLoading=!1,this.updateOrderSummaryDOM(),this.dispatchEvent(new CustomEvent("coupon-removed",{detail:{coupon:i},bubbles:!0,composed:!0}))}catch{this._couponError="\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66",this._couponLoading=!1,this.updateCouponSectionDOM()}}}getAppliedCoupon(){return this._appliedCoupon}renderCustomerInfo(){let t=this.getAttribute("customer-name"),r=this.getAttribute("customer-email");return r?m`
1578
+ `}bindCouponTriggerEvents(t){t.querySelector(".recur-coupon__trigger")?.addEventListener("click",()=>this.showCouponInput())}bindCouponInputEvents(t){let r=t.querySelector(".recur-coupon__input"),o=t.querySelector(".recur-coupon__btn--apply"),i=t.querySelector(".recur-coupon__btn--cancel");r?.addEventListener("input",s=>this.handleCouponInputChange(s)),r?.addEventListener("keydown",s=>this.handleCouponKeydown(s)),o?.addEventListener("click",()=>this.applyCoupon()),i?.addEventListener("click",()=>this.cancelCouponInput())}bindCouponAppliedEvents(t){t.querySelector(".recur-coupon__remove")?.addEventListener("click",()=>this.removeCoupon())}updateOrderSummaryDOM(){let t=document.getElementById(`${this.containerId}-order-summary`);if(!t)return;let r=Number(this.getAttribute("amount")||0),o=this._appliedCoupon?.discountAmount||0,i=r-o,a=t.querySelector(".recur-order-summary__row--total")?.querySelector(".recur-order-summary__total");a&&(a.textContent=`NT$ ${i.toLocaleString()}`),this.updateCouponSectionDOM()}async applyCoupon(){let t=this._couponCode.trim();if(!t){this._couponError="\u8ACB\u8F38\u5165\u512A\u60E0\u78BC",this.updateCouponSectionDOM();return}let r=this.getAttribute("checkout-id"),o=this.getAttribute("api-base-url")||"";if(!r){this._couponError="\u7121\u6CD5\u5957\u7528\u512A\u60E0\u78BC",this.updateCouponSectionDOM();return}this._couponLoading=!0,this._couponError=null,this.updateCouponSectionDOM();try{let i=await fetch(`${o}/v1/checkouts/${r}/coupon`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:t})}),s=await i.json();if(!i.ok){this._couponError=s.error?.message||"\u512A\u60E0\u78BC\u7121\u6548",this._couponLoading=!1,this.updateCouponSectionDOM();return}this._appliedCoupon={code:s.discount.code,couponName:s.discount.couponName,discountType:s.discount.discountType,discountAmount:s.discount.discountAmount,duration:s.discount.duration,durationMonths:s.discount.durationMonths,bonusTrialDays:s.discount.bonusTrialDays,bonusMonths:s.discount.bonusMonths},this._showCouponInput=!1,this._couponCode="",this._couponLoading=!1,this.updateOrderSummaryDOM(),this.dispatchEvent(new CustomEvent("coupon-applied",{detail:{coupon:this._appliedCoupon},bubbles:!0,composed:!0}))}catch{this._couponError="\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66",this._couponLoading=!1,this.updateCouponSectionDOM()}}async removeCoupon(){let t=this.getAttribute("checkout-id"),r=this.getAttribute("api-base-url")||"";if(t){this._couponLoading=!0,this.updateCouponSectionDOM();try{let o=await fetch(`${r}/v1/checkouts/${t}/coupon`,{method:"DELETE"});if(!o.ok){let s=await o.json();this._couponError=s.error?.message||"\u79FB\u9664\u5931\u6557",this._couponLoading=!1,this.updateCouponSectionDOM();return}let i=this._appliedCoupon;this._appliedCoupon=null,this._couponLoading=!1,this.updateOrderSummaryDOM(),this.dispatchEvent(new CustomEvent("coupon-removed",{detail:{coupon:i},bubbles:!0,composed:!0}))}catch{this._couponError="\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66",this._couponLoading=!1,this.updateCouponSectionDOM()}}}getAppliedCoupon(){return this._appliedCoupon}renderCustomerInfo(){let t=this.getAttribute("customer-name"),r=this.getAttribute("customer-email");return r?h`
1583
1579
  <div class="recur-info-display">
1584
- ${t?m`
1580
+ ${t?h`
1585
1581
  <div class="recur-info-row">
1586
1582
  <span class="recur-info-label">姓名</span>
1587
1583
  <span class="recur-info-value">${t}</span>
@@ -1592,7 +1588,7 @@
1592
1588
  <span class="recur-info-value">${r}</span>
1593
1589
  </div>
1594
1590
  </div>
1595
- `:m`
1591
+ `:h`
1596
1592
  <div class="recur-form-group">
1597
1593
  <label class="recur-form-label" for="${this.containerId}-email">Email</label>
1598
1594
  <input
@@ -1615,7 +1611,7 @@
1615
1611
  required
1616
1612
  />
1617
1613
  </div>
1618
- `}renderCardFields(){return m`
1614
+ `}renderCardFields(){return h`
1619
1615
  <div class="recur-card-field">
1620
1616
  <label class="recur-card-field-label">卡號</label>
1621
1617
  <div class="recur-card-field-container" id="${this.containerId}-card-no-wrapper">
@@ -1641,7 +1637,7 @@
1641
1637
  </div>
1642
1638
  </div>
1643
1639
  </div>
1644
- `}hideCardSkeletons(){[`${this.containerId}-card-no-skeleton`,`${this.containerId}-card-exp-skeleton`,`${this.containerId}-card-cvc-skeleton`].forEach(r=>{let o=document.getElementById(r);o&&o.classList.add("hidden")})}renderActions(){return m`
1640
+ `}hideCardSkeletons(){[`${this.containerId}-card-no-skeleton`,`${this.containerId}-card-exp-skeleton`,`${this.containerId}-card-cvc-skeleton`].forEach(r=>{let o=document.getElementById(r);o&&o.classList.add("hidden")})}renderActions(){return h`
1645
1641
  <button
1646
1642
  type="submit"
1647
1643
  id="${this.containerId}-submit-btn"
@@ -1882,7 +1878,7 @@
1882
1878
  <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
1883
1879
  <circle cx="12" cy="7" r="4"/>
1884
1880
  </svg>
1885
- `}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:()=>G,RecurElements:()=>N,createElements:()=>Se,default:()=>Nt,init:()=>ht});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(()=>(Ge(),Ze)),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.11",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"},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 me=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=`
1881
+ `}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:()=>G,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(()=>(Ge(),Ze)),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.12",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"},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=`
1886
1882
  <div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
1887
1883
  <div class="recur-checkout-header" style="margin-bottom: 24px;">
1888
1884
  <h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
@@ -1959,14 +1955,14 @@
1959
1955
  display: block;
1960
1956
  user-select: none;
1961
1957
  transition: height 0.35s ease, opacity 0.4s ease 0.1s;
1962
- `.replace(/\s+/g," ").trim(),this.iframe.allow="payment *",this.iframe.setAttribute("title","Secure payment input frame"),this.iframe.setAttribute("role","presentation"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("frameBorder","0"),this.container.innerHTML="",this.container.appendChild(this.iframe),new Promise((r,o)=>{let i=setTimeout(()=>{o(new Error("Elements initialization timeout"))},3e4),s=()=>{clearTimeout(i),this.off("ready",s),r()},a=c=>{clearTimeout(i),this.off("error",a),o(new Error(c.message||"Elements initialization failed"))};this.on("ready",s),this.on("error",a)})}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}off(e,t){let r=this.eventHandlers.get(e);r&&r.delete(t)}emit(e,t){let r=this.eventHandlers.get(e);r&&r.forEach(o=>o(t))}handleMessage(e){if(!this.isValidOrigin(e.origin))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_ELEMENTS_READY":this.sessionId=r.sessionId,this.timestamp=r.timestamp,this.creditToken=r.creditToken,this.sdkToken=r.sdkToken,this.emit("ready",r);break;case"RECUR_CARD_VALID":this.emit("change",{valid:r.valid});break;case"RECUR_CARD_TOKENIZED":this.cardToken=r.cardToken,this.cardTimestamp=r.timestamp,this.emit("tokenized",r);break;case"RECUR_PAYMENT_ERROR":this.emit("error",r);break;case"RECUR_RESIZE":this.iframe&&r?.height&&(this.iframe.style.height=`${r.height}px`);break}}isValidOrigin(e){try{let t=new URL(this.embedUrl).origin;return e===t}catch{return!1}}async tokenize(){if(!this.iframe||!this.iframe.contentWindow)throw new Error("Elements not mounted");let e=new URL(this.embedUrl).origin;return this.iframe.contentWindow.postMessage({type:"RECUR_TOKENIZE"},e),new Promise((t,r)=>{let o=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),i=a=>{clearTimeout(o),this.off("tokenized",i),t(a)},s=a=>{clearTimeout(o),this.off("error",s),r(new Error(a.message||"Tokenization failed"))};this.on("tokenized",i),this.on("error",s)})}async confirmPayment(e){if(!this.sessionId||!this.cardToken)throw new Error("Card not tokenized. Call tokenize() first.");let t=await fetch(`${this.baseUrl}/api/v1/elements/confirm`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.publishableKey},body:JSON.stringify({sessionId:this.sessionId,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function Se(n){return new N(n)}var Ht="https://vendor.payuni.com.tw/sdk/uni-payment.js",Bt="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",pt=!1,he=!1,Z=null;async function mt(n=!1){return pt&&window.UniPayment?Promise.resolve():(he&&Z||(he=!0,Z=new Promise((e,t)=>{let r=document.createElement("script");r.src=n?Bt:Ht,r.async=!0,r.onload=()=>{pt=!0,he=!1,e()},r.onerror=()=>{he=!1,Z=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),Z)}var G=class{constructor(e){l(this,"core");l(this,"currentDialog",null);l(this,"currentIframe",null);l(this,"currentDialogElement",null);this.core=new pe(e)}async fetchProducts(e){return await this.core.fetchProducts(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new me(t,e).render()}async redirectToCheckout(e){let t=await this.createCheckoutSession(e);window.location.href=t.url}async createCheckoutSession(e){let t=this.getBaseUrl();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");if(!e.successUrl)throw new Error("successUrl is required for hosted checkout");if(!e.cancelUrl)throw new Error("cancelUrl is required for hosted checkout");let r={successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.productId&&(r.productId=e.productId),e.productSlug&&(r.productSlug=e.productSlug),e.customerEmail&&(r.customerEmail=e.customerEmail),e.customerName&&(r.customerName=e.customerName),e.externalCustomerId&&(r.externalCustomerId=e.externalCustomerId);let o=this.core.getConfig(),i=await fetch(`${t}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":o.publishableKey},body:JSON.stringify(r)});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error?.message||c.error||"Failed to create checkout session")}let s=await i.json(),a=w(s);return{id:a.id,url:a.url,expiresAt:a.expiresAt,clientSecret:a.clientSecret}}async getCheckoutStatus(e,t){let r=this.getBaseUrl(),o=this.core.getConfig(),i=await fetch(`${r}/v1/checkouts/${e}?client_secret=${encodeURIComponent(t)}`,{method:"GET",headers:{"X-Recur-Publishable-Key":o.publishableKey}});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error||"Failed to get checkout status")}let s=await i.json(),a=w(s);return{id:a.checkout.id,status:a.checkout.status,amount:a.checkout.amount,currency:a.checkout.currency,lastCharge:a.lastCharge}}async checkout(e){let t=this.core.getConfig(),r=null,o=e.productId||e.planId,i=e.productSlug;try{if(console.log("[Recur SDK] Starting checkout flow...",{productId:o,productSlug:i,mode:e.mode}),!o&&!i)throw new Error("Either productId or productSlug is required");if(!t.publishableKey)throw new Error("publishableKey is required");let s=this.getBaseUrl();console.log("[Recur SDK] Base URL:",s);let a={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},c=e.mode||"modal";if(c==="redirect"){if(!e.successUrl)throw new Error("successUrl is required for redirect mode");if(!e.cancelUrl)throw new Error("cancelUrl is required for redirect mode");console.log("[Recur SDK] Creating hosted checkout session...");let y={successUrl:e.successUrl,cancelUrl:e.cancelUrl};o&&(y.productId=o),i&&(y.productSlug=i),e.customerEmail&&(y.customerEmail=e.customerEmail),e.customerName&&(y.customerName=e.customerName),e.externalCustomerId&&(y.externalCustomerId=e.externalCustomerId);let A=await fetch(`${s}/v1/checkout/sessions`,{method:"POST",headers:a,body:JSON.stringify(y)});if(!A.ok){let R=await A.json().catch(()=>({}));throw console.error("[Recur SDK] Failed to create checkout session:",R),new Error(R.error?.message||R.error||"Failed to create checkout session")}let ge=await A.json(),E=w(ge);console.log("[Recur SDK] Checkout session created:",E),console.log("[Recur SDK] Redirecting to hosted checkout:",E.url),window.location.href=E.url;return}let d=null;if(c==="modal"){let y=this.createDialogWithSkeleton(e.onClose);r=y.dialog,d=y.container}else if(c==="iframe"){if(d=this.getEmbeddedContainer(e.container),!d)throw new Error("Container is required for iframe mode");d.innerHTML="";let y=document.createElement("recur-payment-form-skeleton");d.appendChild(y)}console.log("[Recur SDK] Step 1: Creating embedded checkout...");let p={customerName:e.customerName,customerEmail:e.customerEmail};o&&(p.productId=o),i&&(p.productSlug=i),e.externalCustomerId&&(p.externalCustomerId=e.externalCustomerId),e.successUrl&&(p.successUrl=e.successUrl),e.cancelUrl&&(p.cancelUrl=e.cancelUrl);let h=await fetch(`${s}/v1/checkouts`,{method:"POST",headers:a,body:JSON.stringify(p)});if(!h.ok){let y=await h.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",y);let A=y.details||y.error||"Failed to create checkout";throw new Error(A)}let x=await h.json(),u=w(x);if(console.log("[Recur SDK] Checkout created successfully:",u),e.onSuccess?.(u),console.log("[Recur SDK] Step 2: Extracting SDK token..."),!u.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let T=!u.livemode;if(console.log("[Recur SDK] Environment:",T?"SANDBOX":"PRODUCTION"),await mt(T),console.log("[Recur SDK] PAYUNi SDK loaded successfully"),!window.UniPayment)throw new Error("PAYUNi SDK failed to load");if(console.log("[Recur SDK] Step 4: Rendering payment form..."),!d)throw new Error("Payment container not available");d.innerHTML="";let f=document.createElement("recur-payment-form");if(f.setAttribute("container-id",d.id||"recur-payment-container"),u.checkout?.id&&f.setAttribute("checkout-id",u.checkout.id),f.setAttribute("api-base-url",s),e.customerName&&f.setAttribute("customer-name",e.customerName),e.customerEmail&&f.setAttribute("customer-email",e.customerEmail),u.product?.name&&f.setAttribute("product-name",u.product.name),u.checkout?.amount&&f.setAttribute("amount",u.checkout.amount.toString()),u.product?.interval&&f.setAttribute("interval",u.product.interval),f.setAttribute("custom-styles",`
1958
+ `.replace(/\s+/g," ").trim(),this.iframe.allow="payment *",this.iframe.setAttribute("title","Secure payment input frame"),this.iframe.setAttribute("role","presentation"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("frameBorder","0"),this.container.innerHTML="",this.container.appendChild(this.iframe),new Promise((r,o)=>{let i=setTimeout(()=>{o(new Error("Elements initialization timeout"))},3e4),s=()=>{clearTimeout(i),this.off("ready",s),r()},a=c=>{clearTimeout(i),this.off("error",a),o(new Error(c.message||"Elements initialization failed"))};this.on("ready",s),this.on("error",a)})}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}off(e,t){let r=this.eventHandlers.get(e);r&&r.delete(t)}emit(e,t){let r=this.eventHandlers.get(e);r&&r.forEach(o=>o(t))}handleMessage(e){if(!this.isValidOrigin(e.origin))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_ELEMENTS_READY":this.sessionId=r.sessionId,this.timestamp=r.timestamp,this.creditToken=r.creditToken,this.sdkToken=r.sdkToken,this.emit("ready",r);break;case"RECUR_CARD_VALID":this.emit("change",{valid:r.valid});break;case"RECUR_CARD_TOKENIZED":this.cardToken=r.cardToken,this.cardTimestamp=r.timestamp,this.emit("tokenized",r);break;case"RECUR_PAYMENT_ERROR":this.emit("error",r);break;case"RECUR_RESIZE":this.iframe&&r?.height&&(this.iframe.style.height=`${r.height}px`);break}}isValidOrigin(e){try{let t=new URL(this.embedUrl).origin;return e===t}catch{return!1}}async tokenize(){if(!this.iframe||!this.iframe.contentWindow)throw new Error("Elements not mounted");let e=new URL(this.embedUrl).origin;return this.iframe.contentWindow.postMessage({type:"RECUR_TOKENIZE"},e),new Promise((t,r)=>{let o=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),i=a=>{clearTimeout(o),this.off("tokenized",i),t(a)},s=a=>{clearTimeout(o),this.off("error",s),r(new Error(a.message||"Tokenization failed"))};this.on("tokenized",i),this.on("error",s)})}async confirmPayment(e){if(!this.sessionId||!this.cardToken)throw new Error("Card not tokenized. Call tokenize() first.");let t=await fetch(`${this.baseUrl}/api/v1/elements/confirm`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.publishableKey},body:JSON.stringify({sessionId:this.sessionId,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function Se(n){return new N(n)}var Ht="https://vendor.payuni.com.tw/sdk/uni-payment.js",Bt="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",pt=!1,me=!1,Z=null;async function ht(n=!1){return pt&&window.UniPayment?Promise.resolve():(me&&Z||(me=!0,Z=new Promise((e,t)=>{let r=document.createElement("script");r.src=n?Bt:Ht,r.async=!0,r.onload=()=>{pt=!0,me=!1,e()},r.onerror=()=>{me=!1,Z=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),Z)}var G=class{constructor(e){l(this,"core");l(this,"currentDialog",null);l(this,"currentIframe",null);l(this,"currentDialogElement",null);this.core=new pe(e)}async fetchProducts(e){return await this.core.fetchProducts(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new he(t,e).render()}async redirectToCheckout(e){let t=await this.createCheckoutSession(e);window.location.href=t.url}async createCheckoutSession(e){let t=this.getBaseUrl();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");if(!e.successUrl)throw new Error("successUrl is required for hosted checkout");if(!e.cancelUrl)throw new Error("cancelUrl is required for hosted checkout");let r={successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.productId&&(r.productId=e.productId),e.productSlug&&(r.productSlug=e.productSlug),e.customerEmail&&(r.customerEmail=e.customerEmail),e.customerName&&(r.customerName=e.customerName),e.externalCustomerId&&(r.externalCustomerId=e.externalCustomerId);let o=this.core.getConfig(),i=await fetch(`${t}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":o.publishableKey},body:JSON.stringify(r)});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error?.message||c.error||"Failed to create checkout session")}let s=await i.json(),a=w(s);return{id:a.id,url:a.url,expiresAt:a.expiresAt,clientSecret:a.clientSecret}}async getCheckoutStatus(e,t){let r=this.getBaseUrl(),o=this.core.getConfig(),i=await fetch(`${r}/v1/checkouts/${e}?client_secret=${encodeURIComponent(t)}`,{method:"GET",headers:{"X-Recur-Publishable-Key":o.publishableKey}});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error||"Failed to get checkout status")}let s=await i.json(),a=w(s);return{id:a.checkout.id,status:a.checkout.status,amount:a.checkout.amount,currency:a.checkout.currency,lastCharge:a.lastCharge}}async checkout(e){let t=this.core.getConfig(),r=null,o=e.productId||e.planId,i=e.productSlug;try{if(console.log("[Recur SDK] Starting checkout flow...",{productId:o,productSlug:i,mode:e.mode}),!o&&!i)throw new Error("Either productId or productSlug is required");if(!t.publishableKey)throw new Error("publishableKey is required");let s=this.getBaseUrl();console.log("[Recur SDK] Base URL:",s);let a={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},c=e.mode||"modal";if(c==="redirect"){if(!e.successUrl)throw new Error("successUrl is required for redirect mode");if(!e.cancelUrl)throw new Error("cancelUrl is required for redirect mode");console.log("[Recur SDK] Creating hosted checkout session...");let y={successUrl:e.successUrl,cancelUrl:e.cancelUrl};o&&(y.productId=o),i&&(y.productSlug=i),e.customerEmail&&(y.customerEmail=e.customerEmail),e.customerName&&(y.customerName=e.customerName),e.externalCustomerId&&(y.externalCustomerId=e.externalCustomerId);let A=await fetch(`${s}/v1/checkout/sessions`,{method:"POST",headers:a,body:JSON.stringify(y)});if(!A.ok){let R=await A.json().catch(()=>({}));throw console.error("[Recur SDK] Failed to create checkout session:",R),new Error(R.error?.message||R.error||"Failed to create checkout session")}let ge=await A.json(),E=w(ge);console.log("[Recur SDK] Checkout session created:",E),console.log("[Recur SDK] Redirecting to hosted checkout:",E.url),window.location.href=E.url;return}let d=null;if(c==="modal"){let y=this.createDialogWithSkeleton(e.onClose);r=y.dialog,d=y.container}else if(c==="iframe"){if(d=this.getEmbeddedContainer(e.container),!d)throw new Error("Container is required for iframe mode");d.innerHTML="";let y=document.createElement("recur-payment-form-skeleton");d.appendChild(y)}console.log("[Recur SDK] Step 1: Creating embedded checkout...");let p={customerName:e.customerName,customerEmail:e.customerEmail};o&&(p.productId=o),i&&(p.productSlug=i),e.externalCustomerId&&(p.externalCustomerId=e.externalCustomerId),e.successUrl&&(p.successUrl=e.successUrl),e.cancelUrl&&(p.cancelUrl=e.cancelUrl);let m=await fetch(`${s}/v1/checkouts`,{method:"POST",headers:a,body:JSON.stringify(p)});if(!m.ok){let y=await m.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",y);let A=y.details||y.error||"Failed to create checkout";throw new Error(A)}let x=await m.json(),u=w(x);if(console.log("[Recur SDK] Checkout created successfully:",u),e.onSuccess?.(u),console.log("[Recur SDK] Step 2: Extracting SDK token..."),!u.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let T=!u.livemode;if(console.log("[Recur SDK] Environment:",T?"SANDBOX":"PRODUCTION"),await ht(T),console.log("[Recur SDK] PAYUNi SDK loaded successfully"),!window.UniPayment)throw new Error("PAYUNi SDK failed to load");if(console.log("[Recur SDK] Step 4: Rendering payment form..."),!d)throw new Error("Payment container not available");d.innerHTML="";let f=document.createElement("recur-payment-form");if(f.setAttribute("container-id",d.id||"recur-payment-container"),u.checkout?.id&&f.setAttribute("checkout-id",u.checkout.id),f.setAttribute("api-base-url",s),e.customerName&&f.setAttribute("customer-name",e.customerName),e.customerEmail&&f.setAttribute("customer-email",e.customerEmail),u.product?.name&&f.setAttribute("product-name",u.product.name),u.checkout?.amount&&f.setAttribute("amount",u.checkout.amount.toString()),u.product?.interval&&f.setAttribute("interval",u.product.interval),f.setAttribute("custom-styles",`
1963
1959
  .form-input-focus {
1964
1960
  border-color: var(--ring, hsl(215 16% 47%)) !important;
1965
1961
  outline: 0 !important;
1966
1962
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
1967
1963
  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
1968
1964
  }
1969
- `),d.appendChild(f),await new Promise(y=>setTimeout(y,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await f.initializePayment(u.sdkToken,T?"SANDBOX":"PRODUCTION")===null){console.log("[Recur SDK] Initialization aborted");return}console.log("[Recur SDK] PAYUNi SDK initialized successfully"),console.log("[Recur SDK] Step 6: Setting up submit handler..."),f.addEventListener("submit",(async y=>{console.log("[Recur SDK] Form submitted");let A=y,{paymentSession:ge}=A.detail;try{let E=await ge.getTradeResult();console.log("[Recur SDK] Trade result received"),console.log("[Recur SDK] Executing payment...");let R=E.HashTimestamp||E.timestamp,Te={};if(u.checkout.productType==="SUBSCRIPTION"){let $=u.creditToken,_=u.sdkTimestamp;if(!$)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");Te={creditToken:$,timestamp:_||R},console.log("[Recur SDK] Using creditToken from checkout:",$.substring(0,30)+"..."),console.log("[Recur SDK] Using timestamp:",_?"from checkout (sdkTimestamp)":"from tradeResult")}let fe=await fetch(`${s}/v1/checkouts/${u.checkout.id}/pay`,{method:"POST",headers:a,body:JSON.stringify(Te)});if(!fe.ok){let $=await fe.json().catch(()=>({}));throw new Error($.error||"Failed to execute payment")}let gt=await fe.json(),g=w(gt);if(console.log("[Recur SDK] Payment executed:",g),g.requires3D&&g.redirectUrl){if(console.log("[Recur SDK] 3D verification required"),/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||/wv|WebView|FBAN|FBAV|Instagram|Line|MicroMessenger|QQ/i.test(navigator.userAgent)||/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent)||"standalone"in navigator&&navigator.standalone){console.log("[Recur SDK] Mobile/WebView detected, using redirect for 3D verification"),window.location.href=g.redirectUrl;return}console.log("[Recur SDK] Using popup for 3D verification");{let _=window.open(g.redirectUrl,"recur_3d_verification","width=500,height=700,scrollbars=yes,resizable=yes");if(!_){console.log("[Recur SDK] Popup was blocked (null), falling back to redirect"),window.location.href=g.redirectUrl;return}if(await new Promise(O=>setTimeout(O,100)),_.closed){console.log("[Recur SDK] Popup was closed immediately, falling back to redirect"),window.location.href=g.redirectUrl;return}f.setVerifying?.(!0);let Q=u.checkout.id,$e=u.checkout.clientSecret,ft=90,bt=2e3,z=!0,Ie=!1,Ae;console.log("[Recur SDK] Starting 3D verification polling...");for(let O=0;O<ft&&z;O++){if(_.closed){console.log("[Recur SDK] Popup was closed");try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent($e)}`,{headers:a});if(v.ok){let K=await v.json();if(K.checkout?.status==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded after popup close"),z=!1,Ie=!0,Ae=K.checkout?.orderId;break}}}catch(v){console.error("[Recur SDK] Final status check failed:",v)}throw console.log("[Recur SDK] Payment not confirmed, user closed popup"),f.setVerifying?.(!1),f.resetButton?.(),new Error("3D \u9A57\u8B49\u5DF2\u53D6\u6D88")}try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent($e)}`,{headers:a});if(v.ok){let K=await v.json(),ee=K.checkout?.status;if(console.log(`[Recur SDK] Poll ${O+1}: status = ${ee}`),ee==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded"),z=!1;try{_.close()}catch{}f.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:K.checkout?.orderId||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove());return}if(ee==="CANCELED"||ee==="FAILED"){console.log("[Recur SDK] Payment failed or canceled"),z=!1;try{_.close()}catch{}throw f.setVerifying?.(!1),f.resetButton?.(),new Error("\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")}}}catch(v){if(v.message==="3D \u9A57\u8B49\u5DF2\u53D6\u6D88"||v.message==="\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")throw v;console.error("[Recur SDK] Poll error:",v)}await new Promise(v=>setTimeout(v,bt))}if(z){console.log("[Recur SDK] 3D verification polling timeout");try{_.close()}catch{}throw f.setVerifying?.(!1),f.resetButton?.(),new Error("3D \u9A57\u8B49\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66")}Ie&&(console.log("[Recur SDK] Handling success after popup close"),f.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:Ae||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove()));return}}if(e.onPaymentComplete)if(g.subscription)e.onPaymentComplete({id:g.subscription.id,status:g.subscription.status,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd});else{let $=g.charge?.id||g.paymentIntent?.id,_=g.charge?.status||"SUCCEEDED";e.onPaymentComplete({id:$,status:_,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})}console.log("[Recur SDK] Checkout flow completed successfully!"),f.resetButton?.(),r&&(r.close(),r.remove())}catch(E){console.error("[Recur SDK] Payment error:",E);let R={code:"PAYMENT_FAILED",message:E instanceof Error?E.message:"Payment failed"};e.onError?.(R),f.resetButton?.()}})),console.log("[Recur SDK] Checkout flow initialized, waiting for user input...")}catch(s){console.error("[Recur SDK] Checkout error:",s),r&&(r.close(),r.remove());let a={code:"CHECKOUT_ERROR",message:s instanceof Error?s.message:"An unknown error occurred"};throw e.onError?.(a),s}}getBaseUrl(){let e=this.core.getConfig();if(e.baseUrl)return e.baseUrl;if(typeof window<"u"){let t=window.location.hostname;if(t==="localhost"||t.includes(".test")||t.includes(".local")||t==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}injectDialogStyles(){if(document.getElementById("recur-dialog-styles"))return;let e=document.createElement("style");e.id="recur-dialog-styles",e.textContent=`
1965
+ `),d.appendChild(f),await new Promise(y=>setTimeout(y,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await f.initializePayment(u.sdkToken,T?"SANDBOX":"PRODUCTION")===null){console.log("[Recur SDK] Initialization aborted");return}console.log("[Recur SDK] PAYUNi SDK initialized successfully"),console.log("[Recur SDK] Step 6: Setting up submit handler..."),f.addEventListener("submit",(async y=>{console.log("[Recur SDK] Form submitted");let A=y,{paymentSession:ge}=A.detail;try{let E=await ge.getTradeResult();console.log("[Recur SDK] Trade result received"),console.log("[Recur SDK] Executing payment...");let R=E.HashTimestamp||E.timestamp,Te={};if(u.checkout.productType==="SUBSCRIPTION"){let I=u.creditToken,_=u.sdkTimestamp;if(!I)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");Te={creditToken:I,timestamp:_||R},console.log("[Recur SDK] Using creditToken from checkout:",I.substring(0,30)+"..."),console.log("[Recur SDK] Using timestamp:",_?"from checkout (sdkTimestamp)":"from tradeResult")}let fe=await fetch(`${s}/v1/checkouts/${u.checkout.id}/pay`,{method:"POST",headers:a,body:JSON.stringify(Te)});if(!fe.ok){let I=await fe.json().catch(()=>({}));throw new Error(I.error||"Failed to execute payment")}let gt=await fe.json(),g=w(gt);if(console.log("[Recur SDK] Payment executed:",g),g.requires3D&&g.redirectUrl){if(console.log("[Recur SDK] 3D verification required"),/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||/wv|WebView|FBAN|FBAV|Instagram|Line|MicroMessenger|QQ/i.test(navigator.userAgent)||/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent)||"standalone"in navigator&&navigator.standalone){console.log("[Recur SDK] Mobile/WebView detected, using redirect for 3D verification"),window.location.href=g.redirectUrl;return}console.log("[Recur SDK] Using popup for 3D verification");{let _=window.open(g.redirectUrl,"recur_3d_verification","width=500,height=700,scrollbars=yes,resizable=yes");if(!_){console.log("[Recur SDK] Popup was blocked (null), falling back to redirect"),window.location.href=g.redirectUrl;return}if(await new Promise(O=>setTimeout(O,100)),_.closed){console.log("[Recur SDK] Popup was closed immediately, falling back to redirect"),window.location.href=g.redirectUrl;return}f.setVerifying?.(!0);let Q=u.checkout.id,Ie=u.checkout.clientSecret,ft=90,bt=2e3,z=!0,$e=!1,Ae;console.log("[Recur SDK] Starting 3D verification polling...");for(let O=0;O<ft&&z;O++){if(_.closed){console.log("[Recur SDK] Popup was closed");try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent(Ie)}`,{headers:a});if(v.ok){let K=await v.json();if(K.checkout?.status==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded after popup close"),z=!1,$e=!0,Ae=K.checkout?.orderId;break}}}catch(v){console.error("[Recur SDK] Final status check failed:",v)}throw console.log("[Recur SDK] Payment not confirmed, user closed popup"),f.setVerifying?.(!1),f.resetButton?.(),new Error("3D \u9A57\u8B49\u5DF2\u53D6\u6D88")}try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent(Ie)}`,{headers:a});if(v.ok){let K=await v.json(),ee=K.checkout?.status;if(console.log(`[Recur SDK] Poll ${O+1}: status = ${ee}`),ee==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded"),z=!1;try{_.close()}catch{}f.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:K.checkout?.orderId||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove());return}if(ee==="CANCELED"||ee==="FAILED"){console.log("[Recur SDK] Payment failed or canceled"),z=!1;try{_.close()}catch{}throw f.setVerifying?.(!1),f.resetButton?.(),new Error("\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")}}}catch(v){if(v.message==="3D \u9A57\u8B49\u5DF2\u53D6\u6D88"||v.message==="\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")throw v;console.error("[Recur SDK] Poll error:",v)}await new Promise(v=>setTimeout(v,bt))}if(z){console.log("[Recur SDK] 3D verification polling timeout");try{_.close()}catch{}throw f.setVerifying?.(!1),f.resetButton?.(),new Error("3D \u9A57\u8B49\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66")}$e&&(console.log("[Recur SDK] Handling success after popup close"),f.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:Ae||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove()));return}}if(e.onPaymentComplete)if(g.subscription)e.onPaymentComplete({id:g.subscription.id,status:g.subscription.status,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd});else{let I=g.charge?.id||g.paymentIntent?.id,_=g.charge?.status||"SUCCEEDED";e.onPaymentComplete({id:I,status:_,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})}console.log("[Recur SDK] Checkout flow completed successfully!"),f.resetButton?.(),r&&(r.close(),r.remove())}catch(E){console.error("[Recur SDK] Payment error:",E);let R={code:"PAYMENT_FAILED",message:E instanceof Error?E.message:"Payment failed"};e.onError?.(R),f.resetButton?.()}})),console.log("[Recur SDK] Checkout flow initialized, waiting for user input...")}catch(s){console.error("[Recur SDK] Checkout error:",s),r&&(r.close(),r.remove());let a={code:"CHECKOUT_ERROR",message:s instanceof Error?s.message:"An unknown error occurred"};throw e.onError?.(a),s}}getBaseUrl(){let e=this.core.getConfig();if(e.baseUrl)return e.baseUrl;if(typeof window<"u"){let t=window.location.hostname;if(t==="localhost"||t.includes(".test")||t.includes(".local")||t==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}injectDialogStyles(){if(document.getElementById("recur-dialog-styles"))return;let e=document.createElement("style");e.id="recur-dialog-styles",e.textContent=`
1970
1966
  .recur-dialog {
1971
1967
  border: none;
1972
1968
  border-radius: 12px;
@@ -2022,7 +2018,7 @@
2022
2018
  .recur-dialog__close:hover {
2023
2019
  background: rgba(0, 0, 0, 0.1);
2024
2020
  }
2025
- `,document.head.appendChild(e)}createDialogWithSkeleton(e){this.closeDialog(),this.injectDialogStyles();let t=document.createElement("dialog");t.id="recur-dialog",t.className="recur-dialog";let r=document.createElement("div");r.className="recur-dialog__content";let o=document.createElement("button");o.className="recur-dialog__close",o.innerHTML="\u2715",o.type="button",o.onclick=()=>{this.closeDialog(),e?.()};let i=document.createElement("div");i.id="recur-dialog-payment-container";let s=document.createElement("recur-payment-form-skeleton");return i.appendChild(s),r.appendChild(o),r.appendChild(i),t.appendChild(r),document.body.appendChild(t),t.showModal(),t.addEventListener("cancel",a=>{a.preventDefault(),this.closeDialog(),e?.()}),this.currentDialogElement=t,{dialog:t,container:i}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeDialog(){this.currentDialog&&(this.currentDialog.close(),this.currentDialog=null),this.currentDialogElement&&(this.currentDialogElement.close(),this.currentDialogElement.remove(),this.currentDialogElement=null)}closeModal(){this.closeDialog()}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async createPortalSession(e,t){let r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({customerId:t.customerId,returnUrl:t.returnUrl})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error?.message||i.message||"Failed to create portal session")}let o=await r.json();return{id:o.id,url:o.url||o.portalUrl,expiresAt:o.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function ht(n){return new G(n)}var Nt={init:ht,RecurCheckout:G,RecurElements:N,createElements:Se};return _t(zt);})();
2021
+ `,document.head.appendChild(e)}createDialogWithSkeleton(e){this.closeDialog(),this.injectDialogStyles();let t=document.createElement("dialog");t.id="recur-dialog",t.className="recur-dialog";let r=document.createElement("div");r.className="recur-dialog__content";let o=document.createElement("button");o.className="recur-dialog__close",o.innerHTML="\u2715",o.type="button",o.onclick=()=>{this.closeDialog(),e?.()};let i=document.createElement("div");i.id="recur-dialog-payment-container";let s=document.createElement("recur-payment-form-skeleton");return i.appendChild(s),r.appendChild(o),r.appendChild(i),t.appendChild(r),document.body.appendChild(t),t.showModal(),t.addEventListener("cancel",a=>{a.preventDefault(),this.closeDialog(),e?.()}),this.currentDialogElement=t,{dialog:t,container:i}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeDialog(){this.currentDialog&&(this.currentDialog.close(),this.currentDialog=null),this.currentDialogElement&&(this.currentDialogElement.close(),this.currentDialogElement.remove(),this.currentDialogElement=null)}closeModal(){this.closeDialog()}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async createPortalSession(e,t){let r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({customerId:t.customerId,returnUrl:t.returnUrl})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error?.message||i.message||"Failed to create portal session")}let o=await r.json();return{id:o.id,url:o.url||o.portalUrl,expiresAt:o.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function mt(n){return new G(n)}var Nt={init:mt,RecurCheckout:G,RecurElements:N,createElements:Se};return _t(zt);})();
2026
2022
  /*! Bundled license information:
2027
2023
 
2028
2024
  lit-html/node/lit-html.js:
package/dist/server.cjs CHANGED
@@ -20,7 +20,7 @@ var RecurAPIError = class extends Error {
20
20
 
21
21
  // package.json
22
22
  var package_default = {
23
- version: "0.9.11"};
23
+ version: "0.9.12"};
24
24
 
25
25
  // src/server/resources/portal.ts
26
26
  var SDK_VERSION = package_default.version;
package/dist/server.js CHANGED
@@ -18,7 +18,7 @@ var RecurAPIError = class extends Error {
18
18
 
19
19
  // package.json
20
20
  var package_default = {
21
- version: "0.9.11"};
21
+ version: "0.9.12"};
22
22
 
23
23
  // src/server/resources/portal.ts
24
24
  var SDK_VERSION = package_default.version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recur-tw",
3
- "version": "0.9.11",
3
+ "version": "0.9.12",
4
4
  "description": "React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",
5
5
  "type": "module",
6
6
  "private": false,