## Added
- French (fr) locale with 60+ translations
- Outline panel scroll tracking with active heading highlight
- exec('formatTable') for auto-aligning Markdown table columns
- Code block title rendering via ```js title=hello.js```
- Escaped pipe \| support in table cells
- Custom block token fallback rendering as <div>
- Gutter incremental DOM update (no more full innerHTML)
- 694 tests (+10)
## Changed
- All 6 preset plugins refactored to closure-based state (no this pollution)
- shortcutHelp plugin now i18n-aware (shortcut labels follow locale)
- Context menu labels (Cut/Copy/Paste/Select All) i18n-translated
- Warm theme now has progressBg + closeHoverBg fields
## Added
- Reference link/image resolution: [text][ref] + ![alt][ref] with [ref]: url definitions
- Right-click context menu: undo/redo/cut/copy/paste/selectAll + custom items
- RTL CSS layout support for Arabic, Hebrew, Persian etc.
- Japanese (ja) and Korean (ko) locales with 60+ keys each
- Divider position localStorage persistence
- Regex search toggle in search/replace panel
- Export HTML with embedded CSS styles
- beforeChange / afterChange lifecycle hooks (instance + global)
- copyAsMarkdown() / copyAsHTML() clipboard APIs
- CHANGELOG.md, CONTRIBUTING.md, CI workflow (.github/workflows/ci.yml)
- 2 new test suites: index.test.ts, styles.test.ts (684 total tests, +74)
## Changed
- autoSave plugin: closure-based state per instance instead of this context
- Plugin install() now receives options as second argument
- RTL locale detection: now uses language prefix (ar-SA → RTL)
- Rollup dev mode: only builds UMD format
- prepublishOnly now includes typecheck + test
- Version bumped to 0.2.1
## Fixed
- [text][ref] now correctly renders as link (was raw text)
- ![alt][ref] no longer produces empty src
- autoSave plugin state isolation across multiple editor instances
- Footnote definitions no longer consumed by refDef handler
- _positionHighlightLayer(): set left offset dynamically from gutter width
- Use hidden attribute instead of clearing innerHTML for toggle
- Skip highlight in preview mode
- Initialize highlightLayer hidden state on construction
- Remove hardcoded left:36px CSS
Add color: var(--md-text) to .me-highlight-layer base style
Add color: var(--md-text) to .mh-bold span
Without this, non-matched plain text in the highlight overlay
was invisible when textarea text is transparent
opt(core): _highlightEditor rAF throttle to avoid per-keystroke reflow
opt(core): fix regex order — image before link, code before bold, italic last
opt(core): skip highlighting for documents >50KB to prevent lag
opt(core): add toggleSyntaxHighlight() API method
fix(core): clear _hlRaf in destroy to prevent post-mortem callbacks
fix(core): initialize _hlRaf = null in constructor
fix(plugins): rewrite fileSystem to use File System Access API
- openFile(): showOpenFilePicker for real .md disk files
- saveFile(): showSaveFilePicker or write to existing handle
- saveFileAs(): force save-as dialog
- Graceful fallback when API unsupported
fix(core): syntax highlight layer transparency
- textarea gets me-textarea-highlight class when syntaxHighlight enabled
- CSS: color transparent, caret-color visible, selection bg visible
- Highlight layer positioned after gutter (left:36px)
verify(parser): Mermaid self-implemented container
- Creates <div class="me-mermaid"> with <pre class="mermaid">
- Zero third-party dependencies required
- Users optionally load Mermaid.js to initialize rendering
Replace heading-based _syncScrollByHeading with solid proportional sync:
- _syncScroll(): uses scrollTop/scrollHeight ratio for both gutter and preview
- Prevents sync loops with _syncing flag and rAF debounce
- Bidirectional: preview scroll also syncs back to source textarea
- Ratio-based approach handles height mismatches (e.g. word-wrap in textarea)
- Remove fragile heading detection and scrollIntoView calls
Also fix setValue and _applyHistory to reset scroll positions consistently
Root cause: _syncScrollByHeading used cursor position (selectionStart)
to find nearest heading, but cursor doesn't move during scroll. Preview
was stuck at the same heading regardless of scroll position.
Fix: base heading detection on estimated viewport top line from scrollTop
+ lineHeight. Always run proportional sync first for smooth scrolling,
then fine-tune to nearest heading at viewport top.
feat(a11y): toolbar keyboard navigation (Arrow keys, Home, End)
feat(a11y): aria-live region for screen reader announcements on mode change
feat(a11y): enhance focus-visible style (outline-offset: 2px, hide on mouse focus)
feat(core): Zen mode (editor.toggleZen() / exec('zen'))
- Toggle with Ctrl+Shift+Z shortcut concept
- Auto-hide toolbar and statusbar, mouse to top edge reveals toolbar
- Centered editor pane with max-width constraint
feat(core): heading-aware scroll sync v2
- Sync preview scroll to nearest heading before cursor position
- Falls back to proportional sync when no headings found
feat(core): Word wrap toggle (editor.toggleWordWrap() / setWordWrap(bool))
feat(plugins): shortcutHelp preset plugin
- Press '?' to open keyboard shortcuts overlay panel
- Lists built-in + user-registered shortcuts
- Click overlay or press Escape to close
style: Zen mode CSS, sr-only class, focus-visible refinement
test: 3 new tests for Zen mode, WordWrap, shortcutHelp (535 total)
chore: bump version 0.1.11 → 0.1.12 across all files
fix(core): clear _outlineTimer in destroy() to prevent post-destroy callbacks
fix(core): remove '<' from BRACKET_PAIRS to avoid HTML tag conflicts
fix(core): setValue now updates outline panel and resets gutter scroll
fix(core): getValue returns '' on destroyed instances (safe API access)
opt(core): _renderGutter skips rebuild when line count unchanged
chore: bump version 0.1.10 → 0.1.11 across all files
- Match gutter font-size to textarea (13.5px) so line heights align
- Always sync gutter scrollTop regardless of mode
- Sync gutter scroll position after undo/redo history apply