ultisuite-client/components/gmail/email-view/sandboxed-content.tsx
2026-05-20 18:22:36 +02:00

100 lines
2.5 KiB
TypeScript

"use client"
import { useCallback, useEffect, useRef, useState, type CSSProperties } from "react"
import { useTheme } from "next-themes"
import {
emailPreviewBaseCss,
emailPreviewDarkOverrideCss,
emailPreviewLightOverrideCss,
preprocessEmailHtmlForTheme,
} from "@/lib/email-preview-dark-styles"
const EMAIL_PREVIEW_IFRAME_STYLE: CSSProperties = {
display: "block",
background: "transparent",
}
function documentIsDark(): boolean {
return document.documentElement.classList.contains("dark")
}
export function SandboxedContent({
html,
isSpam,
}: {
html: string
isSpam: boolean
}) {
const iframeRef = useRef<HTMLIFrameElement>(null)
const [height, setHeight] = useState(120)
const sandboxValue = isSpam
? "allow-same-origin"
: "allow-same-origin allow-popups"
const { resolvedTheme } = useTheme()
const injectContent = useCallback(() => {
const iframe = iframeRef.current
if (!iframe) return
const doc = iframe.contentDocument
if (!doc) return
const cspMeta = isSpam
? `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:;">`
: `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src https: data:;">`
const isDark = documentIsDark()
const processedHtml = preprocessEmailHtmlForTheme(html, isDark)
const themeOverrides = isDark
? emailPreviewDarkOverrideCss()
: emailPreviewLightOverrideCss()
doc.open()
doc.write(`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
${cspMeta}
<style>
${emailPreviewBaseCss(isDark)}
${themeOverrides}
</style>
</head>
<body>${processedHtml}</body>
</html>`)
doc.close()
const resizeObserver = new ResizeObserver(() => {
const body = iframe.contentDocument?.body
if (body) {
setHeight(Math.max(60, body.scrollHeight + 2))
}
})
if (doc.body) {
resizeObserver.observe(doc.body)
setHeight(Math.max(60, doc.body.scrollHeight + 2))
}
return () => resizeObserver.disconnect()
}, [html, isSpam, resolvedTheme])
useEffect(() => {
const cleanup = injectContent()
return () => cleanup?.()
}, [injectContent])
return (
<iframe
ref={iframeRef}
sandbox={sandboxValue}
title="Contenu du message"
className="w-full border-0 bg-transparent"
style={{ ...EMAIL_PREVIEW_IFRAME_STYLE, height: `${height}px` }}
tabIndex={-1}
/>
)
}