From aca317779062d19244f802642ee8e829e027a1e5 Mon Sep 17 00:00:00 2001 From: Hirosashii Date: Fri, 21 Nov 2025 00:36:33 -0500 Subject: [PATCH] Create useExposeIframeText.ts --- src/hooks/useExposeIframeText.ts | 56 ++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/hooks/useExposeIframeText.ts diff --git a/src/hooks/useExposeIframeText.ts b/src/hooks/useExposeIframeText.ts new file mode 100644 index 0000000..cc8323e --- /dev/null +++ b/src/hooks/useExposeIframeText.ts @@ -0,0 +1,56 @@ +import { useEffect } from "react"; + +export function useExposeIframeText(iframeSelector = "iframe[id^='epubjs-view']") { + useEffect(() => { + const iframe = document.querySelector(iframeSelector); + if (!iframe) return; + + const mirrorId = "migaku-readable-layer"; + + // Create mirror layer if it doesn't exist + let mirror = document.getElementById(mirrorId); + if (!mirror) { + mirror = document.createElement("div"); + mirror.id = mirrorId; + + Object.assign(mirror.style, { + position: "absolute", + inset: "0", + padding: "50px", + pointerEvents: "none", // important – do NOT block viewer interactions + color: "transparent", + userSelect: "text", + whiteSpace: "pre-wrap", + zIndex: 1, // below UI overlays, above background + fontSize: "16px", + }); + + document.body.appendChild(mirror); + } + + function syncText() { + try { + const doc = iframe.contentDocument; + if (!doc) return; + + // Extract all text from inside the iframe body + let text = ""; + doc.querySelectorAll("p, h1, h2, h3, h4, span").forEach((el) => { + text += el.innerText + "\n"; + }); + + mirror!.textContent = text; + } catch (e) { + console.warn("Unable to access iframe text:", e); + } + } + + // Sync initially + syncText(); + + // Sync whenever iframe loads a new chapter + iframe.addEventListener("load", syncText); + + return () => iframe.removeEventListener("load", syncText); + }, [iframeSelector]); +}