import { useCallback, useEffect, useRef, useState } from 'react'; import type { EditorView } from '@codemirror/view'; interface Opts { getView: () => EditorView | null; } /** Live markdown preview pane: visibility, mobile tab, debounced render. */ export function useLivePreview({ getView }: Opts) { const [showPreview, setShowPreview] = useState(false); const [mobileView, setMobileView] = useState<'edit' | 'preview'>('edit'); const previewRef = useRef(null); const renderMarkdownRef = useRef<((src: string) => string) | null>(null); const previewTimerRef = useRef | null>(null); const updatePreviewRef = useRef<() => void>(() => {}); const updatePreview = useCallback(async () => { const view = getView(); if (!showPreview || !view || !previewRef.current) return; if (!renderMarkdownRef.current) { const mod = await import('../../../../lib/markdown'); renderMarkdownRef.current = mod.renderMarkdown; } const content = view.state.doc.toString(); previewRef.current.innerHTML = renderMarkdownRef.current(content); }, [showPreview, getView]); useEffect(() => { updatePreviewRef.current = updatePreview; }, [updatePreview]); useEffect(() => { if (showPreview) updatePreview(); }, [showPreview, updatePreview]); // Debounced refresh — called from the CodeMirror update listener. const schedulePreview = useCallback(() => { if (previewTimerRef.current) clearTimeout(previewTimerRef.current); previewTimerRef.current = setTimeout(() => updatePreviewRef.current(), 300); }, []); return { showPreview, setShowPreview, mobileView, setMobileView, previewRef, updatePreview, schedulePreview, }; }