import { useState, useRef } from 'react'; import styles from './MarkdownToolbar.module.css'; const TOOLS = [ { label: 'B', title: '加粗', wrap: (s) => `${s}` }, { label: 'I', title: '斜体', wrap: (s) => `${s}` }, { label: 'H2', title: '二级标题', wrap: (s) => `

${s}

` }, { label: '❝', title: '引用', wrap: (s) => `
${s}
` }, { label: '', title: '代码', wrap: (s) => `${s}` }, ]; export default function MarkdownToolbar({ textareaRef }) { const [imgPopover, setImgPopover] = useState(false); const [imgUrl, setImgUrl] = useState(''); const [imgAlt, setImgAlt] = useState(''); const [uploading, setUploading] = useState(false); const fileInputRef = useRef(null); const insertAt = (html) => { const ta = textareaRef.current; if (!ta) return; const pos = ta.selectionEnd; const before = ta.value.slice(0, pos); const after = ta.value.slice(pos); const next = before + '\n' + html + '\n' + after; const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set; setter.call(ta, next); ta.dispatchEvent(new Event('input', { bubbles: true })); ta.focus(); }; const apply = (wrapFn) => { const ta = textareaRef.current; if (!ta) return; const start = ta.selectionStart; const end = ta.selectionEnd; const selected = ta.value.slice(start, end) || '内容'; const wrapped = wrapFn(selected); const before = ta.value.slice(0, start); const after = ta.value.slice(end); const next = before + wrapped + after; const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set; setter.call(ta, next); ta.dispatchEvent(new Event('input', { bubbles: true })); ta.focus(); ta.setSelectionRange(start + wrapped.length, start + wrapped.length); }; const insertImgUrl = () => { if (!imgUrl.trim()) return; const alt = imgAlt.trim() || '图片'; insertAt(`${alt}`); setImgUrl(''); setImgAlt(''); setImgPopover(false); }; const handleFileChange = (e) => { const file = e.target.files[0]; if (!file) return; if (file.size > 2 * 1024 * 1024) { alert('图片文件不能超过 2MB(base64 会使文章体积变大)'); return; } setUploading(true); const reader = new FileReader(); reader.onload = (ev) => { const src = ev.target.result; const alt = file.name.replace(/\.[^.]+$/, '') || '图片'; insertAt(`${alt}`); setUploading(false); setImgPopover(false); e.target.value = ''; }; reader.readAsDataURL(file); }; return (
{TOOLS.map(t => ( ))}
{imgPopover && (

插入图片

setImgUrl(e.target.value)} onKeyDown={e => e.key === 'Enter' && insertImgUrl()} placeholder="https://example.com/image.jpg" autoFocus />
setImgAlt(e.target.value)} placeholder="图片描述(alt,可选)" style={{ marginTop: 6 }} />
)}
); }