recur-tw 0.9.11 → 0.9.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js 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-wrapper {\n position: relative;\n flex: 1;\n}\n\n.recur-coupon__input {\n width: 100%;\n height: 36px;\n padding: 0 32px 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__clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #9ca3af;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.2s;\n}\n\n.recur-coupon__clear:hover {\n color: #6b7280;\n}\n\n.recur-coupon__clear-icon {\n width: 16px;\n height: 16px;\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__error {\n width: 100%;\n margin-top: 8px;\n font-size: 13px;\n color: #dc2626;\n}\n\n.recur-coupon__applied-wrapper {\n width: 100%;\n}\n\n.recur-coupon__description {\n font-size: 12px;\n color: #6b7280;\n margin: 4px 0 0 22px;\n}\n\n.recur-coupon__bonus {\n display: flex;\n align-items: center;\n gap: 6px;\n background: #dcfce7;\n border-radius: 6px;\n padding: 8px 12px;\n margin-top: 8px;\n font-size: 12px;\n color: #15803d;\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
 
@@ -1063,6 +1063,11 @@ var init_payment_form = __esm({
1063
1063
  <svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1064
1064
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
1065
1065
  </svg>
1066
+ `,
1067
+ clearInput: html`
1068
+ <svg class="recur-coupon__clear-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1069
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
1070
+ </svg>
1066
1071
  `,
1067
1072
  spinner: html`<span class="recur-coupon__spinner"></span>`
1068
1073
  };
@@ -1218,19 +1223,12 @@ var init_payment_form = __esm({
1218
1223
  const amount = this.getAttribute("amount");
1219
1224
  const interval = this.getAttribute("interval");
1220
1225
  if (!productName || !amount) {
1221
- const isSubscription2 = !!interval;
1222
1226
  return html`
1223
1227
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1224
1228
  <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>
1229
+ <span class="recur-order-summary__label">方案</span>
1230
+ <span class="recur-order-summary__value recur-skeleton" style="width: 120px; height: 20px;"></span>
1227
1231
  </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
1232
  <div class="recur-order-summary__row">
1235
1233
  <span class="recur-order-summary__label">小計</span>
1236
1234
  <span class="recur-order-summary__value recur-skeleton" style="width: 80px; height: 20px;"></span>
@@ -1255,21 +1253,14 @@ var init_payment_form = __esm({
1255
1253
  const originalAmount = Number(amount);
1256
1254
  const discountAmount = this._appliedCoupon?.discountAmount || 0;
1257
1255
  const finalAmount = originalAmount - discountAmount;
1258
- const isSubscription = !!periodText;
1256
+ const productDisplay = periodText ? `${productName} / \u6BCF${periodText}` : productName;
1259
1257
  return html`
1260
1258
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1261
1259
  <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>
1260
+ <span class="recur-order-summary__label">方案</span>
1261
+ <span class="recur-order-summary__value">${productDisplay}</span>
1264
1262
  </div>
1265
1263
 
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
1264
  <!-- 小計 (Subtotal) - always show -->
1274
1265
  <div class="recur-order-summary__row">
1275
1266
  <span class="recur-order-summary__label">小計</span>
@@ -1289,30 +1280,106 @@ var init_payment_form = __esm({
1289
1280
  </div>
1290
1281
  `;
1291
1282
  }
1283
+ // Helper to get interval text in Chinese
1284
+ getIntervalText(interval, count) {
1285
+ if (!interval) return "";
1286
+ const countText = count && count > 1 ? count.toString() : "";
1287
+ switch (interval.toUpperCase()) {
1288
+ case "MONTH":
1289
+ return `${countText}\u6708`;
1290
+ case "YEAR":
1291
+ return `${countText}\u5E74`;
1292
+ case "WEEK":
1293
+ return `${countText}\u9031`;
1294
+ case "DAY":
1295
+ return `${countText}\u5929`;
1296
+ default:
1297
+ return "";
1298
+ }
1299
+ }
1300
+ // Get discount description based on type and duration
1301
+ getDiscountDescription() {
1302
+ if (!this._appliedCoupon) return null;
1303
+ const { discountType, duration, durationMonths, productPrice, productInterval, productIntervalCount } = this._appliedCoupon;
1304
+ const intervalText = this.getIntervalText(productInterval, productIntervalCount);
1305
+ const originalPriceText = productPrice && intervalText ? `NT$ ${productPrice.toLocaleString()}/${intervalText}` : productPrice ? `NT$ ${productPrice.toLocaleString()}` : "";
1306
+ const amount = parseInt(this.getAttribute("amount") || "0", 10);
1307
+ const finalAmount = amount - this._appliedCoupon.discountAmount;
1308
+ if (discountType === "FIRST_PERIOD_PRICE") {
1309
+ if (originalPriceText) {
1310
+ return `\u9996\u671F\u53EA\u9700 NT$ ${finalAmount.toLocaleString()}\uFF0C\u4E4B\u5F8C ${originalPriceText}`;
1311
+ }
1312
+ return `\u9996\u671F\u53EA\u9700 NT$ ${finalAmount.toLocaleString()}`;
1313
+ }
1314
+ if (duration) {
1315
+ switch (duration) {
1316
+ case "ONCE":
1317
+ if (originalPriceText) {
1318
+ return `\u9996\u671F\u6298\u6263\uFF0C\u4E4B\u5F8C ${originalPriceText}`;
1319
+ }
1320
+ return "\u50C5\u9650\u9996\u671F";
1321
+ case "REPEATING":
1322
+ if (durationMonths) {
1323
+ return `\u524D ${durationMonths} \u671F\u4EAB\u512A\u60E0\uFF0C\u4E4B\u5F8C\u6062\u5FA9\u539F\u50F9`;
1324
+ }
1325
+ return null;
1326
+ case "FOREVER":
1327
+ return "\u7D42\u8EAB\u512A\u60E0";
1328
+ default:
1329
+ return null;
1330
+ }
1331
+ }
1332
+ return null;
1333
+ }
1334
+ // Get bonus description
1335
+ getBonusDescription() {
1336
+ if (!this._appliedCoupon) return null;
1337
+ const parts = [];
1338
+ if (this._appliedCoupon.bonusTrialDays) {
1339
+ parts.push(`\u5EF6\u9577\u8A66\u7528 ${this._appliedCoupon.bonusTrialDays} \u5929`);
1340
+ }
1341
+ if (this._appliedCoupon.bonusMonths) {
1342
+ parts.push(`\u52A0\u9001 ${this._appliedCoupon.bonusMonths} \u500B\u6708`);
1343
+ }
1344
+ return parts.length > 0 ? parts.join("\u3001") : null;
1345
+ }
1292
1346
  renderCoupon() {
1293
1347
  if (this._appliedCoupon) {
1348
+ const discountDescription = this.getDiscountDescription();
1349
+ const bonusDescription = this.getBonusDescription();
1294
1350
  return html`
1295
- <div class="recur-coupon__applied">
1296
- <div class="recur-coupon__applied-info">
1297
- ${icons.tagApplied}
1298
- ${this._appliedCoupon.couponName ? html`
1299
- <span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
1300
- <span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
1301
- ` : html`
1302
- <span class="recur-coupon__applied-name">${this._appliedCoupon.code}</span>
1303
- `}
1304
- <button
1305
- type="button"
1306
- class="recur-coupon__remove"
1307
- ?disabled=${this._couponLoading}
1308
- @click=${() => this.removeCoupon()}
1309
- >
1310
- ${this._couponLoading ? icons.spinner : icons.close}
1311
- </button>
1351
+ <div class="recur-coupon__applied-wrapper">
1352
+ <div class="recur-coupon__applied">
1353
+ <div class="recur-coupon__applied-info">
1354
+ ${icons.tagApplied}
1355
+ ${this._appliedCoupon.couponName ? html`
1356
+ <span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
1357
+ <span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
1358
+ ` : html`
1359
+ <span class="recur-coupon__applied-name">${this._appliedCoupon.code}</span>
1360
+ `}
1361
+ <button
1362
+ type="button"
1363
+ class="recur-coupon__remove"
1364
+ ?disabled=${this._couponLoading}
1365
+ @click=${() => this.removeCoupon()}
1366
+ >
1367
+ ${this._couponLoading ? icons.spinner : icons.close}
1368
+ </button>
1369
+ </div>
1370
+ <span class="recur-coupon__applied-amount">
1371
+ -NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
1372
+ </span>
1312
1373
  </div>
1313
- <span class="recur-coupon__applied-amount">
1314
- -NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
1315
- </span>
1374
+ ${discountDescription ? html`
1375
+ <p class="recur-coupon__description">${discountDescription}</p>
1376
+ ` : nothing}
1377
+ ${bonusDescription ? html`
1378
+ <div class="recur-coupon__bonus">
1379
+ <span>✨</span>
1380
+ <span>${bonusDescription}</span>
1381
+ </div>
1382
+ ` : nothing}
1316
1383
  </div>
1317
1384
  `;
1318
1385
  }
@@ -1320,16 +1387,28 @@ var init_payment_form = __esm({
1320
1387
  return html`
1321
1388
  <div style="width: 100%;">
1322
1389
  <div class="recur-coupon__input-row">
1323
- <input
1324
- type="text"
1325
- class="recur-coupon__input"
1326
- id="${this.containerId}-coupon-input"
1327
- placeholder="輸入優惠碼"
1328
- .value=${this._couponCode}
1329
- ?disabled=${this._couponLoading}
1330
- @input=${(e) => this.handleCouponInputChange(e)}
1331
- @keydown=${(e) => this.handleCouponKeydown(e)}
1332
- />
1390
+ <div class="recur-coupon__input-wrapper">
1391
+ <input
1392
+ type="text"
1393
+ class="recur-coupon__input"
1394
+ id="${this.containerId}-coupon-input"
1395
+ placeholder="輸入優惠碼"
1396
+ .value=${this._couponCode}
1397
+ ?disabled=${this._couponLoading}
1398
+ @input=${(e) => this.handleCouponInputChange(e)}
1399
+ @keydown=${(e) => this.handleCouponKeydown(e)}
1400
+ />
1401
+ ${this._couponCode && !this._couponLoading ? html`
1402
+ <button
1403
+ type="button"
1404
+ class="recur-coupon__clear"
1405
+ @click=${() => this.clearCouponInput()}
1406
+ aria-label="清除"
1407
+ >
1408
+ ${icons.clearInput}
1409
+ </button>
1410
+ ` : nothing}
1411
+ </div>
1333
1412
  <button
1334
1413
  type="button"
1335
1414
  class="recur-coupon__btn recur-coupon__btn--apply"
@@ -1338,14 +1417,6 @@ var init_payment_form = __esm({
1338
1417
  >
1339
1418
  ${this._couponLoading ? icons.spinner : "\u5957\u7528"}
1340
1419
  </button>
1341
- <button
1342
- type="button"
1343
- class="recur-coupon__btn recur-coupon__btn--cancel"
1344
- ?disabled=${this._couponLoading}
1345
- @click=${() => this.cancelCouponInput()}
1346
- >
1347
- 取消
1348
- </button>
1349
1420
  </div>
1350
1421
  ${this._couponError ? html`
1351
1422
  <div class="recur-coupon__error">${this._couponError}</div>
@@ -1380,6 +1451,15 @@ var init_payment_form = __esm({
1380
1451
  this._couponError = null;
1381
1452
  this.updateCouponSectionDOM();
1382
1453
  }
1454
+ clearCouponInput() {
1455
+ this._couponCode = "";
1456
+ this._couponError = null;
1457
+ this.updateCouponSectionDOM();
1458
+ requestAnimationFrame(() => {
1459
+ const input = document.getElementById(`${this.containerId}-coupon-input`);
1460
+ input?.focus();
1461
+ });
1462
+ }
1383
1463
  handleCouponInputChange(e) {
1384
1464
  this._couponCode = e.target.value.toUpperCase();
1385
1465
  this._couponError = null;
@@ -1427,17 +1507,25 @@ var init_payment_form = __esm({
1427
1507
  }
1428
1508
  getCouponInputHTML() {
1429
1509
  const errorHTML = this._couponError ? `<div class="recur-coupon__error">${this._couponError}</div>` : "";
1510
+ const clearBtnHTML = this._couponCode && !this._couponLoading ? `<button type="button" class="recur-coupon__clear" aria-label="\u6E05\u9664">
1511
+ <svg class="recur-coupon__clear-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1512
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
1513
+ </svg>
1514
+ </button>` : "";
1430
1515
  return `
1431
1516
  <div style="width: 100%;">
1432
1517
  <div class="recur-coupon__input-row">
1433
- <input
1434
- type="text"
1435
- class="recur-coupon__input"
1436
- id="${this.containerId}-coupon-input"
1437
- placeholder="\u8F38\u5165\u512A\u60E0\u78BC"
1438
- value="${this._couponCode}"
1439
- ${this._couponLoading ? "disabled" : ""}
1440
- />
1518
+ <div class="recur-coupon__input-wrapper">
1519
+ <input
1520
+ type="text"
1521
+ class="recur-coupon__input"
1522
+ id="${this.containerId}-coupon-input"
1523
+ placeholder="\u8F38\u5165\u512A\u60E0\u78BC"
1524
+ value="${this._couponCode}"
1525
+ ${this._couponLoading ? "disabled" : ""}
1526
+ />
1527
+ ${clearBtnHTML}
1528
+ </div>
1441
1529
  <button
1442
1530
  type="button"
1443
1531
  class="recur-coupon__btn recur-coupon__btn--apply"
@@ -1445,13 +1533,6 @@ var init_payment_form = __esm({
1445
1533
  >
1446
1534
  ${this._couponLoading ? '<span class="recur-coupon__spinner"></span>' : "\u5957\u7528"}
1447
1535
  </button>
1448
- <button
1449
- type="button"
1450
- class="recur-coupon__btn recur-coupon__btn--cancel"
1451
- ${this._couponLoading ? "disabled" : ""}
1452
- >
1453
- \u53D6\u6D88
1454
- </button>
1455
1536
  </div>
1456
1537
  ${errorHTML}
1457
1538
  </div>
@@ -1460,18 +1541,26 @@ var init_payment_form = __esm({
1460
1541
  getCouponAppliedHTML() {
1461
1542
  const coupon = this._appliedCoupon;
1462
1543
  const nameHTML = coupon.couponName ? `<span class="recur-coupon__applied-name">${coupon.couponName}</span><span class="recur-coupon__applied-code">(${coupon.code})</span>` : `<span class="recur-coupon__applied-name">${coupon.code}</span>`;
1544
+ const discountDescription = this.getDiscountDescription();
1545
+ const bonusDescription = this.getBonusDescription();
1546
+ const descriptionHTML = discountDescription ? `<p class="recur-coupon__description">${discountDescription}</p>` : "";
1547
+ const bonusHTML = bonusDescription ? `<div class="recur-coupon__bonus"><span>\u2728</span><span>${bonusDescription}</span></div>` : "";
1463
1548
  return `
1464
- <div class="recur-coupon__applied">
1465
- <div class="recur-coupon__applied-info">
1466
- <svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1467
- <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" />
1468
- </svg>
1469
- ${nameHTML}
1470
- <button type="button" class="recur-coupon__remove" ${this._couponLoading ? "disabled" : ""}>
1471
- ${this._couponLoading ? '<span class="recur-coupon__spinner"></span>' : '<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>'}
1472
- </button>
1549
+ <div class="recur-coupon__applied-wrapper">
1550
+ <div class="recur-coupon__applied">
1551
+ <div class="recur-coupon__applied-info">
1552
+ <svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1553
+ <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" />
1554
+ </svg>
1555
+ ${nameHTML}
1556
+ <button type="button" class="recur-coupon__remove" ${this._couponLoading ? "disabled" : ""}>
1557
+ ${this._couponLoading ? '<span class="recur-coupon__spinner"></span>' : '<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>'}
1558
+ </button>
1559
+ </div>
1560
+ <span class="recur-coupon__applied-amount">-NT$ ${coupon.discountAmount.toLocaleString()}</span>
1473
1561
  </div>
1474
- <span class="recur-coupon__applied-amount">-NT$ ${coupon.discountAmount.toLocaleString()}</span>
1562
+ ${descriptionHTML}
1563
+ ${bonusHTML}
1475
1564
  </div>
1476
1565
  `;
1477
1566
  }
@@ -1482,11 +1571,11 @@ var init_payment_form = __esm({
1482
1571
  bindCouponInputEvents(container) {
1483
1572
  const input = container.querySelector(".recur-coupon__input");
1484
1573
  const applyBtn = container.querySelector(".recur-coupon__btn--apply");
1485
- const cancelBtn = container.querySelector(".recur-coupon__btn--cancel");
1574
+ const clearBtn = container.querySelector(".recur-coupon__clear");
1486
1575
  input?.addEventListener("input", (e) => this.handleCouponInputChange(e));
1487
1576
  input?.addEventListener("keydown", (e) => this.handleCouponKeydown(e));
1488
1577
  applyBtn?.addEventListener("click", () => this.applyCoupon());
1489
- cancelBtn?.addEventListener("click", () => this.cancelCouponInput());
1578
+ clearBtn?.addEventListener("click", () => this.clearCouponInput());
1490
1579
  }
1491
1580
  bindCouponAppliedEvents(container) {
1492
1581
  const removeBtn = container.querySelector(".recur-coupon__remove");
@@ -1546,7 +1635,10 @@ var init_payment_form = __esm({
1546
1635
  duration: data.discount.duration,
1547
1636
  durationMonths: data.discount.durationMonths,
1548
1637
  bonusTrialDays: data.discount.bonusTrialDays,
1549
- bonusMonths: data.discount.bonusMonths
1638
+ bonusMonths: data.discount.bonusMonths,
1639
+ productInterval: data.discount.productInterval,
1640
+ productIntervalCount: data.discount.productIntervalCount,
1641
+ productPrice: data.discount.productPrice
1550
1642
  };
1551
1643
  this._showCouponInput = false;
1552
1644
  this._couponCode = "";
@@ -2554,7 +2646,7 @@ function toCamelCase(obj) {
2554
2646
 
2555
2647
  // package.json
2556
2648
  var package_default = {
2557
- version: "0.9.11"};
2649
+ version: "0.9.13"};
2558
2650
  var SDK_VERSION = package_default.version;
2559
2651
  var SDK_TYPE = "react";
2560
2652
  var RecurContext = createContext(null);
@@ -2890,7 +2982,6 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2890
2982
  paymentForm.setAttribute("interval", checkoutResult.product.interval);
2891
2983
  }
2892
2984
  const customStyles = `
2893
- /* PAYUNi SDK focus \u6A23\u5F0F - shadcn \u98A8\u683C */
2894
2985
  .form-input-focus {
2895
2986
  border-color: var(--ring, hsl(215 16% 47%)) !important;
2896
2987
  outline: 0 !important;