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.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-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";
1039
1039
  }
1040
1040
  });
1041
1041
 
@@ -1069,6 +1069,11 @@ var init_payment_form = __esm({
1069
1069
  <svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1070
1070
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
1071
1071
  </svg>
1072
+ `,
1073
+ clearInput: litHtml.html`
1074
+ <svg class="recur-coupon__clear-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1075
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
1076
+ </svg>
1072
1077
  `,
1073
1078
  spinner: litHtml.html`<span class="recur-coupon__spinner"></span>`
1074
1079
  };
@@ -1224,19 +1229,12 @@ var init_payment_form = __esm({
1224
1229
  const amount = this.getAttribute("amount");
1225
1230
  const interval = this.getAttribute("interval");
1226
1231
  if (!productName || !amount) {
1227
- const isSubscription2 = !!interval;
1228
1232
  return litHtml.html`
1229
1233
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1230
1234
  <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>
1235
+ <span class="recur-order-summary__label">方案</span>
1236
+ <span class="recur-order-summary__value recur-skeleton" style="width: 120px; height: 20px;"></span>
1233
1237
  </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
1238
  <div class="recur-order-summary__row">
1241
1239
  <span class="recur-order-summary__label">小計</span>
1242
1240
  <span class="recur-order-summary__value recur-skeleton" style="width: 80px; height: 20px;"></span>
@@ -1261,21 +1259,14 @@ var init_payment_form = __esm({
1261
1259
  const originalAmount = Number(amount);
1262
1260
  const discountAmount = this._appliedCoupon?.discountAmount || 0;
1263
1261
  const finalAmount = originalAmount - discountAmount;
1264
- const isSubscription = !!periodText;
1262
+ const productDisplay = periodText ? `${productName} / \u6BCF${periodText}` : productName;
1265
1263
  return litHtml.html`
1266
1264
  <div class="recur-order-summary" id="${this.containerId}-order-summary">
1267
1265
  <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>
1266
+ <span class="recur-order-summary__label">方案</span>
1267
+ <span class="recur-order-summary__value">${productDisplay}</span>
1270
1268
  </div>
1271
1269
 
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
1270
  <!-- 小計 (Subtotal) - always show -->
1280
1271
  <div class="recur-order-summary__row">
1281
1272
  <span class="recur-order-summary__label">小計</span>
@@ -1295,30 +1286,106 @@ var init_payment_form = __esm({
1295
1286
  </div>
1296
1287
  `;
1297
1288
  }
1289
+ // Helper to get interval text in Chinese
1290
+ getIntervalText(interval, count) {
1291
+ if (!interval) return "";
1292
+ const countText = count && count > 1 ? count.toString() : "";
1293
+ switch (interval.toUpperCase()) {
1294
+ case "MONTH":
1295
+ return `${countText}\u6708`;
1296
+ case "YEAR":
1297
+ return `${countText}\u5E74`;
1298
+ case "WEEK":
1299
+ return `${countText}\u9031`;
1300
+ case "DAY":
1301
+ return `${countText}\u5929`;
1302
+ default:
1303
+ return "";
1304
+ }
1305
+ }
1306
+ // Get discount description based on type and duration
1307
+ getDiscountDescription() {
1308
+ if (!this._appliedCoupon) return null;
1309
+ const { discountType, duration, durationMonths, productPrice, productInterval, productIntervalCount } = this._appliedCoupon;
1310
+ const intervalText = this.getIntervalText(productInterval, productIntervalCount);
1311
+ const originalPriceText = productPrice && intervalText ? `NT$ ${productPrice.toLocaleString()}/${intervalText}` : productPrice ? `NT$ ${productPrice.toLocaleString()}` : "";
1312
+ const amount = parseInt(this.getAttribute("amount") || "0", 10);
1313
+ const finalAmount = amount - this._appliedCoupon.discountAmount;
1314
+ if (discountType === "FIRST_PERIOD_PRICE") {
1315
+ if (originalPriceText) {
1316
+ return `\u9996\u671F\u53EA\u9700 NT$ ${finalAmount.toLocaleString()}\uFF0C\u4E4B\u5F8C ${originalPriceText}`;
1317
+ }
1318
+ return `\u9996\u671F\u53EA\u9700 NT$ ${finalAmount.toLocaleString()}`;
1319
+ }
1320
+ if (duration) {
1321
+ switch (duration) {
1322
+ case "ONCE":
1323
+ if (originalPriceText) {
1324
+ return `\u9996\u671F\u6298\u6263\uFF0C\u4E4B\u5F8C ${originalPriceText}`;
1325
+ }
1326
+ return "\u50C5\u9650\u9996\u671F";
1327
+ case "REPEATING":
1328
+ if (durationMonths) {
1329
+ return `\u524D ${durationMonths} \u671F\u4EAB\u512A\u60E0\uFF0C\u4E4B\u5F8C\u6062\u5FA9\u539F\u50F9`;
1330
+ }
1331
+ return null;
1332
+ case "FOREVER":
1333
+ return "\u7D42\u8EAB\u512A\u60E0";
1334
+ default:
1335
+ return null;
1336
+ }
1337
+ }
1338
+ return null;
1339
+ }
1340
+ // Get bonus description
1341
+ getBonusDescription() {
1342
+ if (!this._appliedCoupon) return null;
1343
+ const parts = [];
1344
+ if (this._appliedCoupon.bonusTrialDays) {
1345
+ parts.push(`\u5EF6\u9577\u8A66\u7528 ${this._appliedCoupon.bonusTrialDays} \u5929`);
1346
+ }
1347
+ if (this._appliedCoupon.bonusMonths) {
1348
+ parts.push(`\u52A0\u9001 ${this._appliedCoupon.bonusMonths} \u500B\u6708`);
1349
+ }
1350
+ return parts.length > 0 ? parts.join("\u3001") : null;
1351
+ }
1298
1352
  renderCoupon() {
1299
1353
  if (this._appliedCoupon) {
1354
+ const discountDescription = this.getDiscountDescription();
1355
+ const bonusDescription = this.getBonusDescription();
1300
1356
  return litHtml.html`
1301
- <div class="recur-coupon__applied">
1302
- <div class="recur-coupon__applied-info">
1303
- ${icons.tagApplied}
1304
- ${this._appliedCoupon.couponName ? litHtml.html`
1305
- <span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
1306
- <span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
1307
- ` : litHtml.html`
1308
- <span class="recur-coupon__applied-name">${this._appliedCoupon.code}</span>
1309
- `}
1310
- <button
1311
- type="button"
1312
- class="recur-coupon__remove"
1313
- ?disabled=${this._couponLoading}
1314
- @click=${() => this.removeCoupon()}
1315
- >
1316
- ${this._couponLoading ? icons.spinner : icons.close}
1317
- </button>
1357
+ <div class="recur-coupon__applied-wrapper">
1358
+ <div class="recur-coupon__applied">
1359
+ <div class="recur-coupon__applied-info">
1360
+ ${icons.tagApplied}
1361
+ ${this._appliedCoupon.couponName ? litHtml.html`
1362
+ <span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
1363
+ <span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
1364
+ ` : litHtml.html`
1365
+ <span class="recur-coupon__applied-name">${this._appliedCoupon.code}</span>
1366
+ `}
1367
+ <button
1368
+ type="button"
1369
+ class="recur-coupon__remove"
1370
+ ?disabled=${this._couponLoading}
1371
+ @click=${() => this.removeCoupon()}
1372
+ >
1373
+ ${this._couponLoading ? icons.spinner : icons.close}
1374
+ </button>
1375
+ </div>
1376
+ <span class="recur-coupon__applied-amount">
1377
+ -NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
1378
+ </span>
1318
1379
  </div>
1319
- <span class="recur-coupon__applied-amount">
1320
- -NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
1321
- </span>
1380
+ ${discountDescription ? litHtml.html`
1381
+ <p class="recur-coupon__description">${discountDescription}</p>
1382
+ ` : litHtml.nothing}
1383
+ ${bonusDescription ? litHtml.html`
1384
+ <div class="recur-coupon__bonus">
1385
+ <span>✨</span>
1386
+ <span>${bonusDescription}</span>
1387
+ </div>
1388
+ ` : litHtml.nothing}
1322
1389
  </div>
1323
1390
  `;
1324
1391
  }
@@ -1326,16 +1393,28 @@ var init_payment_form = __esm({
1326
1393
  return litHtml.html`
1327
1394
  <div style="width: 100%;">
1328
1395
  <div class="recur-coupon__input-row">
1329
- <input
1330
- type="text"
1331
- class="recur-coupon__input"
1332
- id="${this.containerId}-coupon-input"
1333
- placeholder="輸入優惠碼"
1334
- .value=${this._couponCode}
1335
- ?disabled=${this._couponLoading}
1336
- @input=${(e) => this.handleCouponInputChange(e)}
1337
- @keydown=${(e) => this.handleCouponKeydown(e)}
1338
- />
1396
+ <div class="recur-coupon__input-wrapper">
1397
+ <input
1398
+ type="text"
1399
+ class="recur-coupon__input"
1400
+ id="${this.containerId}-coupon-input"
1401
+ placeholder="輸入優惠碼"
1402
+ .value=${this._couponCode}
1403
+ ?disabled=${this._couponLoading}
1404
+ @input=${(e) => this.handleCouponInputChange(e)}
1405
+ @keydown=${(e) => this.handleCouponKeydown(e)}
1406
+ />
1407
+ ${this._couponCode && !this._couponLoading ? litHtml.html`
1408
+ <button
1409
+ type="button"
1410
+ class="recur-coupon__clear"
1411
+ @click=${() => this.clearCouponInput()}
1412
+ aria-label="清除"
1413
+ >
1414
+ ${icons.clearInput}
1415
+ </button>
1416
+ ` : litHtml.nothing}
1417
+ </div>
1339
1418
  <button
1340
1419
  type="button"
1341
1420
  class="recur-coupon__btn recur-coupon__btn--apply"
@@ -1344,14 +1423,6 @@ var init_payment_form = __esm({
1344
1423
  >
1345
1424
  ${this._couponLoading ? icons.spinner : "\u5957\u7528"}
1346
1425
  </button>
1347
- <button
1348
- type="button"
1349
- class="recur-coupon__btn recur-coupon__btn--cancel"
1350
- ?disabled=${this._couponLoading}
1351
- @click=${() => this.cancelCouponInput()}
1352
- >
1353
- 取消
1354
- </button>
1355
1426
  </div>
1356
1427
  ${this._couponError ? litHtml.html`
1357
1428
  <div class="recur-coupon__error">${this._couponError}</div>
@@ -1386,6 +1457,15 @@ var init_payment_form = __esm({
1386
1457
  this._couponError = null;
1387
1458
  this.updateCouponSectionDOM();
1388
1459
  }
1460
+ clearCouponInput() {
1461
+ this._couponCode = "";
1462
+ this._couponError = null;
1463
+ this.updateCouponSectionDOM();
1464
+ requestAnimationFrame(() => {
1465
+ const input = document.getElementById(`${this.containerId}-coupon-input`);
1466
+ input?.focus();
1467
+ });
1468
+ }
1389
1469
  handleCouponInputChange(e) {
1390
1470
  this._couponCode = e.target.value.toUpperCase();
1391
1471
  this._couponError = null;
@@ -1433,17 +1513,25 @@ var init_payment_form = __esm({
1433
1513
  }
1434
1514
  getCouponInputHTML() {
1435
1515
  const errorHTML = this._couponError ? `<div class="recur-coupon__error">${this._couponError}</div>` : "";
1516
+ const clearBtnHTML = this._couponCode && !this._couponLoading ? `<button type="button" class="recur-coupon__clear" aria-label="\u6E05\u9664">
1517
+ <svg class="recur-coupon__clear-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1518
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
1519
+ </svg>
1520
+ </button>` : "";
1436
1521
  return `
1437
1522
  <div style="width: 100%;">
1438
1523
  <div class="recur-coupon__input-row">
1439
- <input
1440
- type="text"
1441
- class="recur-coupon__input"
1442
- id="${this.containerId}-coupon-input"
1443
- placeholder="\u8F38\u5165\u512A\u60E0\u78BC"
1444
- value="${this._couponCode}"
1445
- ${this._couponLoading ? "disabled" : ""}
1446
- />
1524
+ <div class="recur-coupon__input-wrapper">
1525
+ <input
1526
+ type="text"
1527
+ class="recur-coupon__input"
1528
+ id="${this.containerId}-coupon-input"
1529
+ placeholder="\u8F38\u5165\u512A\u60E0\u78BC"
1530
+ value="${this._couponCode}"
1531
+ ${this._couponLoading ? "disabled" : ""}
1532
+ />
1533
+ ${clearBtnHTML}
1534
+ </div>
1447
1535
  <button
1448
1536
  type="button"
1449
1537
  class="recur-coupon__btn recur-coupon__btn--apply"
@@ -1451,13 +1539,6 @@ var init_payment_form = __esm({
1451
1539
  >
1452
1540
  ${this._couponLoading ? '<span class="recur-coupon__spinner"></span>' : "\u5957\u7528"}
1453
1541
  </button>
1454
- <button
1455
- type="button"
1456
- class="recur-coupon__btn recur-coupon__btn--cancel"
1457
- ${this._couponLoading ? "disabled" : ""}
1458
- >
1459
- \u53D6\u6D88
1460
- </button>
1461
1542
  </div>
1462
1543
  ${errorHTML}
1463
1544
  </div>
@@ -1466,18 +1547,26 @@ var init_payment_form = __esm({
1466
1547
  getCouponAppliedHTML() {
1467
1548
  const coupon = this._appliedCoupon;
1468
1549
  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>`;
1550
+ const discountDescription = this.getDiscountDescription();
1551
+ const bonusDescription = this.getBonusDescription();
1552
+ const descriptionHTML = discountDescription ? `<p class="recur-coupon__description">${discountDescription}</p>` : "";
1553
+ const bonusHTML = bonusDescription ? `<div class="recur-coupon__bonus"><span>\u2728</span><span>${bonusDescription}</span></div>` : "";
1469
1554
  return `
1470
- <div class="recur-coupon__applied">
1471
- <div class="recur-coupon__applied-info">
1472
- <svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1473
- <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" />
1474
- </svg>
1475
- ${nameHTML}
1476
- <button type="button" class="recur-coupon__remove" ${this._couponLoading ? "disabled" : ""}>
1477
- ${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>'}
1478
- </button>
1555
+ <div class="recur-coupon__applied-wrapper">
1556
+ <div class="recur-coupon__applied">
1557
+ <div class="recur-coupon__applied-info">
1558
+ <svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1559
+ <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" />
1560
+ </svg>
1561
+ ${nameHTML}
1562
+ <button type="button" class="recur-coupon__remove" ${this._couponLoading ? "disabled" : ""}>
1563
+ ${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>'}
1564
+ </button>
1565
+ </div>
1566
+ <span class="recur-coupon__applied-amount">-NT$ ${coupon.discountAmount.toLocaleString()}</span>
1479
1567
  </div>
1480
- <span class="recur-coupon__applied-amount">-NT$ ${coupon.discountAmount.toLocaleString()}</span>
1568
+ ${descriptionHTML}
1569
+ ${bonusHTML}
1481
1570
  </div>
1482
1571
  `;
1483
1572
  }
@@ -1488,11 +1577,11 @@ var init_payment_form = __esm({
1488
1577
  bindCouponInputEvents(container) {
1489
1578
  const input = container.querySelector(".recur-coupon__input");
1490
1579
  const applyBtn = container.querySelector(".recur-coupon__btn--apply");
1491
- const cancelBtn = container.querySelector(".recur-coupon__btn--cancel");
1580
+ const clearBtn = container.querySelector(".recur-coupon__clear");
1492
1581
  input?.addEventListener("input", (e) => this.handleCouponInputChange(e));
1493
1582
  input?.addEventListener("keydown", (e) => this.handleCouponKeydown(e));
1494
1583
  applyBtn?.addEventListener("click", () => this.applyCoupon());
1495
- cancelBtn?.addEventListener("click", () => this.cancelCouponInput());
1584
+ clearBtn?.addEventListener("click", () => this.clearCouponInput());
1496
1585
  }
1497
1586
  bindCouponAppliedEvents(container) {
1498
1587
  const removeBtn = container.querySelector(".recur-coupon__remove");
@@ -1552,7 +1641,10 @@ var init_payment_form = __esm({
1552
1641
  duration: data.discount.duration,
1553
1642
  durationMonths: data.discount.durationMonths,
1554
1643
  bonusTrialDays: data.discount.bonusTrialDays,
1555
- bonusMonths: data.discount.bonusMonths
1644
+ bonusMonths: data.discount.bonusMonths,
1645
+ productInterval: data.discount.productInterval,
1646
+ productIntervalCount: data.discount.productIntervalCount,
1647
+ productPrice: data.discount.productPrice
1556
1648
  };
1557
1649
  this._showCouponInput = false;
1558
1650
  this._couponCode = "";
@@ -2560,7 +2652,7 @@ function toCamelCase(obj) {
2560
2652
 
2561
2653
  // package.json
2562
2654
  var package_default = {
2563
- version: "0.9.11"};
2655
+ version: "0.9.13"};
2564
2656
  var SDK_VERSION = package_default.version;
2565
2657
  var SDK_TYPE = "react";
2566
2658
  var RecurContext = React.createContext(null);
@@ -2896,7 +2988,6 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2896
2988
  paymentForm.setAttribute("interval", checkoutResult.product.interval);
2897
2989
  }
2898
2990
  const customStyles = `
2899
- /* PAYUNi SDK focus \u6A23\u5F0F - shadcn \u98A8\u683C */
2900
2991
  .form-input-focus {
2901
2992
  border-color: var(--ring, hsl(215 16% 47%)) !important;
2902
2993
  outline: 0 !important;
package/dist/index.d.cts CHANGED
@@ -511,9 +511,13 @@ declare class RecurPaymentForm extends HTMLElement {
511
511
  private getCustomStyles;
512
512
  private updateCustomStyles;
513
513
  private renderOrderSummary;
514
+ private getIntervalText;
515
+ private getDiscountDescription;
516
+ private getBonusDescription;
514
517
  private renderCoupon;
515
518
  private showCouponInput;
516
519
  private cancelCouponInput;
520
+ private clearCouponInput;
517
521
  private handleCouponInputChange;
518
522
  private handleCouponKeydown;
519
523
  private updateApplyButtonState;
@@ -539,6 +543,9 @@ declare class RecurPaymentForm extends HTMLElement {
539
543
  durationMonths?: number;
540
544
  bonusTrialDays?: number;
541
545
  bonusMonths?: number;
546
+ productInterval?: string;
547
+ productIntervalCount?: number;
548
+ productPrice?: number;
542
549
  } | null;
543
550
  private renderCustomerInfo;
544
551
  private renderCardFields;
package/dist/index.d.ts CHANGED
@@ -511,9 +511,13 @@ declare class RecurPaymentForm extends HTMLElement {
511
511
  private getCustomStyles;
512
512
  private updateCustomStyles;
513
513
  private renderOrderSummary;
514
+ private getIntervalText;
515
+ private getDiscountDescription;
516
+ private getBonusDescription;
514
517
  private renderCoupon;
515
518
  private showCouponInput;
516
519
  private cancelCouponInput;
520
+ private clearCouponInput;
517
521
  private handleCouponInputChange;
518
522
  private handleCouponKeydown;
519
523
  private updateApplyButtonState;
@@ -539,6 +543,9 @@ declare class RecurPaymentForm extends HTMLElement {
539
543
  durationMonths?: number;
540
544
  bonusTrialDays?: number;
541
545
  bonusMonths?: number;
546
+ productInterval?: string;
547
+ productIntervalCount?: number;
548
+ productPrice?: number;
542
549
  } | null;
543
550
  private renderCustomerInfo;
544
551
  private renderCardFields;