erl-mathtextx-editor
v0.1.9
Published
Visual math editor component for solutest.id — CKEditor replacement with zero-LaTeX approach
Maintainers
Readme
erl-mathtextx-editor
Visual Math Editor Component — Zero LaTeX Required
Embeddable visual math editor widget untuk CMS dan platform edukasi. User tidak perlu tahu LaTeX — semua input matematika dilakukan secara visual.
✨ Fitur Utama
- 🎯 Visual Math Keyboard — Klik simbol, operator, template formula
- 📝 Rich Text Editor — Bold, italic, tables, lists, links, images
- 🧮 100+ Formula Templates — Algebra, calculus, trigonometry, chemistry
- 👁️ Content Viewer — Read-only renderer dengan KaTeX
- 🎨 Table Editor — 6 professional table templates, column resize, cell selection
- 🖥️ Code Blocks — Syntax highlighting untuk berbagai bahasa pemrograman
- 📋 Collapsible Sections — Details/summary untuk konten tersembunyi
- ⌨️ Keyboard Shortcuts — Ctrl+K (link), Ctrl+Shift+T (table), Ctrl+S (save)
- 📊 Graph Plotting — Function plotting via Function Plot
- 🔒 XSS Protection — DOMPurify sanitization
- 💻 Code Blocks — Syntax highlighting with 100+ languages
- 📋 Collapsible Sections — Details/summary for hidden content
📦 Installation
npm install erl-mathtextx-editor🚀 Quick Start
Basic Usage
import { MathTextXEditor } from 'erl-mathtextx-editor'
import 'erl-mathtextx-editor/styles'
function App() {
return (
<MathTextXEditor
onChange={(html) => console.log(html)}
placeholder="Tulis soal di sini..."
/>
)
}With Save Handler
import { MathTextXEditor } from 'erl-mathtextx-editor'
import 'erl-mathtextx-editor/styles'
function QuestionForm() {
const handleSave = (html) => {
fetch('/api/questions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: html }),
})
}
return (
<MathTextXEditor
onChange={(html) => console.log(html)}
onSave={handleSave}
placeholder="Tulis pertanyaan..."
/>
)
}Content Viewer (Read-Only)
import { ContentViewer } from 'erl-mathtextx-editor/viewer'
import 'erl-mathtextx-editor/viewer/styles'
function QuestionCard({ questionHtml }) {
return (
<div className="question-card">
<h3>Soal 1</h3>
<ContentViewer content={questionHtml} />
</div>
)
}📋 Props API
MathTextXEditor
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| content | string | '' | Initial HTML content |
| onChange | (html: string) => void | — | Callback on content change |
| onSave | (html: string) => void | — | Callback on Ctrl+S |
| onImageUpload | (file: File) => Promise<string> | — | Custom image upload handler |
| placeholder | string | 'Tulis soal...' | Placeholder text |
| minHeight | string | '200px' | Minimum editor height |
| maxHeight | string | — | Maximum editor height |
| autoFocus | boolean | false | Auto-focus editor on mount |
| toolbarMode | 'basic' \| 'advanced' | 'basic' | Toolbar preset |
| educationLevel | 'sd' \| 'smp' \| 'sma' \| 'all' | 'all' | Filter math templates by level |
ContentViewer
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| content | string | — | HTML content to render (required) |
| className | string | — | Additional CSS class |
📦 Exports
Main Package (erl-mathtextx-editor)
import {
MathTextXEditor,
ContentViewer,
getHTML,
toCompatibleHTML,
sanitizeCKEditorHTML,
MathTypeDialog,
TemplatePanel,
mathTemplates,
getTemplatesByLevel,
getTemplatesByCategory,
getTemplateCategories,
} from 'erl-mathtextx-editor'
import 'erl-mathtextx-editor/styles'Viewer Only (erl-mathtextx-editor/viewer)
import { ContentViewer } from 'erl-mathtextx-editor/viewer'
import 'erl-mathtextx-editor/viewer/styles'⌨️ Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| Ctrl+B | Bold |
| Ctrl+I | Italic |
| Ctrl+U | Underline |
| Ctrl+K | Insert/edit link |
| Ctrl+Shift+T | Insert table |
| Ctrl+S | Save document |
| Tab | Indent paragraph (at start) / Insert 4 spaces (in middle) |
| Shift+Tab | Outdent paragraph |
| Backspace | Outdent (if indented) / Join with previous paragraph |
🎯 Example: Multiple Choice Question Form
import { useState } from 'react'
import { MathTextXEditor } from 'erl-mathtextx-editor'
import 'erl-mathtextx-editor/styles'
export default function QuestionForm() {
const [question, setQuestion] = useState('')
const [options, setOptions] = useState([
{ id: 'A', content: '', isCorrect: false },
{ id: 'B', content: '', isCorrect: false },
{ id: 'C', content: '', isCorrect: false },
{ id: 'D', content: '', isCorrect: false },
])
const handleSubmit = async () => {
await fetch('/api/questions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question, options }),
})
}
return (
<div>
<h2>Buat Soal Pilihan Ganda</h2>
<MathTextXEditor
content={question}
onChange={setQuestion}
placeholder="Tulis pertanyaan..."
minHeight="150px"
/>
{options.map((option) => (
<div key={option.id}>
<label>
<input
type="radio"
name="correct"
checked={option.isCorrect}
onChange={() => {
setOptions(prev =>
prev.map(o => ({
...o,
isCorrect: o.id === option.id
}))
)
}}
/>
Opsi {option.id}
</label>
<MathTextXEditor
content={option.content}
onChange={(html) => {
setOptions(prev =>
prev.map(o =>
o.id === option.id ? { ...o, content: html } : o
)
)
}}
placeholder={`Jawaban ${option.id}...`}
minHeight="80px"
/>
</div>
))}
<button onClick={handleSubmit}>Simpan Soal</button>
</div>
)
}🛠️ Tech Stack
- UI Framework: React 18+
- Editor Engine: TipTap / ProseMirror
- Math Input: MathLive (WYSIWYG math)
- Math Rendering: KaTeX
- XSS Protection: DOMPurify
- Graph Plotting: Function Plot
📄 License
MIT © Erlangga Team
🔗 Links
- NPM: erl-mathtextx-editor
- Source: GitHub Repository
- Issues: Report Bug
