feat: enhance StripePaymentDialog with document handling and portal rendering

This commit is contained in:
2026-06-29 18:27:53 +08:00
parent 9ad17379e8
commit 3b88869a57
@@ -4,7 +4,8 @@
*
* 后端当前返回 PaymentIntent clientSecret,因此这里直接用它完成前端确认。
*/
import { useState, type FormEvent } from "react";
import { useEffect, useState, type FormEvent } from "react";
import { createPortal } from "react-dom";
import {
Elements,
PaymentElement,
@@ -35,8 +36,24 @@ export function StripePaymentDialog({
onClose,
onConfirmed,
}: StripePaymentDialogProps) {
if (!stripePromise) {
return (
useEffect(() => {
if (typeof document === "undefined") return;
const prevOverflow = document.body.style.overflow;
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Escape") onClose();
};
document.body.style.overflow = "hidden";
document.addEventListener("keydown", handleKeyDown);
return () => {
document.body.style.overflow = prevOverflow;
document.removeEventListener("keydown", handleKeyDown);
};
}, [onClose]);
const dialog = !stripePromise ? (
<div className={styles.overlay} role="alertdialog" aria-modal="true">
<div className={styles.dialog}>
<div className={styles.header}>
@@ -56,10 +73,7 @@ export function StripePaymentDialog({
</div>
</div>
</div>
);
}
return (
) : (
<div
className={styles.overlay}
role="dialog"
@@ -95,6 +109,10 @@ export function StripePaymentDialog({
</div>
</div>
);
if (typeof document === "undefined") return null;
return createPortal(dialog, document.body);
}
function StripePaymentForm({