import { useState, useRef, useEffect, useCallback } from "react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; import { Button } from "@/components/ui/button"; import { useBoardStore } from "@/stores/board-store"; const OS_OPTIONS = { scrollbars: { theme: "os-theme-pylon" as const, autoHide: "scroll" as const, autoHideDelay: 600, clickScroll: true }, }; interface MarkdownEditorProps { cardId: string; value: string; } export function MarkdownEditor({ cardId, value }: MarkdownEditorProps) { const [mode, setMode] = useState<"edit" | "preview">("preview"); const [draft, setDraft] = useState(value); const textareaRef = useRef(null); const updateCard = useBoardStore((s) => s.updateCard); const debounceRef = useRef | null>(null); // Sync draft when value changes externally (e.g. undo) useEffect(() => { setDraft(value); }, [value]); // Auto-focus and auto-size textarea when switching to edit mode useEffect(() => { if (mode === "edit" && textareaRef.current) { const el = textareaRef.current; el.style.height = "auto"; el.style.height = el.scrollHeight + "px"; el.focus(); } }, [mode]); const save = useCallback( (text: string) => { if (text !== value) { updateCard(cardId, { description: text }); } }, [cardId, value, updateCard] ); function handleChange(e: React.ChangeEvent) { const text = e.target.value; setDraft(text); // Auto-size textarea to fit content (parent OverlayScrollbars handles overflow) e.target.style.height = "auto"; e.target.style.height = e.target.scrollHeight + "px"; // Debounced auto-save if (debounceRef.current) clearTimeout(debounceRef.current); debounceRef.current = setTimeout(() => { save(text); }, 300); } function handleBlur() { if (debounceRef.current) { clearTimeout(debounceRef.current); debounceRef.current = null; } save(draft); } return (
{/* Mode toggle */}
{/* Editor / Preview */} {mode === "edit" ? (